using System.Collections; using System.Collections.Generic; using GameKitController.Audio; using UnityEngine; using UnityEngine.Events; public class puzzleSystem : MonoBehaviour { [Header ("Main Settings")] [Space] public bool respawnDragableElements; public bool respawnDragableElementsInOriginalPosition; public Transform respawnPosition; public float dragVelocity = 8; public LayerMask layer; public float maxRaycastDistance; [Space] public bool checkIfObjectsToFarFromPuzzleZone; public float maxDistanceFromPuzzleZone; [Space] public float changeHoldDistanceSpeed = 2; public bool useColliderMaterialWhileGrabbed; public PhysicsMaterial grabbedColliderMaterial; [Space] [Header ("Dragable Elements Settings")] [Space] public List dragableElements = new List (); [Space] [Header ("Object ROtation Settings")] [Space] public bool freezeRotationWhenGrabbed; public bool objectCanBeRotated; public float rotateSpeed; public bool horizontalRotationEnabled = true; public bool verticalRotationEnabled = true; public bool rotateToCameraInFixedPosition; public float rotationSpeed; [Space] [Header ("Puzzle Settings")] [Space] public bool resetObjectsWhenStopUse; public bool canResetObjectsWhileUsing; public int numberObjectsToPlace; public bool disableObjectActionAfterResolve; public bool disableObjectTriggerAfterResolve; public float waitDelayToStopUsePuzzleAfterResolve; [Space] [Header ("Camera Rotation Settings")] [Space] public bool rotateAroundPointEnabled; public float rotateAroundPointSpeed; public Transform rotationPointPivot; public Transform rotationPointCamera; public Transform cameraPosition; public bool useVerticalRotationLimit; public bool useHorizontalRotationLimit; public Vector2 verticalRotationLimit = new Vector2 (-90, 90); public Vector2 horizontalRotationLimit = new Vector2 (-90, 90); [Space] [Header ("Action Screen Settings")] [Space] public bool activateActionScreen = true; public string actionScreenName = "Use Puzzle System"; public bool useMeshTextForClues; public GameObject meshTextGameObject; [Space] [Header ("Sound Settings")] [Space] public bool usePuzzleSolvedSound; public AudioClip puzzleSolvedSound; public AudioElement puzzleSolvedAudioElement; [Space] [Header ("Debug")] [Space] public bool showDebugPrint; public bool puzzleSolved; public bool usingPuzzle; public int currentNumberObjectsPlaced; public bool touching; public bool movingObject; public GameObject currentGrabbedObject; [Space] [Header ("Events Settings")] [Space] public bool useEventOnResetPuzzle; public UnityEvent resetPuzzleEvent; public UnityEvent puzzleSolvedEvent; public bool useEventAfterResolveDelay; public UnityEvent eventAfterResolveDelay; [Space] [Header ("Components")] [Space] public electronicDevice electronicDeviceManager; public deviceStringAction deviceStringActionManager; public AudioSource mainAudioSource; public Collider mainCollider; [Space] [Header ("Gizmo Settings")] [Space] public bool showGizmo; public Color gizmoColor; public float gizmoRadius = 0.1f; public float gizmoArrowLength = 1; public float gizmoArrowLineLength = 2.5f; public float gizmoArrowAngle = 20; public Color gizmoArrowColor = Color.white; Vector3 respawnPositionValue; GameObject currentDragableElement; playerInputManager playerInput; GameObject currentPlayer; bool touchPlatform; Touch currentTouch; Rigidbody currentGrabbedObjectRigidbody; Camera mainCamera; Transform mainCameraTransform; RaycastHit hit; float currentDistanceGrabbedObject; Vector3 touchPosition; Vector3 nextPosition; Vector3 currentPosition; bool rotatingObject; bool increaseHoldObjectDistance; bool decreaseHoldObjectDistance; Quaternion originalRotationPointPivotRotation; Quaternion oriinalRotationPointCameraRotation; Collider grabbedObjectCollider; PhysicsMaterial originalGrabbedColliderMaterial; Vector2 lookAngle; float lastTimeMouseWheelUsed; bool mouseWheelUsedPreviously; List grabableObjectsInfoList = new List (); Coroutine resetObjectRotationCoroutine; puzzleSystemPlayerManagement puzzleSystemPlayerManager; Vector2 axisValues; private void InitializeAudioElements () { if (mainAudioSource == null) { mainAudioSource = GetComponent (); } if (mainAudioSource != null) { puzzleSolvedAudioElement.audioSource = mainAudioSource; } if (puzzleSolvedSound != null) { puzzleSolvedAudioElement.clip = puzzleSolvedSound; } } void Start () { if (electronicDeviceManager == null) { electronicDeviceManager = GetComponent (); } touchPlatform = touchJoystick.checkTouchPlatform (); if (resetObjectsWhenStopUse) { for (int i = 0; i < dragableElements.Count; i++) { grabableObjectsInfo newGrabableObjectsInfo = new grabableObjectsInfo (); newGrabableObjectsInfo.grabableGameObject = dragableElements [i]; newGrabableObjectsInfo.grabableTransform = dragableElements [i].transform; newGrabableObjectsInfo.originalPosition = dragableElements [i].transform.position; newGrabableObjectsInfo.originalRotation = dragableElements [i].transform.rotation; grabableObjectsInfoList.Add (newGrabableObjectsInfo); } } originalRotationPointPivotRotation = rotationPointPivot.localRotation; oriinalRotationPointCameraRotation = rotationPointCamera.localRotation; if (deviceStringActionManager == null) { deviceStringActionManager = GetComponent (); } InitializeAudioElements (); if (respawnPosition != null) { respawnPositionValue = respawnPosition.position; } } void Update () { if (usingPuzzle) { int touchCount = Input.touchCount; if (!touchPlatform) { touchCount++; } for (int i = 0; i < touchCount; i++) { if (!touchPlatform) { currentTouch = touchJoystick.convertMouseIntoFinger (); } else { currentTouch = Input.GetTouch (i); } if (currentTouch.phase == TouchPhase.Began && !touching) { Ray ray = mainCamera.ScreenPointToRay (currentTouch.position); if (Physics.Raycast (ray, out hit, maxRaycastDistance, layer)) { GameObject objectToCheck = canBeDragged (hit.collider.gameObject); if (objectToCheck != null) { touching = true; currentGrabbedObject = objectToCheck; currentGrabbedObjectRigidbody = currentGrabbedObject.GetComponent (); currentGrabbedObjectRigidbody.linearVelocity = Vector3.zero; currentDistanceGrabbedObject = mainCameraTransform.InverseTransformDirection (currentGrabbedObject.transform.position - mainCameraTransform.position).z; grabbedObjectCollider = currentGrabbedObject.GetComponent (); if (freezeRotationWhenGrabbed) { currentGrabbedObjectRigidbody.freezeRotation = true; } if (useColliderMaterialWhileGrabbed && grabbedObjectCollider != null) { originalGrabbedColliderMaterial = grabbedObjectCollider.material; grabbedObjectCollider.material = grabbedColliderMaterial; } if (showDebugPrint) { print ("object detected " + objectToCheck.name); } } else { if (showDebugPrint) { print ("object not detected "); } } } } if ((currentTouch.phase == TouchPhase.Stationary || currentTouch.phase == TouchPhase.Moved) && currentGrabbedObject != null) { movingObject = true; touchPosition = mainCamera.ScreenToWorldPoint (new Vector3 (currentTouch.position.x, currentTouch.position.y, currentDistanceGrabbedObject)); nextPosition = touchPosition; currentPosition = currentGrabbedObject.transform.position; currentGrabbedObjectRigidbody.linearVelocity = (nextPosition - currentPosition) * dragVelocity; if (rotatingObject) { if (horizontalRotationEnabled) { currentGrabbedObject.transform.Rotate (0, -rotateSpeed * playerInput.getPlayerMovementAxis ().x, 0); } if (verticalRotationEnabled) { currentGrabbedObject.transform.Rotate (rotateSpeed * playerInput.getPlayerMovementAxis ().y, 0, 0); } if (showDebugPrint) { print ("rotating object"); } } else { if (rotateToCameraInFixedPosition) { Quaternion direction = Quaternion.LookRotation (mainCameraTransform.forward); currentGrabbedObject.transform.rotation = Quaternion.Slerp (currentGrabbedObject.transform.rotation, direction, Time.deltaTime * rotationSpeed); } } if (mouseWheelUsedPreviously && Time.time > lastTimeMouseWheelUsed + 0.1f) { increaseHoldObjectDistance = false; decreaseHoldObjectDistance = false; mouseWheelUsedPreviously = false; } if (increaseHoldObjectDistance) { currentDistanceGrabbedObject += Time.deltaTime * changeHoldDistanceSpeed; } if (decreaseHoldObjectDistance) { currentDistanceGrabbedObject -= Time.deltaTime * changeHoldDistanceSpeed; } if (showDebugPrint) { print ("moving object"); } } if (currentTouch.phase == TouchPhase.Ended && touching) { dropObject (); } } if (rotateAroundPointEnabled && !rotatingObject) { axisValues = playerInput.getPlayerMovementAxis (); lookAngle.x -= axisValues.x * rotateAroundPointSpeed; lookAngle.y += axisValues.y * rotateAroundPointSpeed; if (useVerticalRotationLimit) { lookAngle.y = Mathf.Clamp (lookAngle.y, verticalRotationLimit.x, verticalRotationLimit.y); } else { if (lookAngle.y > 360 || lookAngle.y < -360) { lookAngle.y = 0; } } if (useHorizontalRotationLimit) { lookAngle.x = Mathf.Clamp (lookAngle.x, horizontalRotationLimit.x, horizontalRotationLimit.y); } else { if (lookAngle.x > 360 || lookAngle.x < -360) { lookAngle.x = 0; } } rotationPointPivot.localRotation = Quaternion.Euler (0, lookAngle.x, 0); rotationPointCamera.localRotation = Quaternion.Euler (lookAngle.y, 0, 0); } if (checkIfObjectsToFarFromPuzzleZone) { int grabableObjectsInfoListCount = grabableObjectsInfoList.Count; for (int i = 0; i < grabableObjectsInfoListCount; i++) { float currentDistance = GKC_Utils.distance (grabableObjectsInfoList [i].grabableTransform.position, respawnPositionValue); if (currentDistance > maxDistanceFromPuzzleZone) { if (respawnDragableElements) { if (showDebugPrint) { print ("object too far from zone " + grabableObjectsInfoList [i].grabableGameObject.name); } setObjectBackToPuzzleZone (grabableObjectsInfoList [i].grabableGameObject); } } } } } } public void resetObjects () { for (int i = 0; i < grabableObjectsInfoList.Count; i++) { grabableObjectsInfoList [i].grabableTransform.position = grabableObjectsInfoList [i].originalPosition; grabableObjectsInfoList [i].grabableTransform.rotation = grabableObjectsInfoList [i].originalRotation; Rigidbody currentRigidbody = grabableObjectsInfoList [i].grabableGameObject.GetComponent (); if (currentRigidbody != null) { currentRigidbody.isKinematic = false; } } resetNumberObjectsPlaced (); if (useEventOnResetPuzzle) { if (resetPuzzleEvent.GetPersistentEventCount () > 0) { resetPuzzleEvent.Invoke (); } } } public void OnTriggerExit (Collider col) { if (respawnDragableElements && respawnPosition != null) { if (showDebugPrint) { print ("checking if object exits trigger " + col.gameObject.name); } setObjectBackToPuzzleZone (col.gameObject); } } void setObjectBackToPuzzleZone (GameObject newObject) { GameObject objectToCheck = canBeDragged (newObject); if (objectToCheck != null) { if (showDebugPrint) { print ("checking if object exits trigger " + objectToCheck.name + " " + newObject.name); } currentDragableElement = objectToCheck; if (currentDragableElement == currentGrabbedObject) { dropObject (); } Component [] ColliderList = currentDragableElement.GetComponentsInChildren (typeof (Collider)); foreach (Collider child in ColliderList) { if (!child.isTrigger) { child.enabled = false; } } Rigidbody currentRigidbody = currentDragableElement.GetComponent (); if (currentRigidbody != null) { currentRigidbody.isKinematic = true; } if (respawnDragableElementsInOriginalPosition) { for (int i = 0; i < grabableObjectsInfoList.Count; i++) { if (grabableObjectsInfoList [i].grabableGameObject == currentDragableElement) { grabableObjectsInfoList [i].grabableTransform.position = grabableObjectsInfoList [i].originalPosition; grabableObjectsInfoList [i].grabableTransform.rotation = grabableObjectsInfoList [i].originalRotation; } } } else { currentDragableElement.transform.position = respawnPosition.position; currentDragableElement.transform.rotation = respawnPosition.rotation; } if (currentRigidbody != null) { currentRigidbody.isKinematic = false; } foreach (Collider child in ColliderList) { if (!child.isTrigger) { child.enabled = true; } } } } public GameObject canBeDragged (GameObject objectToCheck) { if (dragableElements.Contains (objectToCheck)) { return objectToCheck; } for (int i = 0; i < dragableElements.Count; i++) { if (objectToCheck.transform.IsChildOf (dragableElements [i].transform)) { return dragableElements [i]; } } return null; } public void dropObject () { if (resetObjectRotationCoroutine != null) { StopCoroutine (resetObjectRotationCoroutine); } currentGrabbedObjectRigidbody.freezeRotation = false; if (useColliderMaterialWhileGrabbed && grabbedObjectCollider != null) { grabbedObjectCollider.material = originalGrabbedColliderMaterial; } touching = false; movingObject = false; currentGrabbedObject = null; rotatingObject = false; increaseHoldObjectDistance = false; decreaseHoldObjectDistance = false; currentGrabbedObjectRigidbody = null; } public void checkIfObjectGrabbed (GameObject objectToCheck) { if (currentGrabbedObject == objectToCheck) { dropObject (); } } public void startOrStopPuzzle () { usingPuzzle = !usingPuzzle; if (usingPuzzle) { setCurrentPlayer (electronicDeviceManager.getCurrentPlayer ()); } else { if (resetObjectsWhenStopUse && !puzzleSolved) { resetObjects (); } rotationPointPivot.localRotation = originalRotationPointPivotRotation; rotationPointCamera.localRotation = oriinalRotationPointCameraRotation; lookAngle = Vector3.zero; } if (puzzleSystemPlayerManager != null) { puzzleSystemPlayerManager.setUsingPuzzleState (usingPuzzle); } if (activateActionScreen) { playerInput.enableOrDisableActionScreen (actionScreenName, usingPuzzle); } if (useMeshTextForClues) { if (meshTextGameObject != null) { meshTextGameObject.SetActive (usingPuzzle); } } setMainColliderTriggerEnabledState (!usingPuzzle); } public void setCurrentPlayer (GameObject player) { currentPlayer = player; if (currentPlayer != null) { playerComponentsManager mainPlayerComponentsManager = currentPlayer.GetComponent (); puzzleSystemPlayerManager = mainPlayerComponentsManager.getPuzzleSystemPlayerManagement (); mainCamera = mainPlayerComponentsManager.getPlayerCamera ().getMainCamera (); mainCameraTransform = mainCamera.transform; playerInput = mainPlayerComponentsManager.getPlayerInputManager (); puzzleSystemPlayerManager.setcurrentPuzzleSystem (this); } } public void increaseNumberObjectsPlaced () { currentNumberObjectsPlaced++; if (currentNumberObjectsPlaced == numberObjectsToPlace) { solvePuzzle (); } } public void resetNumberObjectsPlaced () { currentNumberObjectsPlaced = 0; } public void solvePuzzle () { if (puzzleSolvedEvent.GetPersistentEventCount () > 0) { puzzleSolvedEvent.Invoke (); } puzzleSolved = true; if (disableObjectActionAfterResolve) { deviceStringActionManager.showIcon = false; removeDeviceFromList (); StartCoroutine (waitingAfterUnlock ()); } if (disableObjectTriggerAfterResolve) { setMainColliderTriggerEnabledState (false); } if (usePuzzleSolvedSound) { playSound (puzzleSolvedAudioElement); } } public void setMainColliderTriggerEnabledState (bool state) { if (mainCollider != null) { if (disableObjectTriggerAfterResolve) { if (puzzleSolved) { if (state) { return; } } } mainCollider.enabled = state; } } public void resetCurrentObjectRotation () { if (resetObjectRotationCoroutine != null) { StopCoroutine (resetObjectRotationCoroutine); } resetObjectRotationCoroutine = StartCoroutine (resetCurrenObjectRotationCoroutine ()); } IEnumerator resetCurrenObjectRotationCoroutine () { if (showDebugPrint) { print ("reset current object rotation start"); } GameObject objectToRotate = currentGrabbedObject; Quaternion targetRotation = Quaternion.identity; for (int i = 0; i < grabableObjectsInfoList.Count; i++) { if (grabableObjectsInfoList [i].grabableGameObject == objectToRotate) { targetRotation = grabableObjectsInfoList [i].originalRotation; } } float timePassed = 0; while (objectToRotate.transform.rotation != targetRotation || timePassed < 3) { objectToRotate.transform.rotation = Quaternion.Slerp (objectToRotate.transform.rotation, targetRotation, Time.deltaTime * rotateSpeed); timePassed += Time.deltaTime; yield return null; } if (showDebugPrint) { print ("reset current object rotation end"); } } public void removeDeviceFromList () { if (currentPlayer != null) { currentPlayer.GetComponent ().removeDeviceFromListExternalCall (gameObject); } } public void playSound (AudioElement soundEffect) { if (soundEffect != null) { if (mainAudioSource != null) GKC_Utils.checkAudioSourcePitch (mainAudioSource); AudioPlayer.PlayOneShot (soundEffect, gameObject); } } IEnumerator waitingAfterUnlock () { yield return new WaitForSeconds (waitDelayToStopUsePuzzleAfterResolve); if (useEventAfterResolveDelay) { eventAfterResolveDelay.Invoke (); } electronicDeviceManager.stopUsindDevice (); yield return null; } //CALL INPUT FUNCTIONS public void inputSetRotateObjectState (bool state) { if (usingPuzzle && objectCanBeRotated && currentGrabbedObjectRigidbody != null) { if (state) { rotatingObject = true; currentGrabbedObjectRigidbody.freezeRotation = true; } else { rotatingObject = false; currentGrabbedObjectRigidbody.freezeRotation = false; } } } public void inputIncreaseObjectHolDistanceByButton (bool state) { if (usingPuzzle && movingObject) { if (state) { increaseHoldObjectDistance = true; } else { increaseHoldObjectDistance = false; } } } public void inputDecreaseObjectHolDistanceByButton (bool state) { if (usingPuzzle && movingObject) { if (state) { decreaseHoldObjectDistance = true; } else { decreaseHoldObjectDistance = false; } } } public void inputSetObjectHolDistanceByMouseWheel (bool state) { if (usingPuzzle && movingObject) { if (state) { lastTimeMouseWheelUsed = Time.time; increaseHoldObjectDistance = true; mouseWheelUsedPreviously = true; } else { lastTimeMouseWheelUsed = Time.time; decreaseHoldObjectDistance = true; mouseWheelUsedPreviously = true; } } } public void inputResetPuzzle () { if (usingPuzzle && canResetObjectsWhileUsing && !puzzleSolved) { if (currentGrabbedObject == null) { resetObjects (); } else { resetCurrentObjectRotation (); } } } void OnDrawGizmos () { if (!showGizmo) { return; } if (GKC_Utils.isCurrentSelectionActiveGameObject (gameObject)) { DrawGizmos (); } } void OnDrawGizmosSelected () { DrawGizmos (); } //draw the pivot and the final positions of every door void DrawGizmos () { if (showGizmo) { Gizmos.color = gizmoColor; Gizmos.DrawLine (transform.position, rotationPointPivot.position); Gizmos.DrawLine (rotationPointPivot.position, rotationPointCamera.position); Gizmos.DrawLine (rotationPointPivot.position, cameraPosition.position); Gizmos.DrawSphere (transform.position, gizmoRadius); Gizmos.DrawSphere (rotationPointPivot.position, gizmoRadius); Gizmos.DrawSphere (rotationPointCamera.position, gizmoRadius); Gizmos.DrawSphere (cameraPosition.position, gizmoRadius); Gizmos.color = Color.green; GKC_Utils.drawGizmoArrow (cameraPosition.position, cameraPosition.forward * gizmoArrowLineLength, gizmoArrowColor, gizmoArrowLength, gizmoArrowAngle); } } [System.Serializable] public class grabableObjectsInfo { public GameObject grabableGameObject; public Transform grabableTransform; public Vector3 originalPosition; public Quaternion originalRotation; } }