using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic; using UnityEngine.Events; using System.Linq; public class gravitySystem : gravityObjectManager { public bool gravityPowerEnabled; public bool gravityPowerInputEnabled; public Transform gravityCenter; public GameObject playerCameraGameObject; public bool liftToSearchEnabled; public bool randomRotationOnAirEnabled; public GameObject cursor; public LayerMask layer; public float searchSurfaceSpeed = 5; public float accelerateSpeed = 20; public float airControlSpeed = 5; bool cursorActive; bool cursorLocated; public bool preserveVelocityWhenDisableGravityPower; float extraMultiplierPreserveVelocity; public float highGravityMultiplier; public List materialToChange = new List (); public bool changeModelColor; public Color powerColor; public float hoverSpeed; public float hoverAmount; public float hoverSmooth; public GameObject arrow; bool arrowLocated; public bool powerActivated; public bool recalculatingSurface; public bool searchingSurface; public bool searchingNewSurfaceBelow; public bool searchAround; public Vector3 currentNormal = new Vector3 (0, 1, 0); public bool dead; public bool firstPersonView; public Renderer playerRenderer; public bool usedByAI; public string tagForCircumnavigate = "sphere"; public string tagForMovingObjects = "moving"; public float rotateToSurfaceSpeed = 2; public float rotateToRegularGravitySpeed = 2; public Vector3 regularGravity = new Vector3 (0, 1, 0); public bool gravityPowerActive; public bool startWithNewGravity; public bool usePlayerRotation; public bool adjustRotationToSurfaceFound; public Vector3 newGravityToStart; public bool zeroGravityModeOn; public bool startWithZeroGravityMode; public bool canResetRotationOnZeroGravityMode; public bool canAdjustToForwardSurface; public Transform forwardSurfaceRayPosition; public float maxDistanceToAdjust; public float resetRotationZeroGravitySpeed; public float adjustToForwardSurfaceSpeed; public bool canActivateFreeFloatingMode; public bool freeFloatingModeOn; public bool useCustomDirectionOnResetZeroGravityRotation; public Vector3 customDirectionOnResetZeroGravityRotation; public bool useEventsOnFreeFloatingModeStateChange; public UnityEvent evenOnFreeFloatingModeStateEnabled; public UnityEvent eventOnFreeFloatingModeStateDisabled; public bool useEventsOnZeroGravityModeStateChange; public UnityEvent evenOnZeroGravityModeStateEnabled; public UnityEvent eventOnZeroGravityModeStateDisabled; public bool useEventsOnUseGravityPowerStateChange; public UnityEvent eventsOnUseGravityPowerStateEnabled; public UnityEvent eventsOnUseGravityPowerStateDisabled; public float circumnavigateRotationSpeed = 10; public bool circumnavigateCurrentSurfaceActive; public bool useLerpRotation; public Transform gravityAdherenceRaycastParent; public bool checkSurfaceBelowLedge; public float surfaceBelowLedgeRaycastDistance = 3; public float belowLedgeRotationSpeed = 10; public Transform surfaceBelowRaycastTransform; public bool checkSurfaceInFront; public float surfaceInFrontRaycastDistance = 0.5f; public float surfaceInFrontRotationSpeed = 10; public Transform surfaceInFrontRaycastTransform; public bool checkCircumnavigateSurfaceOnZeroGravity = true; public bool searchNewSurfaceOnHighFallSpeed = true; public float minSpeedToSearchNewSurface = 15; bool searchNewSurfaceOnHighFallSpeedPaused; public bool pauseSearchNewSurfaceOnHighFallSpeedOnReverseGravityInput = true; public bool shakeCameraOnHighFallSpeed = true; public float minSpeedToShakeCamera = 15; bool cameraShakeCanBeUsed = true; public bool checkSurfaceBelowOnRegularState; public float timeToSetNullParentOnAir = 0.5f; float lastTimeParentFound; public bool stopAimModeWhenSearchingSurface; public Transform pivotCameraTransform; public SphereCollider gravityCenterCollider; public playerController playerControllerManager; public otherPowers powers; public CapsuleCollider playerCollider; public playerInputManager playerInput; public playerWeaponsManager weaponsManager; public Rigidbody mainRigidbody; public playerCamera playerCameraManager; public Transform mainCameraTransform; public Vector3 debugGravityDirection; public bool hovering; public bool turning; public bool checkGravityArrowStateActive = true; public float raycastDistanceToCheckBelowPlayer = 10; public bool useInfiniteRaycastDistanceToCheckBelowPlayer; public bool updateCurrentNormalByExternalTransformActive; Transform currentUpdateCurrentNormalByExternalTransform; public bool allowCircumnavigationOnAllSurfacesWithIgnoretagList; public List circumnavigationOnAllSurfacesWithIgnoretagList = new List (); bool circumnavigationOnAllSurfacesWithIgnoretagListAssigned; bool ignoreUseGravityCenterForRotationActive; public bool setOnGroundStateOnTeleportToSurfaceOnZeroGravity; bool ignoreRecalculateSurface; Transform currentCenterPoint; bool currentCenterPointAssigned; zeroGravityRoomSystem currentZeroGravityRoom; Transform playerCameraTransform; Vector3 currentPlayerPosition; Quaternion arrowRotation; Color originalPowerColor; bool accelerating; bool rotating = false; Vector3 gravityDirection; Vector3 rightAxis; float timer = 0.75f; float rotateAmount = 40; float normalGravityMultiplier; Vector3 surfaceNormal; Vector3 turnDirection; bool playerIsChildOfParentActive; GameObject fatherDetected; bool circumnavigableSurfaceFound; RaycastHit hit; Ray ray; public bool choosingDirection; bool onGround; bool lifting; Coroutine rotateCharacterState; Coroutine rotateToSurfaceState; Transform externalGravityCenter; Transform currentSurfaceBelowPlayer; Transform previousSurfaceBelowPlayer; Vector3 currentPosition; bool preservingVelocity; Vector3 previousRigidbodyVelocity; bool playerInsideGravityRoom; Vector3 rayPosition; Vector3 rayDirection; Vector3 currentRotatingNormal; Coroutine colorCoroutine; public setGravity currentSetGravityManager; bool surfaceFound; RaycastHit currentSurfaceFound; float currentCircumnagivateRotationSpeed; Vector2 axisValues; float verticalInput; float horizontalInput; Vector3 moveInput; float gravityAdherenceRaycastParentAngleRotation; Coroutine zeroGravityModeRotateCharacterCoroutine; Coroutine teleportCoroutine; Coroutine freeFloatingModeCoroutine; bool gravityArrowCurrentlyActive; Transform playerTransform; bool teleportInProcess; bool startWithZeroGravityModeChecked; bool cameraShakeActive; //Editor variables public bool showCircumnavigationhSettings; public bool showZeroGravitySettings; public bool showFreeFloatingModeSettings; public bool showEventsSettings; public bool showOtherSettings; public bool showDebugSettings; public bool showAllSettings; public bool showComponents; public bool showGizmo; Vector3 vector3Zero = Vector3.zero; Quaternion quaternionIdentity = Quaternion.identity; void Awake () { normalGravityMultiplier = playerControllerManager.getGravityMultiplier (); playerTransform = transform; //get the pivot of the camera playerCameraTransform = playerCameraGameObject.transform; } void Start () { mainRigidbody.freezeRotation = true; //the gravity center has a sphere collider, that surrounds completly the player to use it when the player searchs a new surface, //detecting the collision with any object to rotate the player to that surface //this is done like this to avoid that the player cross a collider when he moves while he searchs a new surface //get all the neccessary components in the player //get the original value of some parameters originalPowerColor = powerColor; GameObject newGravityCenter = new GameObject (); externalGravityCenter = newGravityCenter.transform; externalGravityCenter.name = "External Gravity Center"; externalGravityCenter.SetParent (playerTransform); if (startWithNewGravity) { if (usePlayerRotation) { Vector3 normalDirection = -playerTransform.up; if (adjustRotationToSurfaceFound) { if (Physics.Raycast (playerTransform.position, -playerTransform.up, out hit, Mathf.Infinity, layer)) { normalDirection = hit.normal; } } if (playerTransform.up != currentNormal) { setNormal (normalDirection); } } else { setNormal (newGravityToStart); } } currentRotatingNormal = currentNormal; if (arrow != null) { arrowLocated = true; if (checkGravityArrowStateActive) { if (arrow.activeSelf) { arrow.SetActive (false); } } else { gravityArrowCurrentlyActive = true; } } if (cursor != null) { cursorLocated = true; } } void Update () { currentPosition = playerTransform.position; checkGravityArrowState (); if (!startWithZeroGravityModeChecked) { if (startWithZeroGravityMode) { setZeroGravityModeOnState (true); } startWithZeroGravityModeChecked = true; } //elevate the player above the ground when the gravity power is enabled and the player was in the ground before it if (lifting) { bool surfaceAbove = false; //check if there is any obstacle above the player while he is being elevated, to prevent he can cross any collider ray = new Ray (currentPosition + 1.5f * playerTransform.up, playerTransform.up); if (Physics.SphereCast (ray, 0.4f, out hit, 0.5f, layer)) { surfaceAbove = true; } else { //if the ray doesn't found any surface, keep lifting the player until the timer reachs its target value timer -= Time.deltaTime; playerTransform.Translate ((Time.deltaTime * 4) * Vector3.up); playerCameraTransform.Translate ((Time.deltaTime * 4) * Vector3.up); } //if the timer ends or a surface is found, stop the lifting and start rotate the player to float in the air if (surfaceAbove || timer < 0) { lifting = false; timer = 0.75f; searchingSurface = false; searchAround = false; if (canRotatePlayer ()) { rotateMeshPlayer (); } setHoverState (true); } } //moving in the air with the power gravity activated looking for a new surface if (searchingSurface) { //parameters to store the position and the direction of the raycast that checks any close surface to the player rayPosition = vector3Zero; rayDirection = vector3Zero; //set the size of the ray float rayDistance = 0; //if the player has set the direction of the air movement, the raycast starts in camera pivot position //else the player is falling and reach certain amount of velocity, so the next surface that he will touch becomes in his new ground //and the raycast starts in the player position if (!searchingNewSurfaceBelow) { rayDistance = 2; Vector3 newVelocity = (Mathf.Abs (playerControllerManager.getGravityForce ()) * mainRigidbody.mass * searchSurfaceSpeed) * gravityDirection; //when the player searchs a new surface using the gravity force, the player can moves like when he falls if (!playerControllerManager.isPlayerRunning ()) { //get the global input and convert it to the local direction, using the axis in the changegravity script Vector3 forwardAxis = Vector3.Cross (gravityDirection, rightAxis); Vector3 newMoveInput = playerControllerManager.getVerticalInput () * forwardAxis + playerControllerManager.getHorizontalInput () * rightAxis; if (newMoveInput.magnitude > 1) { newMoveInput.Normalize (); } if (newMoveInput.magnitude > 0) { newVelocity += airControlSpeed * newMoveInput; } } //apply and extra force if the player increase his movement if (accelerating) { newVelocity += accelerateSpeed * gravityDirection; } //make a lerp of the velocity applied to the player to move him smoothly mainRigidbody.linearVelocity = Vector3.Lerp (mainRigidbody.linearVelocity, newVelocity, Time.deltaTime * 2); //set the direction of the ray that checks any surface rayPosition = pivotCameraTransform.position; rayDirection = gravityDirection; if (currentNormal == regularGravity) { rayDistance = GKC_Utils.distance (rayPosition, currentPosition) + 0.5f; } } //else, the player is falling in his ground direction, so the ray to check a new surface is below his feet else { rayPosition = currentPosition; rayDirection = -playerTransform.up; rayDistance = 0.6f; } if (showGizmo) { //launch a raycast to check any surface Debug.DrawRay (rayPosition, rayDistance * rayDirection, Color.yellow); } if (Physics.Raycast (rayPosition, rayDirection, out hit, rayDistance, layer)) { //if the object detected has not trigger and rigidbody, then if (!hit.collider.isTrigger && hit.rigidbody == null) { //disable the search of the surface and rotate the player to that surface playerControllerManager.setGravityPowerActiveState (false); playerCameraManager.sethorizontalCameraLimitActiveOnAirState (true); setPowerActivateState (false); searchingNewSurfaceBelow = false; searchingSurface = false; searchAround = false; mainRigidbody.linearVelocity = vector3Zero; //disable the collider in the gravity center and enable the capsule collider in the player gravityCenterCollider.enabled = false; playerCollider.isTrigger = false; //check if the object detected can be circumnavigate if (hit.collider.gameObject.CompareTag (tagForCircumnavigate) || canCircumnavigateObject (hit.collider.transform)) { circumnavigableSurfaceFound = true; } //check if the object is moving to parent the player inside it if (hit.collider.gameObject.CompareTag (tagForMovingObjects)) { addParent (hit.collider.gameObject); } //set the camera in its regular position playerCameraManager.changeCameraFov (false); //if the new normal is different from the previous normal in the gravity power, then rotate the player if (hit.normal != currentNormal) { checkRotateToSurface (hit.normal, rotateToSurfaceSpeed); } //if the player back to the regular gravity value, change its color to the regular state if (hit.normal == regularGravity) { changeColor (false); } } } if (!turning && canRotatePlayer ()) { rotateMeshPlayer (); } } //if the player falls and reachs certain velocity, the camera shakes and the mesh of the player rotates //also, if the gravity power is activated, look a new surface to change the gravity to the found surface if (!freeFloatingModeOn && !zeroGravityModeOn && !onGround && !searchingNewSurfaceBelow && !choosingDirection && !powerActivated && !playerControllerManager.isFlyingActive () && !playerControllerManager.isSwimModeActive () && !playerControllerManager.isPauseCameraShakeFromGravityActive ()) { if (shakeCameraOnHighFallSpeed && playerTransform.InverseTransformDirection (mainRigidbody.linearVelocity).y < -minSpeedToShakeCamera) { if (!playerControllerManager.isSlowFallExternallyActive ()) { enableCameraShake (); if (!weaponsManager.isCarryingWeaponInThirdPerson ()) { rotateMeshPlayer (); } } } if (searchNewSurfaceOnHighFallSpeed && !searchNewSurfaceOnHighFallSpeedPaused && playerTransform.InverseTransformDirection (mainRigidbody.linearVelocity).y < -minSpeedToSearchNewSurface) { //if the gravity of the player is different from the regular gravity, start searchin the new surface if (currentNormal != regularGravity) { searchingNewSurfaceBelow = true; searchingSurface = true; recalculatingSurface = false; circumnavigableSurfaceFound = false; } } } //walk in spheres and moving objects, recalculating his new normal and lerping the player to the new rotation if (!lifting && !searchingSurface && (circumnavigableSurfaceFound || playerIsChildOfParentActive) && recalculatingSurface && !rotating) { float rayDistance = 0.5f; if (!onGround) { if (!freeFloatingModeOn && !zeroGravityModeOn) { rayDistance = raycastDistanceToCheckBelowPlayer; if (useInfiniteRaycastDistanceToCheckBelowPlayer) { rayDistance = 1000; } } } surfaceFound = false; //get the normal direction of the object below the player, to recalculate the rotation of the player if (Physics.Raycast (currentPosition + 0.1f * playerTransform.up, -playerTransform.up, out hit, rayDistance, layer)) { currentSurfaceFound = hit; surfaceFound = true; currentCircumnagivateRotationSpeed = circumnavigateRotationSpeed; } //Get the correct raycast orientation according to input, for example, it is no the same ray position and direction if the player is walking forward or backward on //first person or if he is aiming if (checkSurfaceBelowLedge || checkSurfaceInFront) { rayPosition = currentPosition + 0.1f * playerTransform.up; if (playerControllerManager.isLookingInCameraDirection ()) { axisValues = playerInput.getPlayerRawMovementAxis (); verticalInput = axisValues.y; horizontalInput = axisValues.x; rayPosition += (verticalInput * 0.2f) * playerTransform.forward; rayPosition += (horizontalInput * 0.2f) * playerTransform.right; moveInput = (verticalInput * playerTransform.forward + horizontalInput * playerTransform.right); gravityAdherenceRaycastParentAngleRotation = Vector3.SignedAngle (playerTransform.forward, moveInput, playerTransform.up); if (verticalInput == 0 && horizontalInput == 0) { gravityAdherenceRaycastParentAngleRotation = 0; } } else { rayPosition += 0.2f * playerTransform.forward; gravityAdherenceRaycastParentAngleRotation = 0; } gravityAdherenceRaycastParent.localRotation = Quaternion.Euler (new Vector3 (0, gravityAdherenceRaycastParentAngleRotation, 0)); } if (checkSurfaceBelowLedge) { rayDirection = -playerTransform.up; if (showGizmo) { Debug.DrawRay (rayPosition, rayDirection, Color.white); } if (!Physics.Raycast (rayPosition, rayDirection, out hit, 1, layer)) { if (showGizmo) { Debug.DrawRay (rayPosition, rayDirection, Color.green); } rayPosition = surfaceBelowRaycastTransform.position; rayDirection = surfaceBelowRaycastTransform.forward; if (Physics.Raycast (rayPosition, rayDirection, out hit, surfaceBelowLedgeRaycastDistance, layer)) { if (showGizmo) { Debug.DrawRay (rayPosition, hit.distance * rayDirection, Color.yellow); } currentSurfaceFound = hit; surfaceFound = true; currentCircumnagivateRotationSpeed = belowLedgeRotationSpeed; } else { if (showGizmo) { Debug.DrawRay (rayPosition, surfaceBelowLedgeRaycastDistance * rayDirection, Color.red); } } } else { if (showGizmo) { Debug.DrawRay (rayPosition, hit.distance * rayDirection, Color.red); } } } if (checkSurfaceInFront) { rayPosition = surfaceInFrontRaycastTransform.position; rayDirection = surfaceInFrontRaycastTransform.forward; if (Physics.Raycast (rayPosition, rayDirection, out hit, surfaceInFrontRaycastDistance, layer)) { currentSurfaceFound = hit; surfaceFound = true; currentCircumnagivateRotationSpeed = surfaceInFrontRotationSpeed; } } bool surfaceNormalFound = false; if (surfaceFound) { if (!currentSurfaceFound.collider.isTrigger && currentSurfaceFound.rigidbody == null) { //the object detected can be circumnavigate, so get the normal direction if (currentSurfaceFound.collider.gameObject.CompareTag (tagForCircumnavigate) || canCircumnavigateObject (currentSurfaceFound.transform)) { surfaceNormal = currentSurfaceFound.normal; surfaceNormalFound = true; } //the object is moving, so get the normal direction and set the player as a children of the moving obejct else if (currentSurfaceFound.collider.gameObject.CompareTag (tagForMovingObjects)) { surfaceNormal = currentSurfaceFound.normal; if (!playerIsChildOfParentActive) { addParent (currentSurfaceFound.collider.gameObject); } surfaceNormalFound = true; } } } else { if (playerIsChildOfParentActive) { removeParent (); } } if (currentCenterPointAssigned) { if (surfaceNormalFound) { Vector3 heading = playerTransform.position - currentCenterPoint.position; float distance = heading.magnitude; Vector3 direction = heading / distance; surfaceNormal = direction; } } if ((!zeroGravityModeOn && !freeFloatingModeOn) || onGround) { if (useLerpRotation) { //recalculate the rotation of the player and the camera according to the normal of the surface under the player currentNormal = Vector3.Lerp (currentNormal, surfaceNormal, currentCircumnagivateRotationSpeed * Time.deltaTime); Vector3 myForward = Vector3.Cross (playerTransform.right, currentNormal); Quaternion dstRot = Quaternion.LookRotation (myForward, currentNormal); playerTransform.rotation = Quaternion.Lerp (playerTransform.rotation, dstRot, currentCircumnagivateRotationSpeed * Time.deltaTime); Vector3 myForwardCamera = Vector3.Cross (playerCameraTransform.right, currentNormal); Quaternion dstRotCamera = Quaternion.LookRotation (myForwardCamera, currentNormal); playerCameraTransform.rotation = Quaternion.Lerp (playerCameraTransform.rotation, dstRotCamera, currentCircumnagivateRotationSpeed * Time.deltaTime); } else { currentNormal = Vector3.Slerp (currentNormal, surfaceNormal, currentCircumnagivateRotationSpeed * Time.deltaTime); Vector3 myForward = Vector3.Cross (playerTransform.right, currentNormal); Quaternion dstRot = Quaternion.LookRotation (myForward, currentNormal); playerTransform.rotation = Quaternion.Slerp (playerTransform.rotation, dstRot, currentCircumnagivateRotationSpeed * Time.deltaTime); Vector3 myForwardCamera = Vector3.Cross (playerCameraTransform.right, currentNormal); Quaternion dstRotCamera = Quaternion.LookRotation (myForwardCamera, currentNormal); playerCameraTransform.rotation = Quaternion.Slerp (playerCameraTransform.rotation, dstRotCamera, currentCircumnagivateRotationSpeed * Time.deltaTime); } updateCurrentRotatingNormal (currentNormal); } //set the normal in the playerController component playerControllerManager.setCurrentNormalCharacter (currentNormal); } if (updateCurrentNormalByExternalTransformActive) { currentNormal = currentUpdateCurrentNormalByExternalTransform.up; playerControllerManager.setCurrentNormalCharacter (currentNormal); updateCurrentRotatingNormal (currentNormal); } if (ignoreRecalculateSurface) { recalculatingSurface = false; gravityPowerActive = false; } if (zeroGravityModeOn && !onGround && !rotating) { currentNormal = playerTransform.up; playerControllerManager.setCurrentNormalCharacter (currentNormal); updateCurrentRotatingNormal (currentNormal); } //set a cursor in the screen when the character can choose a direction to change his gravity if (!usedByAI) { if (cursorLocated) { if (choosingDirection) { if (!cursorActive) { cursor.SetActive (true); cursorActive = true; } } if (!choosingDirection) { if (cursorActive) { cursor.SetActive (false); cursorActive = false; } } } } //if the player can choosed a direction, lerp his velocity to zero if (choosingDirection) { mainRigidbody.linearVelocity = Vector3.Lerp (mainRigidbody.linearVelocity, vector3Zero, Time.deltaTime * 2); } if (rotating && !playerControllerManager.isPlayerRunning ()) { mainRigidbody.linearVelocity = vector3Zero; } if ((gravityPowerActive || circumnavigateCurrentSurfaceActive || (zeroGravityModeOn && checkCircumnavigateSurfaceOnZeroGravity)) && !powerActivated) { currentSurfaceBelowPlayer = playerControllerManager.getCurrentSurfaceBelowPlayer (); if (currentSurfaceBelowPlayer != null) { //check if the object detected can be circumnavigate if (currentSurfaceBelowPlayer.CompareTag (tagForCircumnavigate) || canCircumnavigateObject (currentSurfaceBelowPlayer)) { circumnavigableSurfaceFound = true; } else { circumnavigableSurfaceFound = false; if (checkSurfaceInFront) { rayPosition = surfaceInFrontRaycastTransform.position; rayDirection = surfaceInFrontRaycastTransform.forward; if (Physics.Raycast (rayPosition, rayDirection, out hit, surfaceInFrontRaycastDistance, layer)) { currentSurfaceBelowPlayer = hit.collider.transform; if (currentSurfaceBelowPlayer.CompareTag (tagForCircumnavigate) || canCircumnavigateObject (currentSurfaceBelowPlayer)) { circumnavigableSurfaceFound = true; } } } } //check if the object is moving to parent the player inside it if (currentSurfaceBelowPlayer.CompareTag (tagForMovingObjects)) { if (previousSurfaceBelowPlayer != currentSurfaceBelowPlayer) { previousSurfaceBelowPlayer = currentSurfaceBelowPlayer; addParent (currentSurfaceBelowPlayer.gameObject); } } else if (playerIsChildOfParentActive && !currentSurfaceBelowPlayer.IsChildOf (fatherDetected.transform)) { removeParent (); } //if the surface where the player lands can be circumnavigated or an moving/rotating object, then keep recalculating the player throught the normal surface if (circumnavigableSurfaceFound || playerIsChildOfParentActive) { recalculatingSurface = true; } //else disable this state else { recalculatingSurface = false; } } else { if (previousSurfaceBelowPlayer) { previousSurfaceBelowPlayer = null; } if (rotating) { circumnavigableSurfaceFound = false; } } } else { if ((circumnavigableSurfaceFound || playerIsChildOfParentActive) && rotating) { circumnavigableSurfaceFound = false; } if (checkSurfaceBelowOnRegularState && !gravityPowerActive && !zeroGravityModeOn && !playerControllerManager.isPlayerSetAsChildOfParent ()) { currentSurfaceBelowPlayer = playerControllerManager.getCurrentSurfaceBelowPlayer (); if (currentSurfaceBelowPlayer != null) { //check if the object is moving to parent the player inside it if (previousSurfaceBelowPlayer != currentSurfaceBelowPlayer) { previousSurfaceBelowPlayer = currentSurfaceBelowPlayer; if (currentSurfaceBelowPlayer.CompareTag (tagForMovingObjects)) { addParent (currentSurfaceBelowPlayer.gameObject); lastTimeParentFound = Time.time; } else if (playerIsChildOfParentActive && !currentSurfaceBelowPlayer.IsChildOf (fatherDetected.transform)) { removeParent (); } } } else { if (previousSurfaceBelowPlayer != null) { previousSurfaceBelowPlayer = null; } if (Time.time > timeToSetNullParentOnAir + lastTimeParentFound) { if (playerIsChildOfParentActive) { removeParent (); } } } } else { if (currentSurfaceBelowPlayer != null) { currentSurfaceBelowPlayer = null; } if (previousSurfaceBelowPlayer != null) { previousSurfaceBelowPlayer = null; } } } } public void setAllowCircumnavigationOnAllSurfacesWithIgnoretagListState (bool state) { allowCircumnavigationOnAllSurfacesWithIgnoretagList = state; } public void setCircumnavigationOnAllSurfacesWithIgnoretagList (List newList) { circumnavigationOnAllSurfacesWithIgnoretagList = newList; circumnavigationOnAllSurfacesWithIgnoretagListAssigned = circumnavigationOnAllSurfacesWithIgnoretagList.Count != 0; } bool canCircumnavigateObject (Transform objectToCheck) { bool result = false; if (allowCircumnavigationOnAllSurfacesWithIgnoretagList) { if (circumnavigationOnAllSurfacesWithIgnoretagListAssigned) { if (!circumnavigationOnAllSurfacesWithIgnoretagList.Contains (objectToCheck.tag)) { result = true; } } else { result = true; } } return result; } public void setUpdateCurrentNormalByExternalTransformState (bool state, Transform newTransform, bool ignoreRecalculateSurfaceValue) { updateCurrentNormalByExternalTransformActive = state; currentUpdateCurrentNormalByExternalTransform = newTransform; ignoreRecalculateSurface = ignoreRecalculateSurfaceValue; if (!state) { Vector3 newNormal = currentUpdateCurrentNormalByExternalTransform.up; float currentAngleDifference = Vector3.Angle (regularGravity, newNormal); if (Mathf.Abs (currentAngleDifference) < 1) { newNormal = regularGravity; } currentNormal = newNormal; playerControllerManager.setCurrentNormalCharacter (currentNormal); updateCurrentRotatingNormal (currentNormal); ignoreRecalculateSurface = false; } } public void setIgnoreRecalculateSurfaceState (bool state) { ignoreRecalculateSurface = state; } //rotate randomly the mesh of the player in the air, also make that mesh float while chooses a direction in the air void FixedUpdate () { if (turning) { if (randomRotationOnAirEnabled || powerActivated) { gravityCenter.transform.Rotate ((rotateAmount * Time.deltaTime) * turnDirection); } if (weaponsManager.isCarryingWeaponInThirdPerson () || powers.isAimingPowerInThirdPerson ()) { turning = false; checkRotateCharacter (vector3Zero); } } if (hovering) { float posTargetY = Mathf.Sin (Time.time * hoverSpeed) * hoverAmount; mainRigidbody.position = Vector3.MoveTowards (mainRigidbody.position, mainRigidbody.position + posTargetY * playerTransform.up, Time.deltaTime * hoverSmooth); } } void checkGravityArrowState () { //the arrow in the back of the player looks to the direction of the real gravity if (arrowLocated) { if (gravityArrowCurrentlyActive) { currentPlayerPosition = new Vector3 (currentPosition.x, 0, currentPosition.z); if (currentPlayerPosition != vector3Zero) { arrowRotation = Quaternion.LookRotation (currentPlayerPosition); if (arrowRotation.eulerAngles != vector3Zero) { arrow.transform.rotation = arrowRotation; } } if (checkGravityArrowStateActive) { if (!powerActivated && !searchingSurface && currentNormal == regularGravity) { gravityArrowCurrentlyActive = false; arrow.SetActive (false); } } } else { if (powerActivated || searchingSurface || currentNormal != regularGravity) { gravityArrowCurrentlyActive = true; arrow.SetActive (true); } } } } public void checkOnGroundOrAirState () { onGroundOrOnAir (playerControllerManager.isPlayerOnGround ()); } //playerController set the values of ground in this script and in the camera code public override void onGroundOrOnAir (bool state) { onGround = state; if (onGround) { //the player is on the ground //set the states in the camera, on ground, stop any shake of the camera, and back the camera to its regular position if it has been moved playerCameraManager.onGroundOrOnAir (true); disableCameraShake (); playerCameraManager.changeCameraFov (false); //stop rotate the player turning = false; //if the surface where the player lands can be circumnavigated or an moving/rotating object, then keep recalculating the player throught the normal surface if ((circumnavigableSurfaceFound || playerIsChildOfParentActive) && (gravityPowerActive || circumnavigateCurrentSurfaceActive || (zeroGravityModeOn && checkCircumnavigateSurfaceOnZeroGravity))) { recalculatingSurface = true; } //else disable this state else { recalculatingSurface = false; } //set the gravity force applied to the player to its regular state playerControllerManager.setGravityMultiplierValueFromExternalFunction (normalGravityMultiplier); //set the model rotation to the regular state checkRotateCharacter (vector3Zero); accelerating = false; if (currentNormal != regularGravity) { gravityPowerActive = true; } } else { //the player is on the air playerCameraManager.onGroundOrOnAir (false); } } //when the player searchs a new surface using the gravity power on button, check the collisions in the gravity center sphere collider, to change the //gravity of the player to the detected normal direction void OnCollisionEnter (Collision collision) { //check that the player is searching a surface, the player is not running, and that he is searching around if (searchingSurface && turning && searchAround && !playerControllerManager.isPlayerRunning ()) { //check that the detected object is not a trigger or the player himself if (!collision.gameObject.CompareTag ("Player") && collision.rigidbody == null && !collision.collider.isTrigger) { //get the collision contant point to change the direction of the ray that searchs a new direction, setting the direction from the player //to the collision point as the new direction Vector3 hitDirection = collision.contacts [0].point - pivotCameraTransform.position; hitDirection = hitDirection / hitDirection.magnitude; gravityDirection = hitDirection; searchAround = false; } } } //now the gravity power is in a function, so it can be called from keyboard and a touch button public void activateGravityPower () { gravityPowerActive = true; // print ("activate gravity power"); //if the option to lift the player when he uses the gravity power is disable, then searchs an new surface in the camera direction if (!liftToSearchEnabled) { changeOnTrigger (mainCameraTransform.TransformDirection (Vector3.forward), mainCameraTransform.TransformDirection (Vector3.right)); } //else lift the player, and once that he has been lifted, then press again the gravit power on button to search an new surface //or disable the gravity power else { //enable the sphere collider in the gravity center gravityCenterCollider.enabled = true; //disable the capsule collider in the player playerCollider.isTrigger = true; //get the last time that the player was in the air playerControllerManager.lastTimeFalling = Time.time; recalculatingSurface = false; accelerating = false; //change the color of the player's textures changeColor (true); searchingNewSurfaceBelow = false; removeParent (); circumnavigableSurfaceFound = false; playerControllerManager.setGravityPowerActiveState (true); playerCameraManager.sethorizontalCameraLimitActiveOnAirState (false); setPowerActivateState (true); //calibrate the accelerometer to rotate the camera in this mode playerCameraManager.calibrateAccelerometer (); //drop any object that the player is holding and disable aim mode if (stopAimModeWhenSearchingSurface) { checkKeepPower (); checkKeepWeapons (); } playerCameraManager.checkIfDropObjectIfNotPhysical (false); //the player is in the ground, so he is elevated above it if (onGround) { lifting = true; choosingDirection = true; } //the player set the direction of the movement in the air to search a new surface if (!lifting && choosingDirection) { enableCameraShake (); setHoverState (false); if (canRotatePlayer ()) { rotateMeshPlayer (); } searchingSurface = true; circumnavigableSurfaceFound = false; removeParent (); choosingDirection = false; searchAround = true; gravityDirection = mainCameraTransform.forward; //get direction and right axis of the camera, so when the player searchs a new surface, this is used to get the local movement, //which allows to move the player in his local right, left, forward and back while he also displaces in the air rightAxis = mainCameraTransform.right; if (canRotatePlayer ()) { checkRotateCharacter (-gravityDirection); } return; } //the player is in the air, so he is stopped in it to choose a direction if (!onGround && !choosingDirection && !lifting) { disableCameraShake (); playerCameraManager.changeCameraFov (false); setHoverState (true); if (canRotatePlayer ()) { rotateMeshPlayer (); } choosingDirection = true; searchingSurface = false; searchAround = false; } } } //now the gravity power is in a function, so it can be called from keyboard and a touch button public void deactivateGravityPower () { //check that the power gravity is already enabled if ((choosingDirection || searchingSurface || currentNormal != regularGravity) && !playerControllerManager.isUsingDevice ()) { // print ("deactivate gravity power"); //disable the sphere collider in the gravity center gravityCenterCollider.enabled = false; //enable the capsule collider in the player playerCollider.isTrigger = false; //get the last time that the player was in the air playerControllerManager.lastTimeFalling = Time.time; accelerating = false; //set the force of the gravity in the player to its regular state playerControllerManager.setGravityMultiplierValueFromExternalFunction (normalGravityMultiplier); //change the color of the player changeColor (false); choosingDirection = false; circumnavigableSurfaceFound = false; removeParent (); setHoverState (false); turning = false; searchingSurface = false; searchAround = false; lifting = false; recalculatingSurface = false; timer = 0.75f; //stop to shake the camera and set its position to the regular state disableCameraShake (); playerCameraManager.changeCameraFov (false); //if the normal of the player is different from the regular gravity, rotate the player if (currentNormal != regularGravity) { if (preserveVelocityWhenDisableGravityPower) { previousRigidbodyVelocity = mainRigidbody.linearVelocity; preservingVelocity = true; extraMultiplierPreserveVelocity = 1; } checkRotateToSurface (regularGravity, rotateToRegularGravitySpeed); } //rotate the mesh of the player also checkRotateCharacter (regularGravity); playerControllerManager.setGravityPowerActiveState (false); playerCameraManager.sethorizontalCameraLimitActiveOnAirState (true); setPowerActivateState (false); //set the value of the normal in the playerController component to its regular state playerControllerManager.setCurrentNormalCharacter (regularGravity); gravityPowerActive = false; currentSetGravityManager = null; searchNewSurfaceOnHighFallSpeedPaused = false; } } public void checkKeepWeapons () { if (weaponsManager.isAimingInThirdPerson () || weaponsManager.isCarryingWeaponInThirdPerson ()) { weaponsManager.checkIfKeepSingleOrDualWeapon (); } } public void checkKeepPower () { if (powers.isAimingPowerInThirdPerson ()) { powers.deactivateAimMode (); } } //now the change of velocity is in a function, so it can be called from keyboard and a touch button public void changeMovementVelocity (bool value) { //if the player is not choosing a gravity direction and he is searching a surface or the player is not in the ground and with a changed normal, then if (!choosingDirection && (powerActivated || (!playerControllerManager.isPlayerOnGround () && currentNormal != regularGravity))) { accelerating = value; //move the camera to a further away position, and add extra force to the player's velocity if (accelerating) { playerCameraManager.changeCameraFov (true); playerControllerManager.setGravityMultiplierValueFromExternalFunction (highGravityMultiplier); //when the player accelerates his movement in the air, the camera shakes //if the player accelerates his movement in the air and shake camera is enabled if (playerCameraManager.settings.enableShakeCamera) { playerCameraManager.accelerateShake (true); } } //else, set the camera to its regular position, reset the force applied to the player's velocity else { playerCameraManager.changeCameraFov (false); playerControllerManager.setGravityMultiplierValueFromExternalFunction (normalGravityMultiplier); playerCameraManager.accelerateShake (false); } } } //convert the character in a child of the moving object public void addParent (GameObject obj) { fatherDetected = obj; parentAssignedSystem currentParentAssignedSystem = obj.GetComponent (); if (currentParentAssignedSystem != null) { fatherDetected = currentParentAssignedSystem.getAssignedParent (); } if (rotating) { externalGravityCenter.SetParent (fatherDetected.transform); } else { setFatherDetectedAsParent (); } if (fatherDetected != null) { playerIsChildOfParentActive = true; } else { playerIsChildOfParentActive = false; } } //remove the parent of the player, so he moves freely again public void removeParent () { if (rotating) { setExternalGravityCenterAsParent (); } else { setNullParent (); } fatherDetected = null; playerIsChildOfParentActive = false; } public void setExternalGravityCenterAsParent () { setNewParent (externalGravityCenter); } public void setFatherDetectedAsParent () { setNewParent (fatherDetected.transform); } public void setNullParent () { setNewParent (null); } public void setNewParent (Transform newParent) { if (playerTransform == null) { playerTransform = transform; } // if (newParent != null) { // print (newParent.name); // } else { // print ("removing parent"); // } playerTransform.SetParent (newParent); playerCameraTransform.SetParent (newParent); } public void setCorrectParent () { if (playerIsChildOfParentActive) { setFatherDetectedAsParent (); } else { setNullParent (); } } //the funcion to change camera view, to be called from a key or a touch button public void changeCameraView (bool state) { firstPersonView = state; //disable or enable the mesh of the player setGravityArrowState (!firstPersonView); } //set a random direction to rotate the character void rotateMeshPlayer () { if (!turning) { turning = true; turnDirection = new Vector3 (Random.Range (-1, 1), Random.Range (-1, 1), Random.Range (-1, 1)); if (turnDirection.magnitude == 0) { turnDirection.x = 1; } } } //set if the player is hovering or not void setHoverState (bool state) { hovering = state; } public bool canRotatePlayer () { return (stopAimModeWhenSearchingSurface || (!weaponsManager.isCarryingWeaponInThirdPerson () && !powers.isAimingPowerInThirdPerson ())); } //change the gravity of the player when he touchs the arrow trigger public void changeOnTrigger (Vector3 dir, Vector3 right) { //set the parameters needed to change the player's gravity without using the gravity power buttons searchingNewSurfaceBelow = false; removeParent (); circumnavigableSurfaceFound = false; searchingSurface = true; searchAround = true; changeColor (true); playerControllerManager.setGravityMultiplierValueFromExternalFunction (normalGravityMultiplier); playerControllerManager.setGravityPowerActiveState (true); playerCameraManager.sethorizontalCameraLimitActiveOnAirState (false); setPowerActivateState (true); playerCameraManager.calibrateAccelerometer (); if (canRotatePlayer ()) { rotateMeshPlayer (); } enableCameraShake (); gravityDirection = dir; rightAxis = right; if (canRotatePlayer ()) { checkRotateCharacter (-gravityDirection); } gravityPowerActive = true; } //stop the gravity power when the player is going to drive a vehicle public void stopGravityPower () { //disable the sphere collider in the gravity center gravityCenterCollider.enabled = false; //get the last time that the player was in the air playerControllerManager.lastTimeFalling = Time.time; accelerating = false; //set the force of the gravity in the player to its regular state playerControllerManager.setGravityMultiplierValueFromExternalFunction (normalGravityMultiplier); choosingDirection = false; circumnavigableSurfaceFound = false; removeParent (); setHoverState (false); turning = false; searchingSurface = false; searchAround = false; lifting = false; recalculatingSurface = false; timer = 0.75f; //stop to shake the camera and set its position to the regular state disableCameraShake (); playerCameraManager.changeCameraFov (false); playerControllerManager.setGravityPowerActiveState (false); playerCameraManager.sethorizontalCameraLimitActiveOnAirState (true); setPowerActivateState (false); //reset the player's rotation playerTransform.rotation = quaternionIdentity; gravityCenter.transform.localRotation = quaternionIdentity; //set to 0 the current velocity of the player mainRigidbody.linearVelocity = vector3Zero; gravityPowerActive = false; } //rotate the player, camera and mesh of the player to the new surface orientation //public public void checkRotateToSurface (Vector3 normal, float rotSpeed) { stopRotateToSurfaceCoroutine (); rotateCharacterState = StartCoroutine (rotateToSurface (normal, rotSpeed)); } public void stopRotateToSurfaceCoroutine () { //get the coroutine, stop it and play it again if (rotateCharacterState != null) { StopCoroutine (rotateCharacterState); } } public IEnumerator rotateToSurface (Vector3 normal, float rotSpeed) { updateCurrentRotatingNormal (normal); externalGravityCenter.SetParent (null); if (ignoreUseGravityCenterForRotationActive) { if (playerControllerManager.isPlayerOnGround ()) { externalGravityCenter.position = playerTransform.position + 1.1f * playerTransform.up; } else { externalGravityCenter.position = gravityCenter.position; } } else { externalGravityCenter.position = gravityCenter.position; } ignoreUseGravityCenterForRotationActive = false; externalGravityCenter.rotation = playerTransform.rotation; setExternalGravityCenterAsParent (); setRotatingToSurfaceState (true); Quaternion currentPlayerRotation = externalGravityCenter.rotation; Vector3 currentPlayerForward = Vector3.Cross (externalGravityCenter.right, normal); if (currentPlayerForward == Vector3.zero) { externalGravityCenter.eulerAngles += externalGravityCenter.up * 2; currentPlayerRotation = externalGravityCenter.rotation; currentPlayerForward = Vector3.Cross (externalGravityCenter.right, normal); } Quaternion playerTargetRotation = Quaternion.LookRotation (currentPlayerForward, normal); Quaternion currentGravityCenterRotation = gravityCenter.localRotation; Quaternion gravityCenterTargetRotation = quaternionIdentity; bool resetCameraTransformRotationResult = false; if (deactivatingZeroGravityModeActive) { float playerCameraAngle = Vector3.Angle (playerTransform.up, playerCameraTransform.up); if (Mathf.Abs (playerCameraAngle) > 0.0000001f) { resetCameraTransformRotationResult = true; } deactivatingZeroGravityModeActive = false; } bool targetReached = false; float currentTimer = 0; float normalAngle = 0; float rotateTimer = 0; while (!targetReached) { rotateTimer += Time.deltaTime * rotSpeed; currentTimer += Time.deltaTime; externalGravityCenter.rotation = Quaternion.Slerp (currentPlayerRotation, playerTargetRotation, rotateTimer); gravityCenter.transform.localRotation = Quaternion.Slerp (currentGravityCenterRotation, gravityCenterTargetRotation, rotateTimer); if (resetCameraTransformRotationResult) { playerCameraTransform.localRotation = Quaternion.Slerp (playerCameraTransform.localRotation, quaternionIdentity, rotateTimer); } normalAngle = Vector3.Angle (playerTransform.up, normal); if (normalAngle < 0.001f || currentTimer > 3) { targetReached = true; } yield return null; } //for (float t = 0; t < 1;) { // t += Time.deltaTime * rotSpeed; // externalGravityCenter.rotation = Quaternion.Slerp (currentPlayerRotation, playerTargetRotation, t); // gravityCenter.transform.localRotation = Quaternion.Slerp (currentGravityCenterRotation, gravityCenterTargetRotation, t); // yield return null; //} setCorrectParent (); externalGravityCenter.SetParent (playerTransform); currentNormal = normal; playerControllerManager.setGravityMultiplierValueFromExternalFunction (normalGravityMultiplier); playerControllerManager.setCurrentNormalCharacter (normal); if (currentNormal == regularGravity) { gravityPowerActive = false; } setRotatingToSurfaceState (false); //adjust gravity rotation for locked camera playerCameraManager.setLockedMainCameraTransformRotation (normal); if (zeroGravityModeOn || freeFloatingModeOn) { disableCameraShake (); } if (preservingVelocity) { preservingVelocity = false; yield return new WaitForSeconds (0.02f); playerControllerManager.addExternalForce (extraMultiplierPreserveVelocity * previousRigidbodyVelocity); } checkOnGroundOrAirState (); } public override bool isPlayerSearchingGravitySurface () { return powerActivated; } public bool isCharacterRotatingToSurface () { return rotating; } void setRotatingToSurfaceState (bool state) { rotating = state; playerControllerManager.setCharacterRotatingToSurfaceState (state); playerCameraManager.setCharacterRotatingToSurfaceState (state); } public void checkRotateToSurfaceWithoutParent (Vector3 normal, float rotSpeed) { stopRotateToSurfaceWithOutParentCoroutine (); rotateCharacterState = StartCoroutine (rotateToSurfaceWithOutParent (normal, rotSpeed)); } public void stopRotateToSurfaceWithOutParentCoroutine () { //get the coroutine, stop it and play it again if (rotateCharacterState != null) { StopCoroutine (rotateCharacterState); } } public IEnumerator rotateToSurfaceWithOutParent (Vector3 normal, float rotSpeed) { updateCurrentRotatingNormal (normal); setRotatingToSurfaceState (true); Quaternion currentPlayerRotation = playerTransform.rotation; Vector3 currentPlayerForward = Vector3.Cross (playerTransform.right, normal); Quaternion playerTargetRotation = Quaternion.LookRotation (currentPlayerForward, normal); Quaternion currentCameraRotation = playerCameraTransform.rotation; Vector3 currentCameraForward = Vector3.Cross (playerCameraTransform.right, normal); Quaternion cameraTargetRotation = Quaternion.LookRotation (currentCameraForward, normal); Quaternion currentGravityCenterRotation = gravityCenter.localRotation; Quaternion gravityCenterTargetRotation = quaternionIdentity; for (float t = 0; t < 1;) { t += Time.deltaTime * rotSpeed; playerTransform.rotation = Quaternion.Slerp (currentPlayerRotation, playerTargetRotation, t); playerCameraTransform.rotation = Quaternion.Slerp (currentCameraRotation, cameraTargetRotation, t); gravityCenter.transform.localRotation = Quaternion.Slerp (currentGravityCenterRotation, gravityCenterTargetRotation, t); yield return null; } currentNormal = normal; playerControllerManager.setGravityMultiplierValueFromExternalFunction (normalGravityMultiplier); playerControllerManager.setCurrentNormalCharacter (normal); if (currentNormal == regularGravity) { gravityPowerActive = false; } setRotatingToSurfaceState (false); //adjust gravity rotation for locked camera playerCameraManager.setLockedMainCameraTransformRotation (normal); if (zeroGravityModeOn || freeFloatingModeOn) { disableCameraShake (); } if (preservingVelocity) { preservingVelocity = false; mainRigidbody.linearVelocity = 2 * previousRigidbodyVelocity; } } public void setNormal (Vector3 normal) { Vector3 myForwardPlayer = Vector3.Cross (playerTransform.right, normal); Vector3 myForwardCamera = Vector3.Cross (playerCameraTransform.right, normal); Quaternion dstRotPlayer = Quaternion.LookRotation (myForwardPlayer, normal); Quaternion dstRotCamera = Quaternion.LookRotation (myForwardCamera, normal); playerTransform.rotation = dstRotPlayer; playerCameraTransform.rotation = dstRotCamera; currentNormal = normal; playerControllerManager.setCurrentNormalCharacter (normal); if (currentNormal != regularGravity) { gravityPowerActive = true; changeColor (true); } else { changeColor (false); } updateCurrentRotatingNormal (currentNormal); currentSetGravityManager = null; } public override Vector3 getCurrentNormal () { return currentNormal; } public void setCurrentNormal (Vector3 newValue) { currentNormal = newValue; } public override bool isUsingRegularGravity () { return currentNormal == regularGravity; } public Vector3 getRegularGravity () { return regularGravity; } public void updateCurrentRotatingNormal (Vector3 newNormal) { currentRotatingNormal = newNormal; } public Vector3 getCurrentRotatingNormal () { return currentRotatingNormal; } //rotate the mesh of the character in the direction of the camera when he selects a gravity direction in the air // and to the quaternion identity when he is on ground public void checkRotateCharacter (Vector3 normal) { float angle = Vector3.Angle (gravityCenter.up, playerTransform.up); if (Mathf.Abs (angle) > 0 || currentNormal == regularGravity) { //get the coroutine, stop it and play it again if (rotateToSurfaceState != null) { StopCoroutine (rotateToSurfaceState); } rotateToSurfaceState = StartCoroutine (rotateCharacter (normal)); } } public IEnumerator rotateCharacter (Vector3 normal) { Quaternion orgRotCenter = gravityCenter.transform.localRotation; Quaternion dstRotCenter = new Quaternion (0, 0, 0, 1); //check that the normal is different from zero, to rotate the player's mesh in the direction of the new gravity when he use the gravity power button //and select the camera direction to search a new surface //else, the player's mesh is rotated to its regular state if (normal != vector3Zero) { orgRotCenter = gravityCenter.transform.rotation; Vector3 myForward = Vector3.Cross (gravityCenter.transform.right, normal); dstRotCenter = Quaternion.LookRotation (myForward, normal); } for (float t = 0; t < 1;) { t += Time.deltaTime * 3; if (normal == vector3Zero) { gravityCenter.transform.localRotation = Quaternion.Slerp (orgRotCenter, dstRotCenter, t); } else { gravityCenter.transform.rotation = Quaternion.Slerp (orgRotCenter, dstRotCenter, t); } yield return null; } } public void changeGravityDirectionDirectlyInvertedValue (Vector3 gravityDirection, bool preserveVelocity) { changeGravityDirectionDirectly (-gravityDirection, preserveVelocity); } public void changeGravityDirectionDirectly (Vector3 gravityDirection, bool preserveVelocity) { if (!rotating) { //disable the search of the surface and rotate the player to that surface playerControllerManager.setGravityPowerActiveState (false); playerCameraManager.sethorizontalCameraLimitActiveOnAirState (true); setPowerActivateState (false); searchingNewSurfaceBelow = false; searchingSurface = false; searchAround = false; if (preserveVelocity) { previousRigidbodyVelocity = mainRigidbody.linearVelocity; preservingVelocity = true; extraMultiplierPreserveVelocity = 2; } mainRigidbody.linearVelocity = vector3Zero; //disable the collider in the gravity center and enable the capsule collider in the player gravityCenterCollider.enabled = false; playerCollider.isTrigger = false; //set the camera in its regular position playerCameraManager.changeCameraFov (false); //if the new normal is different from the previous normal in the gravity power, then rotate the player if (gravityDirection != currentNormal) { checkRotateToSurface (gravityDirection, rotateToSurfaceSpeed); } //if the player back to the regular gravity value, change its color to the regular state if (gravityDirection == regularGravity) { changeColor (false); } else { changeColor (true); } } } public void setCurrentSetGravityManager (setGravity currentSetGravity) { currentSetGravityManager = currentSetGravity; } public void setCurrentGravityCenterPoint (Transform newTransform) { currentCenterPoint = newTransform; currentCenterPointAssigned = currentCenterPoint != null; } public setGravity getCurrentSetGravityManager () { return currentSetGravityManager; } public void changeColor (bool state) { if (!changeModelColor) { return; } if (colorCoroutine != null) { StopCoroutine (colorCoroutine); } colorCoroutine = StartCoroutine (changeColorCoroutine (state)); } //change the mesh color of the character according to the gravity power public IEnumerator changeColorCoroutine (bool value) { if (playerRenderer != null) { if (value) { powerColor = originalPowerColor; } else { powerColor = Color.white; } int propertyNameID = Shader.PropertyToID ("_Color"); for (float t = 0; t < 1;) { t += Time.deltaTime; for (int i = 0; i < materialToChange.Count; i++) { if (playerRenderer.materials.Length >= materialToChange.Count) { if (materialToChange [i] == true && playerRenderer.materials [i].HasProperty (propertyNameID)) { playerRenderer.materials [i].color = Color.Lerp (playerRenderer.materials [i].color, powerColor, t); } } } yield return null; } } } public void setMeshCharacter (SkinnedMeshRenderer currentMeshCharacter) { if (currentMeshCharacter != null) { playerRenderer = currentMeshCharacter.GetComponent (); } updateComponent (); } //change the object which the camera follows and disable or enabled the powers according to the player state public void death (bool state) { dead = state; if (state) { deactivateGravityPower (); turning = false; setHoverState (false); checkRotateCharacter (vector3Zero); } } public void setGravityArrow (GameObject obj) { arrow = obj; } public void setGravityArrowState (bool state) { if (arrow != null) { if (arrow.activeSelf != state) { arrow.SetActive (state); } gravityArrowCurrentlyActive = state; } } public void setFirstPersonView (bool state) { firstPersonView = state; } public override Transform getGravityCenter () { return gravityCenter; } public bool isCurcumnavigating () { return circumnavigableSurfaceFound; } public override bool isSearchingSurface () { return searchingSurface; } public bool isGravityPowerActive () { return gravityPowerActive; } public void startOverride () { overrideTurretControlState (true); } public void stopOverride () { overrideTurretControlState (false); } public void overrideTurretControlState (bool state) { usedByAI = !state; } public bool isZeroGravityModeOn () { return zeroGravityModeOn; } public void toggleZeroGravityModeOnState () { setZeroGravityModeOnState (!zeroGravityModeOn); } bool deactivatingZeroGravityModeActive; public void setZeroGravityModeOnState (bool state) { if (freeFloatingModeOn) { setfreeFloatingModeOnState (false); } zeroGravityModeOn = state; disableCameraShake (); playerControllerManager.setZeroGravityModeOnState (zeroGravityModeOn); playerCameraManager.setZeroGravityModeOnState (zeroGravityModeOn); if (!zeroGravityModeOn) { if (currentNormal != regularGravity) { deactivatingZeroGravityModeActive = true; deactivateGravityPower (); } } checkEventsOnZeroGravityModeStateChange (zeroGravityModeOn); } public void setZeroGravityModeOnStateWithOutRotation (bool state) { if (freeFloatingModeOn) { setfreeFloatingModeOnState (false); } zeroGravityModeOn = state; disableCameraShake (); playerControllerManager.setZeroGravityModeOnState (zeroGravityModeOn); playerCameraManager.setZeroGravityModeOnState (zeroGravityModeOn); checkEventsOnZeroGravityModeStateChange (zeroGravityModeOn); } public void disableFreeFloatingModeOnIfActive () { if (freeFloatingModeOn) { setfreeFloatingModeOnState (false); } } public void setfreeFloatingModeOnState (bool state) { if (zeroGravityModeOn) { return; } if (!canActivateFreeFloatingMode) { return; } freeFloatingModeOn = state; disableCameraShake (); checkEventsOnFreeFloatingModeStateChange (freeFloatingModeOn); playerControllerManager.setfreeFloatingModeOnState (freeFloatingModeOn); playerCameraManager.setfreeFloatingModeOnState (freeFloatingModeOn); stopSetfreeFloatingModeOnStateWithDelayCoroutine (); } public void checkEventsOnFreeFloatingModeStateChange (bool state) { if (useEventsOnFreeFloatingModeStateChange) { if (state) { evenOnFreeFloatingModeStateEnabled.Invoke (); } else { eventOnFreeFloatingModeStateDisabled.Invoke (); } } } public void checkEventsOnZeroGravityModeStateChange (bool state) { if (useEventsOnZeroGravityModeStateChange) { if (state) { evenOnZeroGravityModeStateEnabled.Invoke (); } else { eventOnZeroGravityModeStateDisabled.Invoke (); } } } public void checkEventsOnUseGravityPowerStateChange (bool state) { if (useEventsOnUseGravityPowerStateChange) { if (state) { eventsOnUseGravityPowerStateEnabled.Invoke (); } else { eventsOnUseGravityPowerStateDisabled.Invoke (); } } } public void setPowerActivateState (bool state) { powerActivated = state; checkEventsOnUseGravityPowerStateChange (state); } public void changeFreeFloatingModeOnState () { setfreeFloatingModeOnState (!freeFloatingModeOn); } public void setfreeFloatingModeOnStateWithDelay (float delayAmount, bool state) { stopSetfreeFloatingModeOnStateWithDelayCoroutine (); freeFloatingModeCoroutine = StartCoroutine (setfreeFloatingModeOnStateWithDelayCoroutine (delayAmount, state)); } public void stopSetfreeFloatingModeOnStateWithDelayCoroutine () { if (freeFloatingModeCoroutine != null) { StopCoroutine (freeFloatingModeCoroutine); } } public IEnumerator setfreeFloatingModeOnStateWithDelayCoroutine (float delayAmount, bool state) { yield return new WaitForSeconds (delayAmount); setfreeFloatingModeOnState (state); } public void setCanActivateFreeFloatingModeState (bool state) { canActivateFreeFloatingMode = state; } public void rotateCharacterInZeroGravityMode (Vector3 normal, float rotSpeed) { //get the coroutine, stop it and play it again if (zeroGravityModeRotateCharacterCoroutine != null) { StopCoroutine (zeroGravityModeRotateCharacterCoroutine); } zeroGravityModeRotateCharacterCoroutine = StartCoroutine (rotateCharacterInZeroGravityModeCoroutine (normal, rotSpeed)); } public IEnumerator rotateCharacterInZeroGravityModeCoroutine (Vector3 normal, float rotSpeed) { externalGravityCenter.SetParent (null); externalGravityCenter.position = playerTransform.position + playerTransform.up; externalGravityCenter.rotation = playerCameraTransform.rotation; setExternalGravityCenterAsParent (); setRotatingToSurfaceState (true); Quaternion currentPlayerRotation = playerCameraTransform.rotation; Vector3 currentPlayerForward = Vector3.Cross (playerCameraTransform.right, normal); Quaternion playerTargetRotation = Quaternion.LookRotation (currentPlayerForward, normal); Quaternion currentGravityCenterRotation = gravityCenter.localRotation; Quaternion gravityCenterTargetRotation = quaternionIdentity; for (float t = 0; t < 1;) { t += Time.deltaTime * rotSpeed; externalGravityCenter.rotation = Quaternion.Lerp (currentPlayerRotation, playerTargetRotation, t); gravityCenter.transform.localRotation = Quaternion.Lerp (currentGravityCenterRotation, gravityCenterTargetRotation, t); yield return null; } setCorrectParent (); externalGravityCenter.SetParent (playerTransform); setRotatingToSurfaceState (false); } public void teleportPlayer (Vector3 teleportPosition, float teleportSpeed, Vector3 normal, float rotSpeed) { stopTeleporting (); teleportCoroutine = StartCoroutine (teleportPlayerCoroutine (teleportPosition, teleportSpeed, normal, rotSpeed)); } public void stopTeleporting () { if (teleportCoroutine != null) { StopCoroutine (teleportCoroutine); } setPlayerControlState (true); } public void setPlayerControlState (bool state) { playerControllerManager.changeScriptState (state); playerControllerManager.setGravityForcePuase (!state); playerControllerManager.setRigidbodyVelocityToZero (); playerControllerManager.setPhysicMaterialAssigmentPausedState (!state); if (!state) { playerControllerManager.setZeroFrictionMaterial (); if (!playerControllerManager.isPauseCheckOnGroundStateZGActive ()) { playerControllerManager.setCheckOnGrundStatePausedFFOrZGState (false); } } } IEnumerator teleportPlayerCoroutine (Vector3 targetPosition, float currentTeleportSpeed, Vector3 normal, float rotSpeed) { teleportInProcess = true; externalGravityCenter.SetParent (null); externalGravityCenter.position = playerTransform.position + playerTransform.up; externalGravityCenter.rotation = playerCameraTransform.rotation; setExternalGravityCenterAsParent (); setPlayerControlState (false); if (setOnGroundStateOnTeleportToSurfaceOnZeroGravity) { playerControllerManager.setIgnoreSetCheckOnGrundStatePausedFFOrZGStateActive (true); } setRotatingToSurfaceState (true); Quaternion currentPlayerRotation = playerCameraTransform.rotation; Vector3 currentPlayerForward = Vector3.Cross (playerCameraTransform.right, normal); Quaternion playerTargetRotation = Quaternion.LookRotation (currentPlayerForward, normal); float dist = GKC_Utils.distance (externalGravityCenter.position, targetPosition); float duration = dist / currentTeleportSpeed; float translateTimer = 0; float rotateTimer = 0; float teleportTimer = 0; float normalAngle = 0; Vector3 targetPositionDirection = targetPosition - externalGravityCenter.position; targetPositionDirection = targetPositionDirection / targetPositionDirection.magnitude; bool targetReached = false; while (!targetReached) { translateTimer += Time.deltaTime / duration; externalGravityCenter.position = Vector3.Lerp (externalGravityCenter.position, targetPosition, translateTimer); rotateTimer += Time.deltaTime * rotSpeed; externalGravityCenter.rotation = Quaternion.Lerp (currentPlayerRotation, playerTargetRotation, rotateTimer); teleportTimer += Time.deltaTime; normalAngle = Vector3.Angle (playerTransform.up, normal); if ((GKC_Utils.distance (externalGravityCenter.position, targetPosition) < 0.2f && normalAngle < 1) || teleportTimer > (duration + 5)) { targetReached = true; } yield return null; } setPlayerControlState (true); setRotatingToSurfaceState (false); setCorrectParent (); externalGravityCenter.SetParent (playerTransform); teleportInProcess = false; if (setOnGroundStateOnTeleportToSurfaceOnZeroGravity) { playerControllerManager.setCheckOnGrundStatePausedFFOrZGState (false); } } public bool isTeleportInProcess () { return teleportInProcess; } public void setGravityPowerEnabledState (bool state) { gravityPowerEnabled = state; } public void setGravityPowerState (bool enablePower) { //activate the power of change gravity //one press=the player elevates above the surface if he was in the ground or stops him in the air if he was not in the ground //two press=make the player moves in straight direction of the camera, looking a new surface //three press=stops the player again in the air if (!dead && !playerControllerManager.isUsingDevice () && gravityPowerEnabled) { if (enablePower) { activateGravityPower (); } else { deactivateGravityPower (); } } } public void disableGravityPowerIfOnAir () { if (choosingDirection || searchingSurface) { deactivateGravityPower (); } } public void enableCameraShake () { if (cameraShakeCanBeUsed) { playerCameraManager.startShakeCamera (); cameraShakeActive = true; } } public void disableCameraShake () { if (cameraShakeCanBeUsed) { if (cameraShakeActive) { playerCameraManager.stopShakeCamera (); cameraShakeActive = false; } } } public void setCameraShakeCanBeUsedState (bool state) { cameraShakeCanBeUsed = state; if (!cameraShakeCanBeUsed) { playerCameraManager.stopShakeCamera (); } } public void setGravityPowerInputEnabledState (bool state) { gravityPowerInputEnabled = state; } //CALL INPUT FUNCTIONS public void inputSetGravityPowerState (bool enablePower) { if (gravityPowerInputEnabled) { setGravityPowerState (enablePower); } } public void inputChangeGravitySpeed (bool increaseSpeed) { if (!dead && !playerControllerManager.isUsingDevice () && gravityPowerEnabled) { if (increaseSpeed) { changeMovementVelocity (true); } else { changeMovementVelocity (false); } } } public void inputAdjustToSurfaceOnZeroGravity () { if (!dead && !playerControllerManager.isUsingDevice () && zeroGravityModeOn && !onGround && !rotating && canAdjustToForwardSurface) { if (playerControllerManager.isPlayerMovingOn2_5dWorld ()) { return; } if (Physics.Raycast (forwardSurfaceRayPosition.position, forwardSurfaceRayPosition.forward, out hit, maxDistanceToAdjust, layer)) { if (currentNormal != regularGravity) { teleportPlayer (hit.point + 0.6f * hit.normal, adjustToForwardSurfaceSpeed, hit.normal, resetRotationZeroGravitySpeed); } } } } public void setCustomDirectionOnResetZeroGravityRotationValue (Vector3 newValue) { customDirectionOnResetZeroGravityRotation = newValue; } public void setCustomDirectionOnResetZeroGravityRotationValue (Transform newTransform) { setCustomDirectionOnResetZeroGravityRotationValue (newTransform.up); } public void inputResetRotationOnZeroGravity () { if (!dead && !playerControllerManager.isUsingDevice () && zeroGravityModeOn && !onGround && !rotating && canResetRotationOnZeroGravityMode) { bool canResetRotationResult = false; Vector3 targetGravityDirection = regularGravity; if (useCustomDirectionOnResetZeroGravityRotation) { targetGravityDirection = customDirectionOnResetZeroGravityRotation; } if (currentNormal != targetGravityDirection) { canResetRotationResult = true; } if (canResetRotationResult) { rotateCharacterInZeroGravityMode (targetGravityDirection, resetRotationZeroGravitySpeed); } } } public void inputToggleReverseGravity () { if (!dead && !playerControllerManager.isUsingDevice () && gravityPowerEnabled) { ignoreUseGravityCenterForRotationActive = true; if (currentNormal != regularGravity) { deactivateGravityPower (); } else { changeGravityDirectionDirectlyInvertedValue (currentNormal, true); if (pauseSearchNewSurfaceOnHighFallSpeedOnReverseGravityInput) { searchNewSurfaceOnHighFallSpeedPaused = true; } } } } public void setCurrentZeroGravityRoom (zeroGravityRoomSystem gravityRoom) { currentZeroGravityRoom = gravityRoom; if (currentZeroGravityRoom != null) { playerInsideGravityRoom = true; } else { playerInsideGravityRoom = false; } } public bool isPlayerInsiderGravityRoom () { return playerInsideGravityRoom; } public zeroGravityRoomSystem getCurrentZeroGravityRoom () { return currentZeroGravityRoom; } public Transform getCurrentSurfaceBelowPlayer () { return currentSurfaceBelowPlayer; } public void addObjectToCurrentZeroGravityRoomSystem (GameObject objectToAdd) { if (currentZeroGravityRoom != null) { currentZeroGravityRoom.addObjectToRoom (objectToAdd); } } public void setCircumnavigateSurfaceState (bool state) { circumnavigateCurrentSurfaceActive = state; if (!circumnavigateCurrentSurfaceActive) { if (circumnavigableSurfaceFound || playerIsChildOfParentActive) { circumnavigableSurfaceFound = false; if (playerIsChildOfParentActive) { removeParent (); } } recalculatingSurface = false; } } public void setCheckSurfaceInFrontState (bool state) { checkSurfaceInFront = state; } public void setCheckSurfaceBelowLedgeState (bool state) { checkSurfaceBelowLedge = state; } public void setUsedByAIState (bool state) { usedByAI = state; } void updateComponent () { GKC_Utils.updateComponent (this); } }