1139 lines
42 KiB
C#
1139 lines
42 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
public class vehicleGravityControl : gravityObjectManager
|
|
{
|
|
[Header ("Main Settings")]
|
|
[Space]
|
|
|
|
public bool useGravity = true;
|
|
|
|
public float gravityForce = 9.8f;
|
|
|
|
public bool searchNewSurfaceOnHighFallSpeed = true;
|
|
public bool shakeCameraOnHighFallSpeed = true;
|
|
public float minSpeedToShakeCamera = 10;
|
|
|
|
public bool checkSurfaceBelowOnRegularState;
|
|
public float timeToSetNullParentOnAir = 0.5f;
|
|
float lastTimeParentFound;
|
|
|
|
public bool changeDriverGravityWhenGetsOff = true;
|
|
|
|
public bool setVehicleRegularGravityOnDriverGetOff;
|
|
|
|
[Space]
|
|
[Header ("Circumnavigation Settings")]
|
|
[Space]
|
|
|
|
public float circumnavigateRotationSpeed = 10;
|
|
public bool circumnavigateCurrentSurfaceActive;
|
|
public bool useLerpRotation;
|
|
|
|
public bool checkSurfaceBelowLedge;
|
|
public float surfaceBelowLedgeRaycastDistance = 3;
|
|
public float belowLedgeRotationSpeed = 10;
|
|
|
|
public float minAngleDifferenceToAdhereToSurface = 4;
|
|
|
|
[Space]
|
|
[Header ("Current Normal/Gravity Settings")]
|
|
[Space]
|
|
|
|
public Vector3 regularGravity = new Vector3 (0, 1, 0);
|
|
public Vector3 currentNormal = new Vector3 (0, 1, 0);
|
|
|
|
[Space]
|
|
[Header ("Gravity At Start Settings")]
|
|
[Space]
|
|
|
|
public bool startWithNewGravity;
|
|
public bool useVehicleRotation;
|
|
public bool adjustRotationToSurfaceFound;
|
|
public Vector3 newGravityToStart;
|
|
|
|
[Space]
|
|
[Header ("Others Settings")]
|
|
[Space]
|
|
|
|
public otherSettings settings;
|
|
|
|
[Space]
|
|
[Header ("Debug")]
|
|
[Space]
|
|
|
|
public bool gravityControlEnabled;
|
|
public bool OnGround;
|
|
public bool gravityPowerActive;
|
|
|
|
public bool powerActivated;
|
|
public bool recalculatingSurface;
|
|
public bool searchingSurface;
|
|
public bool searchingNewSurfaceBelow;
|
|
public bool searchAround;
|
|
public bool rotating;
|
|
|
|
public bool circumnavigableSurfaceFound;
|
|
|
|
public bool useCenterPointActive;
|
|
public Transform currentCenterPoint;
|
|
|
|
[Space]
|
|
[Header ("Gizmo Settings")]
|
|
[Space]
|
|
|
|
public bool showGizmo;
|
|
|
|
[Space]
|
|
[Header ("Components")]
|
|
[Space]
|
|
|
|
public Transform gravityAdherenceRaycastParent;
|
|
public Transform surfaceBelowRaycastTransform;
|
|
|
|
public vehicleController mainVehicleController;
|
|
public Collider gravityCenterCollider;
|
|
public Rigidbody mainRigidbody;
|
|
public vehicleCameraController vehicleCameraManager;
|
|
public vehicleHUDManager HUDManager;
|
|
public inputActionManager actionManager;
|
|
|
|
Vector3 previousNormalDetected;
|
|
|
|
Transform vehicleCamera;
|
|
|
|
|
|
bool conservateSpeed;
|
|
bool accelerating;
|
|
Vector3 forwardAxisCamera;
|
|
Vector3 rightAxisCamera;
|
|
Vector3 forwardAxisMovement;
|
|
Vector3 surfaceNormal;
|
|
Vector3 previousVelocity;
|
|
float normalGravityMultiplier;
|
|
float horizontalAxis;
|
|
float verticalAxis;
|
|
Transform pivot;
|
|
|
|
GameObject fatherDetected;
|
|
|
|
RaycastHit hit;
|
|
Coroutine rotateCharacterState;
|
|
|
|
Vector2 axisValues;
|
|
|
|
Coroutine rotateVehicleCoroutine;
|
|
|
|
bool gravityForcePaused;
|
|
|
|
bool onGroundChecked;
|
|
float currentCircumnagivateRotationSpeed;
|
|
|
|
bool surfaceFound;
|
|
RaycastHit currentSurfaceFound;
|
|
Vector3 currentPosition;
|
|
Vector3 rayPosition;
|
|
Vector3 rayDirection;
|
|
float gravityAdherenceRaycastParentAngleRotation;
|
|
|
|
bool checkDownSpeedActive = true;
|
|
|
|
GameObject currentObjectBelowVehicle;
|
|
GameObject previousSurfaceBelowVehicle;
|
|
|
|
Vector3 pos;
|
|
Vector3 dir;
|
|
|
|
Vector3 currentUp;
|
|
|
|
bool mainVehicleControllerLocated;
|
|
|
|
float originalGravityForce;
|
|
|
|
bool addPreviousVelocityMagnitude;
|
|
float previousVelocityMagnitude;
|
|
|
|
float lastTimeRotateVehicleToRaycastDirection;
|
|
|
|
|
|
void Start ()
|
|
{
|
|
//set the current normal in the vehicle controller
|
|
if (mainVehicleController == null) {
|
|
mainVehicleController = GetComponent<vehicleController> ();
|
|
}
|
|
|
|
mainVehicleControllerLocated = mainVehicleController != null;
|
|
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.setNormal (currentNormal);
|
|
}
|
|
|
|
if (startWithNewGravity) {
|
|
if (useVehicleRotation) {
|
|
currentUp = transform.up;
|
|
|
|
Vector3 normalDirection = -currentUp;
|
|
|
|
if (adjustRotationToSurfaceFound) {
|
|
if (Physics.Raycast (transform.position, -currentUp, out hit, Mathf.Infinity, settings.layer)) {
|
|
normalDirection = hit.normal;
|
|
}
|
|
}
|
|
|
|
if (currentUp != currentNormal) {
|
|
setCustomNormal (normalDirection);
|
|
}
|
|
} else {
|
|
setCustomNormal (newGravityToStart);
|
|
}
|
|
}
|
|
|
|
vehicleCamera = vehicleCameraManager.transform;
|
|
|
|
originalGravityForce = gravityForce;
|
|
}
|
|
|
|
void Update ()
|
|
{
|
|
currentPosition = transform.position;
|
|
|
|
//if the vehicle is searching a new surface
|
|
if (searchingSurface) {
|
|
//set the vehicle movement direction in the air (local X and Y axis)
|
|
forwardAxisCamera = pivot.TransformDirection (Vector3.up);
|
|
rightAxisCamera = pivot.TransformDirection (Vector3.right);
|
|
|
|
//new position and direction of a raycast to detect a surface
|
|
pos = Vector3.zero;
|
|
dir = Vector3.zero;
|
|
|
|
//if the player has activate the gravity control in the vehicle, then apply force in the camera direction and set the raycast position in the center of mass
|
|
if (!searchingNewSurfaceBelow) {
|
|
//this function apply force to the vehicle in the new direction and allows to move it in the air in the left, right, forward and backward direction using the direction
|
|
//of the movement as local Y axis
|
|
moveInTheAir ((gravityForce * (mainRigidbody.mass / settings.massDivider) * settings.speed) * forwardAxisMovement, settings.speed, mainRigidbody.mass / settings.massDivider, forwardAxisMovement);
|
|
|
|
pos = settings.centerOfMass.position;
|
|
|
|
dir = forwardAxisMovement;
|
|
}
|
|
//else, the player is falling in the air while the gravity control was enabled, so the ray direction is the negavite local Y axis or -currentNormal and the position is the
|
|
//vehicle itself
|
|
else {
|
|
pos = currentPosition;
|
|
dir = -currentNormal;
|
|
}
|
|
|
|
if (showGizmo) {
|
|
Debug.DrawRay (pos, settings.vehicleRadius * dir, Color.yellow);
|
|
}
|
|
|
|
//if the raycast found a new surface, then
|
|
if (Physics.Raycast (pos, dir, out hit, settings.vehicleRadius, settings.layer)) {
|
|
//check is not a trigger or a rigidbody
|
|
if (!hit.collider.isTrigger && hit.rigidbody == null) {
|
|
//a new valid surface has been detected, so stop the search of a new surface
|
|
|
|
searchingNewSurfaceBelow = false;
|
|
searchingSurface = false;
|
|
searchAround = false;
|
|
powerActivated = false;
|
|
|
|
//set to 0 the vehicle velocity
|
|
mainRigidbody.linearVelocity = Vector3.zero;
|
|
|
|
//disable the collider in the center of mass
|
|
gravityCenterCollider.enabled = false;
|
|
|
|
//if the surface can be circumnavigate
|
|
if (hit.collider.gameObject.CompareTag (settings.tagForCircumnavigate)) {
|
|
circumnavigableSurfaceFound = true;
|
|
}
|
|
|
|
//if the surface is moving
|
|
if (hit.collider.gameObject.CompareTag (settings.tagForMovingObjects)) {
|
|
addParent (hit.collider.gameObject);
|
|
}
|
|
|
|
//if the new normal is different from the current normal, which means that is other surface inclination, then
|
|
if (hit.normal != currentNormal) {
|
|
//rotate the vehicle according to that normal
|
|
if (rotateVehicleCoroutine != null) {
|
|
StopCoroutine (rotateVehicleCoroutine);
|
|
}
|
|
|
|
rotateVehicleCoroutine = StartCoroutine (rotateToSurface (hit.normal, 2));
|
|
}
|
|
|
|
//disable the gravity control in the vehicle controller
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.changeGravityControlUse (false);
|
|
}
|
|
|
|
vehicleCameraManager.usingBoost (false, "StopShake", true, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
//if the gravity control is enabled, and the vehicle falls in its negative loxal Y axis,
|
|
//then check if there is any surface below the vehicle which will become the new ground surface
|
|
//in case the vehicle reachs a certain velocity
|
|
if (!OnGround && !powerActivated) {
|
|
if (checkDownSpeedActive && shakeCameraOnHighFallSpeed && transform.InverseTransformDirection (mainRigidbody.linearVelocity).y < -minSpeedToShakeCamera) {
|
|
vehicleCameraManager.usingBoost (true, "Regular Gravity Control", true, true);
|
|
}
|
|
|
|
if (searchNewSurfaceOnHighFallSpeed && transform.InverseTransformDirection (mainRigidbody.linearVelocity).y < -settings.velocityToSearch && !searchingNewSurfaceBelow && !powerActivated) {
|
|
//check that the current normal is not the regular one
|
|
if (currentNormal != regularGravity) {
|
|
//enable the collider in the center of mass
|
|
gravityCenterCollider.enabled = true;
|
|
|
|
//searching a new surface
|
|
searchingNewSurfaceBelow = true;
|
|
searchingSurface = true;
|
|
|
|
//stop to recalculate the normal of the vehicle
|
|
recalculatingSurface = false;
|
|
circumnavigableSurfaceFound = false;
|
|
|
|
//enable the gravity control in the vehicle controller
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.changeGravityControlUse (true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//if the vehicle is above a circumnavigable object, then recalculate the current normal of the vehicle according to the surface normal under the vehicle
|
|
if (!searchingSurface && (circumnavigableSurfaceFound || fatherDetected != null) && recalculatingSurface) {
|
|
//set the distance of the ray, if the vehicle is not on the ground, the distance is higher
|
|
float distance = settings.rayDistance + 0.05f;
|
|
if (!OnGround) {
|
|
distance = 10;
|
|
}
|
|
|
|
surfaceFound = false;
|
|
|
|
//if the vehicle founds a surface below it, get its normal
|
|
if (Physics.Raycast (settings.centerOfMass.position, -currentNormal, out hit, distance, settings.layer)) {
|
|
currentSurfaceFound = hit;
|
|
surfaceFound = true;
|
|
currentCircumnagivateRotationSpeed = circumnavigateRotationSpeed;
|
|
}
|
|
|
|
currentUp = transform.up;
|
|
|
|
//Get the correct raycast orientation according to input, for example, it is no the same ray position and direction if the vehicle is moving forward or backward
|
|
if (checkSurfaceBelowLedge) {
|
|
rayPosition = currentPosition + 0.1f * currentUp;
|
|
|
|
gravityAdherenceRaycastParentAngleRotation = Vector3.SignedAngle (transform.forward, mainRigidbody.linearVelocity, currentUp);
|
|
|
|
gravityAdherenceRaycastParent.localRotation = Quaternion.Euler (new Vector3 (0, gravityAdherenceRaycastParentAngleRotation, 0));
|
|
}
|
|
|
|
if (checkSurfaceBelowLedge) {
|
|
rayDirection = -currentUp;
|
|
|
|
if (showGizmo) {
|
|
Debug.DrawRay (rayPosition, rayDirection, Color.white);
|
|
}
|
|
|
|
if (!Physics.Raycast (rayPosition, rayDirection, out hit, 1, settings.layer)) {
|
|
if (showGizmo) {
|
|
Debug.DrawRay (rayPosition, rayDirection, Color.green);
|
|
}
|
|
|
|
rayPosition = surfaceBelowRaycastTransform.position;
|
|
rayDirection = surfaceBelowRaycastTransform.forward;
|
|
|
|
if (Physics.Raycast (rayPosition, rayDirection, out hit, surfaceBelowLedgeRaycastDistance, settings.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 (surfaceFound) {
|
|
if (!currentSurfaceFound.collider.isTrigger && currentSurfaceFound.rigidbody == null) {
|
|
//the object detected can be circumnavigate, so get the normal direction
|
|
if (currentSurfaceFound.collider.gameObject.CompareTag (settings.tagForCircumnavigate)) {
|
|
|
|
if (useCenterPointActive) {
|
|
Vector3 heading = settings.centerOfMass.position - currentCenterPoint.transform.position;
|
|
|
|
surfaceNormal = heading / heading.magnitude;
|
|
|
|
} else {
|
|
surfaceNormal = currentSurfaceFound.normal;
|
|
}
|
|
}
|
|
|
|
//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 (settings.tagForMovingObjects)) {
|
|
if (useCenterPointActive) {
|
|
Vector3 heading = settings.centerOfMass.position - currentCenterPoint.transform.position;
|
|
|
|
surfaceNormal = heading / heading.magnitude;
|
|
|
|
} else {
|
|
surfaceNormal = currentSurfaceFound.normal;
|
|
}
|
|
|
|
if (fatherDetected == null) {
|
|
addParent (currentSurfaceFound.collider.gameObject);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (fatherDetected != null) {
|
|
removeParent ();
|
|
}
|
|
}
|
|
|
|
|
|
if (useLerpRotation) {
|
|
//set the current normal according to the hit.normal
|
|
currentNormal = Vector3.Lerp (currentNormal, surfaceNormal, currentCircumnagivateRotationSpeed * Time.deltaTime);
|
|
|
|
if (Vector3.Angle (previousNormalDetected, surfaceNormal) > minAngleDifferenceToAdhereToSurface) {
|
|
previousNormalDetected = surfaceNormal;
|
|
|
|
Vector3 myForward = Vector3.Cross (transform.right, currentNormal);
|
|
Quaternion dstRot = Quaternion.LookRotation (myForward, currentNormal);
|
|
transform.rotation = Quaternion.Lerp (transform.rotation, dstRot, currentCircumnagivateRotationSpeed * Time.deltaTime);
|
|
Vector3 myForwardCamera = Vector3.Cross (vehicleCamera.right, currentNormal);
|
|
Quaternion dstRotCamera = Quaternion.LookRotation (myForwardCamera, currentNormal);
|
|
vehicleCamera.rotation = Quaternion.Lerp (vehicleCamera.rotation, dstRotCamera, currentCircumnagivateRotationSpeed * Time.deltaTime);
|
|
}
|
|
} else {
|
|
//set the current normal according to the hit.normal
|
|
currentNormal = Vector3.Slerp (currentNormal, surfaceNormal, currentCircumnagivateRotationSpeed * Time.deltaTime);
|
|
|
|
if (Vector3.Angle (previousNormalDetected, currentNormal) > minAngleDifferenceToAdhereToSurface) {
|
|
previousNormalDetected = surfaceNormal;
|
|
|
|
Vector3 myForward = Vector3.Cross (transform.right, currentNormal);
|
|
Quaternion dstRot = Quaternion.LookRotation (myForward, currentNormal);
|
|
transform.rotation = Quaternion.Slerp (transform.rotation, dstRot, currentCircumnagivateRotationSpeed * Time.deltaTime);
|
|
}
|
|
|
|
Vector3 myForwardCamera = Vector3.Cross (vehicleCamera.right, currentNormal);
|
|
Quaternion dstRotCamera = Quaternion.LookRotation (myForwardCamera, currentNormal);
|
|
|
|
vehicleCamera.rotation = Quaternion.Slerp (vehicleCamera.rotation, dstRotCamera, currentCircumnagivateRotationSpeed * Time.deltaTime);
|
|
}
|
|
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.setNormal (currentNormal);
|
|
}
|
|
}
|
|
|
|
//if the vehicle is being rotated to a new surface, set its velocity to 0
|
|
if (rotating) {
|
|
mainRigidbody.linearVelocity = Vector3.zero;
|
|
}
|
|
|
|
if ((gravityPowerActive || circumnavigateCurrentSurfaceActive) && !powerActivated) {
|
|
if (currentObjectBelowVehicle != null) {
|
|
//check if the object detected can be circumnavigate
|
|
if (currentObjectBelowVehicle.CompareTag (settings.tagForCircumnavigate)) {
|
|
circumnavigableSurfaceFound = true;
|
|
} else {
|
|
circumnavigableSurfaceFound = false;
|
|
}
|
|
|
|
//check if the object is moving to parent the player inside it
|
|
if (currentObjectBelowVehicle.CompareTag (settings.tagForMovingObjects)) {
|
|
if (previousSurfaceBelowVehicle != currentObjectBelowVehicle) {
|
|
previousSurfaceBelowVehicle = currentObjectBelowVehicle;
|
|
|
|
addParent (currentObjectBelowVehicle);
|
|
}
|
|
} else if (fatherDetected != null && !currentObjectBelowVehicle.transform.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 || fatherDetected != null) {
|
|
recalculatingSurface = true;
|
|
}
|
|
//else disable this state
|
|
else {
|
|
recalculatingSurface = false;
|
|
}
|
|
} else {
|
|
if (previousSurfaceBelowVehicle != null) {
|
|
previousSurfaceBelowVehicle = null;
|
|
}
|
|
|
|
if (rotating) {
|
|
circumnavigableSurfaceFound = false;
|
|
}
|
|
}
|
|
} else {
|
|
if ((circumnavigableSurfaceFound || fatherDetected != null) && rotating) {
|
|
circumnavigableSurfaceFound = false;
|
|
}
|
|
|
|
if (checkSurfaceBelowOnRegularState && !gravityPowerActive && !HUDManager.isVehicletAsChildOfParent ()) {
|
|
if (currentObjectBelowVehicle != null) {
|
|
//check if the object is moving to parent the player inside it
|
|
if (currentObjectBelowVehicle.CompareTag (settings.tagForMovingObjects)) {
|
|
if (previousSurfaceBelowVehicle != currentObjectBelowVehicle) {
|
|
previousSurfaceBelowVehicle = currentObjectBelowVehicle;
|
|
|
|
addParent (currentObjectBelowVehicle);
|
|
|
|
lastTimeParentFound = Time.time;
|
|
}
|
|
} else if (fatherDetected != null && !currentObjectBelowVehicle.transform.IsChildOf (fatherDetected.transform)) {
|
|
removeParent ();
|
|
}
|
|
|
|
} else {
|
|
if (previousSurfaceBelowVehicle != null) {
|
|
previousSurfaceBelowVehicle = null;
|
|
}
|
|
|
|
if (Time.time > timeToSetNullParentOnAir + lastTimeParentFound) {
|
|
removeParent ();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FixedUpdate ()
|
|
{
|
|
// If the gravity control is not being used
|
|
if (!powerActivated && !gravityForcePaused) {
|
|
// Apply force to the vehicle in the negative local Y axis, so the vehicle has a regular gravity
|
|
if (useGravity) {
|
|
mainRigidbody.AddForce ((-gravityForce * mainRigidbody.mass * settings.gravityMultiplier) * currentNormal);
|
|
}
|
|
|
|
// If the vehicle is search a new surface, and previously the gravity control was enabled, then
|
|
if (searchingNewSurfaceBelow) {
|
|
// Apply force in the negative local Y axis of the vehicle, and allow to move it left, right, backward and forward
|
|
moveInTheAir (mainRigidbody.linearVelocity, 1, 1, -currentNormal);
|
|
}
|
|
|
|
// Check if the vehicle is on the ground
|
|
OnGround = false;
|
|
|
|
// Use a raycast to it, with the center of the mass as position and the negative local Y axis as direction, using the ray distance configured in the inspector
|
|
if (Physics.Raycast (settings.centerOfMass.position, -currentNormal, out hit, settings.rayDistance, settings.layer)) {
|
|
if (showGizmo) {
|
|
Debug.DrawLine (settings.centerOfMass.position, hit.point, Color.cyan);
|
|
}
|
|
|
|
// If the hit is not a trigger
|
|
if (!hit.collider.isTrigger) {
|
|
// The vehicle is on the ground
|
|
OnGround = true;
|
|
|
|
currentObjectBelowVehicle = hit.collider.gameObject;
|
|
}
|
|
} else {
|
|
// Else the vehicle is in the air
|
|
OnGround = false;
|
|
|
|
currentObjectBelowVehicle = null;
|
|
}
|
|
} else {
|
|
// The vehicle is searching a new surface, so it is in the air
|
|
OnGround = false;
|
|
}
|
|
|
|
if (OnGround) {
|
|
if (!onGroundChecked) {
|
|
|
|
vehicleCameraManager.usingBoost (false, "stopShake", true, true);
|
|
|
|
onGroundChecked = true;
|
|
|
|
// If the gravity control is enabled, and the surface below the vehicle can be circumnavigate or is a moving object, allow to recalculate the normal
|
|
if ((circumnavigableSurfaceFound || fatherDetected != null) && gravityPowerActive) {
|
|
recalculatingSurface = true;
|
|
} else {
|
|
recalculatingSurface = false;
|
|
}
|
|
}
|
|
} else {
|
|
if (onGroundChecked) {
|
|
onGroundChecked = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void moveInTheAir (Vector3 newVel, float speedMultiplier, float massMultiplier, Vector3 movementDirection)
|
|
{
|
|
//get the new velocity to apply to the vehicle
|
|
Vector3 newVelocity = newVel;
|
|
|
|
//get the current values of the horizontal and vertical axis, from the input manager
|
|
if (actionManager != null) {
|
|
axisValues = actionManager.getPlayerMovementAxis ();
|
|
} else {
|
|
axisValues = Vector3.zero;
|
|
}
|
|
|
|
horizontalAxis = axisValues.x;
|
|
verticalAxis = axisValues.y;
|
|
|
|
//allow to move the vehicle in its local X and Y axis while he falls or move in the air using the gravity control
|
|
Vector3 newmoveInput = verticalAxis * forwardAxisCamera + horizontalAxis * rightAxisCamera;
|
|
|
|
if (newmoveInput.magnitude > 1) {
|
|
newmoveInput.Normalize ();
|
|
}
|
|
|
|
//if the input axis are being used, set that movement to the vehicle
|
|
if (newmoveInput.magnitude > 0) {
|
|
newVelocity += (settings.speed * (mainRigidbody.mass / settings.massDivider) * speedMultiplier) * newmoveInput;
|
|
}
|
|
|
|
//if the player is accelerating in the air, add more velocity to the vehicle
|
|
if (accelerating) {
|
|
newVelocity += (settings.accelerateSpeed * massMultiplier) * forwardAxisMovement;
|
|
}
|
|
|
|
//if the current local Y velocity is lower than the limit, clamp the velocity
|
|
if (Mathf.Abs (transform.InverseTransformDirection (newVelocity).y) > 40) {
|
|
newVelocity -= Mathf.Abs (transform.InverseTransformDirection (newVelocity).y) * movementDirection;
|
|
newVelocity += 40 * movementDirection;
|
|
}
|
|
|
|
//set the new velocity to the vehicle
|
|
mainRigidbody.linearVelocity = Vector3.Lerp (mainRigidbody.linearVelocity, newVelocity, Time.deltaTime * 2);
|
|
}
|
|
|
|
//when the colliders of the vehicle hits another surface
|
|
public void setCollisionDetected (Collision currentCollision)
|
|
{
|
|
//if the vehicle was searching a new surface using the gravity control, then
|
|
if (searchingSurface && searchAround) {
|
|
//check the type of collider
|
|
if (!currentCollision.gameObject.CompareTag ("Player") && currentCollision.rigidbody == null && !currentCollision.collider.isTrigger) {
|
|
//using the collision contact, get the direction of that new surface, so the vehicle change its movement to the position of that surface
|
|
//like this the searching of a new surface is more accurate, since a raycast and collisions are used to detect the new surface
|
|
Vector3 hitDirection = currentCollision.contacts [0].point - settings.centerOfMass.position;
|
|
|
|
//set the current direction of the vehicle
|
|
hitDirection = hitDirection / hitDirection.magnitude;
|
|
forwardAxisMovement = hitDirection;
|
|
|
|
//stop to search collisions around the vehicle
|
|
searchAround = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//set and remove the parent of the vehicle according to the type of surface
|
|
void addParent (GameObject obj)
|
|
{
|
|
fatherDetected = obj;
|
|
|
|
parentAssignedSystem currentParentAssignedSystem = obj.GetComponent<parentAssignedSystem> ();
|
|
|
|
if (currentParentAssignedSystem != null) {
|
|
fatherDetected = currentParentAssignedSystem.getAssignedParent ();
|
|
}
|
|
|
|
setFatherDetectedAsParent ();
|
|
}
|
|
|
|
void removeParent ()
|
|
{
|
|
setNullParent ();
|
|
|
|
fatherDetected = null;
|
|
}
|
|
|
|
public void setFatherDetectedAsParent ()
|
|
{
|
|
transform.SetParent (fatherDetected.transform);
|
|
|
|
vehicleCamera.SetParent (fatherDetected.transform);
|
|
}
|
|
|
|
public void setNullParent ()
|
|
{
|
|
transform.SetParent (null);
|
|
vehicleCamera.SetParent (null);
|
|
}
|
|
|
|
//activate the collider in the center of mass of the vehicle to dectect collisions with a new surface when the gravity control is enabled
|
|
IEnumerator activateCollider ()
|
|
{
|
|
//wait to avoid enable the collider when the vehicle stills in the ground
|
|
yield return new WaitForSeconds (0.2f);
|
|
|
|
//if the vehicle is searching surface, then active the collider
|
|
if (searchingSurface || searchingNewSurfaceBelow || searchAround) {
|
|
gravityCenterCollider.enabled = true;
|
|
}
|
|
}
|
|
|
|
//enable the gravity control in the direction of the camera
|
|
public void activateGravityPower (Vector3 dir, Vector3 right)
|
|
{
|
|
StartCoroutine (activateCollider ());
|
|
|
|
searchingNewSurfaceBelow = false;
|
|
|
|
removeParent ();
|
|
|
|
circumnavigableSurfaceFound = false;
|
|
|
|
searchingSurface = true;
|
|
|
|
searchAround = true;
|
|
|
|
gravityPowerActive = true;
|
|
|
|
forwardAxisMovement = dir;
|
|
|
|
rightAxisCamera = right;
|
|
|
|
powerActivated = true;
|
|
|
|
//enable the gravity control in the vehicle controller
|
|
vehicleCameraManager.usingBoost (true, "Regular Gravity Control", true, true);
|
|
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.changeGravityControlUse (true);
|
|
}
|
|
}
|
|
|
|
//disaable the gravity control, rotatin the vehicle to the regular gravity
|
|
public void deactivateGravityPower ()
|
|
{
|
|
//check that the vehicle was searching a new surface, or that the gravity is different than vector3.up
|
|
if (searchingSurface || searchingNewSurfaceBelow || searchAround || currentNormal != regularGravity) {
|
|
conservateSpeed = true;
|
|
|
|
gravityCenterCollider.enabled = false;
|
|
|
|
accelerating = false;
|
|
|
|
circumnavigableSurfaceFound = false;
|
|
|
|
removeParent ();
|
|
|
|
searchingNewSurfaceBelow = false;
|
|
|
|
searchingSurface = false;
|
|
|
|
searchAround = false;
|
|
|
|
recalculatingSurface = false;
|
|
|
|
powerActivated = false;
|
|
|
|
//if the current normal before reset the gravity to the regular one is different from vectore.up, then rotate the vehicle back to the regular state
|
|
if (currentNormal != regularGravity) {
|
|
if (rotateVehicleCoroutine != null) {
|
|
StopCoroutine (rotateVehicleCoroutine);
|
|
}
|
|
|
|
rotateVehicleCoroutine = StartCoroutine (rotateToSurface (regularGravity, 2));
|
|
}
|
|
|
|
gravityPowerActive = false;
|
|
|
|
//set the normal in the vehicle controller
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.setNormal (regularGravity);
|
|
}
|
|
|
|
//disable the gravity control in the vehicle controller
|
|
vehicleCameraManager.usingBoost (false, "stopShake", true, true);
|
|
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.changeGravityControlUse (false);
|
|
}
|
|
}
|
|
}
|
|
|
|
//the player is getting on or off from the vehicle, so enable or disable the graivty control component
|
|
public void changeGravityControlState (bool state)
|
|
{
|
|
gravityControlEnabled = state;
|
|
|
|
//if the vehicle is not being driving, and it wasn't in the ground, deactivate the gravity control
|
|
if (!gravityControlEnabled && !OnGround) {
|
|
deactivateGravityPower ();
|
|
|
|
accelerating = false;
|
|
}
|
|
}
|
|
|
|
//rotate the vehicle and its camera to the new found surface, using the normal of that surface
|
|
public IEnumerator rotateToSurface (Vector3 normal, int rotSpeed)
|
|
{
|
|
previousVelocity = mainRigidbody.linearVelocity;
|
|
|
|
//the vehicle is being rotate, so set its velocity to 0
|
|
rotating = true;
|
|
|
|
currentNormal = normal;
|
|
|
|
//set the new normal in the vehicle controller
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.setNormal (currentNormal);
|
|
}
|
|
|
|
//get the current rotation of the vehicle and the camera
|
|
Quaternion currentVehicleRotation = transform.rotation;
|
|
Quaternion currentVehicleCameraRotation = vehicleCamera.rotation;
|
|
|
|
Vector3 currentVehicleForward = Vector3.Cross (transform.right, normal);
|
|
Quaternion targetVehicleRotation = Quaternion.LookRotation (currentVehicleForward, normal);
|
|
Vector3 currentVehicleCameraForward = Vector3.Cross (vehicleCamera.right, normal);
|
|
Quaternion targetVehicleCameraRotation = Quaternion.LookRotation (currentVehicleCameraForward, normal);
|
|
|
|
//rotate from their rotation to thew new surface normal direction
|
|
for (float t = 0; t < 1;) {
|
|
t += Time.deltaTime * rotSpeed;
|
|
|
|
vehicleCamera.rotation = Quaternion.Slerp (currentVehicleCameraRotation, targetVehicleCameraRotation, t);
|
|
transform.rotation = Quaternion.Slerp (currentVehicleRotation, targetVehicleRotation, t);
|
|
|
|
yield return null;
|
|
}
|
|
|
|
rotating = false;
|
|
|
|
//store the current vehicle velocity to set it again once the rotation is finished, is only applied when the gravity control is disabled
|
|
if (conservateSpeed) {
|
|
mainRigidbody.linearVelocity = previousVelocity;
|
|
}
|
|
|
|
conservateSpeed = false;
|
|
}
|
|
|
|
public void setUseCenterPointActiveState (bool state, Transform newCenterPoint)
|
|
{
|
|
useCenterPointActive = state;
|
|
|
|
currentCenterPoint = newCenterPoint;
|
|
}
|
|
|
|
public void rotateVehicleToRaycastDirection (Vector3 raycastDirection)
|
|
{
|
|
if (rotating) {
|
|
return;
|
|
}
|
|
|
|
print ("ROTATE");
|
|
|
|
if (lastTimeRotateVehicleToRaycastDirection != 0) {
|
|
if (Time.time < lastTimeRotateVehicleToRaycastDirection + 0.5f) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
lastTimeRotateVehicleToRaycastDirection = Time.time;
|
|
|
|
pos = settings.centerOfMass.position;
|
|
dir = raycastDirection;
|
|
|
|
//if the raycast found a new surface, then
|
|
if (Physics.Raycast (pos, dir, out hit, Mathf.Infinity, settings.layer)) {
|
|
//check is not a trigger or a rigidbody
|
|
if (!hit.collider.isTrigger && hit.rigidbody == null) {
|
|
//a new valid surface has been detected, so stop the search of a new surface
|
|
|
|
searchingNewSurfaceBelow = false;
|
|
searchingSurface = false;
|
|
searchAround = false;
|
|
powerActivated = false;
|
|
|
|
addPreviousVelocityMagnitude = true;
|
|
|
|
if (mainRigidbody.linearVelocity.magnitude != 0) {
|
|
previousVelocityMagnitude = mainRigidbody.linearVelocity.magnitude;
|
|
}
|
|
|
|
//set to 0 the vehicle velocity
|
|
mainRigidbody.linearVelocity = Vector3.zero;
|
|
|
|
//disable the collider in the center of mass
|
|
gravityCenterCollider.enabled = false;
|
|
|
|
//if the surface can be circumnavigate
|
|
if (hit.collider.gameObject.CompareTag (settings.tagForCircumnavigate)) {
|
|
circumnavigableSurfaceFound = true;
|
|
}
|
|
|
|
//if the surface is moving
|
|
if (hit.collider.gameObject.CompareTag (settings.tagForMovingObjects)) {
|
|
addParent (hit.collider.gameObject);
|
|
}
|
|
|
|
//if the new normal is different from the current normal, which means that is other surface inclination, then
|
|
if (hit.normal != currentNormal) {
|
|
//rotate the vehicle according to that normal
|
|
if (rotateVehicleCoroutine != null) {
|
|
StopCoroutine (rotateVehicleCoroutine);
|
|
}
|
|
|
|
rotateVehicleCoroutine = StartCoroutine (rotateToSurface (hit.normal, 2));
|
|
}
|
|
|
|
//disable the gravity control in the vehicle controller
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.changeGravityControlUse (false);
|
|
}
|
|
|
|
vehicleCameraManager.usingBoost (false, "StopShake", true, true);
|
|
|
|
if (rotateVehicleCoroutine != null) {
|
|
StopCoroutine (rotateVehicleCoroutine);
|
|
}
|
|
|
|
rotateVehicleCoroutine = StartCoroutine (rotateVehicleToLandSurfaceCoroutine (hit.normal));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void rotateVehicleToLandSurface (Vector3 hitNormal)
|
|
{
|
|
if (rotating && hitNormal == currentNormal) {
|
|
return;
|
|
}
|
|
|
|
if (rotateVehicleCoroutine != null) {
|
|
StopCoroutine (rotateVehicleCoroutine);
|
|
}
|
|
|
|
rotateVehicleCoroutine = StartCoroutine (rotateVehicleToLandSurfaceCoroutine (hitNormal));
|
|
}
|
|
|
|
public IEnumerator rotateVehicleToLandSurfaceCoroutine (Vector3 hitNormal)
|
|
{
|
|
rotating = true;
|
|
|
|
currentNormal = hitNormal;
|
|
|
|
//set the new normal in the vehicle controller
|
|
if (mainVehicleControllerLocated) {
|
|
mainVehicleController.setNormal (currentNormal);
|
|
}
|
|
|
|
//get the current rotation of the vehicle and the camera
|
|
Quaternion currentVehicleRotation = transform.rotation;
|
|
Quaternion currentVehicleCameraRotation = vehicleCamera.rotation;
|
|
Vector3 currentVehicleForward = Vector3.Cross (transform.right, hitNormal);
|
|
Quaternion targetVehicleRotation = Quaternion.LookRotation (currentVehicleForward, hitNormal);
|
|
Vector3 currentVehicleCameraForward = Vector3.Cross (vehicleCamera.right, hitNormal);
|
|
Quaternion targetVehicleCameraRotation = Quaternion.LookRotation (currentVehicleCameraForward, hitNormal);
|
|
|
|
//rotate from their rotation to thew new surface normal direction
|
|
for (float t = 0; t < 1;) {
|
|
t += Time.deltaTime * 2;
|
|
|
|
vehicleCamera.rotation = Quaternion.Slerp (currentVehicleCameraRotation, targetVehicleCameraRotation, t);
|
|
transform.rotation = Quaternion.Slerp (currentVehicleRotation, targetVehicleRotation, t);
|
|
|
|
yield return null;
|
|
}
|
|
|
|
rotating = false;
|
|
|
|
pauseDownForce (false);
|
|
|
|
if (addPreviousVelocityMagnitude) {
|
|
mainRigidbody.linearVelocity += previousVelocityMagnitude * (-currentNormal);
|
|
|
|
addPreviousVelocityMagnitude = false;
|
|
}
|
|
}
|
|
|
|
//get the current camera pivot, according to the vehicle view, in fisrt or third person
|
|
public void getCurrentCameraPivot (Transform newPivot)
|
|
{
|
|
pivot = newPivot;
|
|
}
|
|
|
|
public void pauseDownForce (bool state)
|
|
{
|
|
useGravity = !state;
|
|
}
|
|
|
|
public void setCustomNormal (Vector3 normal)
|
|
{
|
|
Quaternion currentVehicleRotation = transform.rotation;
|
|
Quaternion currentVehicleCameraRotation = vehicleCamera.rotation;
|
|
Vector3 currentVehicleForward = Vector3.Cross (transform.right, normal);
|
|
Quaternion targetVehicleRotation = Quaternion.LookRotation (currentVehicleForward, normal);
|
|
Vector3 currentVehicleCameraForward = Vector3.Cross (vehicleCamera.right, normal);
|
|
Quaternion targetVehicleCameraRotation = Quaternion.LookRotation (currentVehicleCameraForward, normal);
|
|
|
|
transform.rotation = targetVehicleRotation;
|
|
vehicleCamera.rotation = targetVehicleCameraRotation;
|
|
currentNormal = normal;
|
|
}
|
|
|
|
public override Vector3 getCurrentNormal ()
|
|
{
|
|
return currentNormal;
|
|
}
|
|
|
|
public float getGravityForce ()
|
|
{
|
|
return gravityForce;
|
|
}
|
|
|
|
public void setNewGravityForce (float newValue)
|
|
{
|
|
gravityForce = newValue;
|
|
}
|
|
|
|
public void setOriginalGravityForce ()
|
|
{
|
|
setNewGravityForce (originalGravityForce);
|
|
}
|
|
|
|
public override bool isUsingRegularGravity ()
|
|
{
|
|
return currentNormal == regularGravity;
|
|
}
|
|
|
|
public Vector3 getRegularGravity ()
|
|
{
|
|
return regularGravity;
|
|
}
|
|
|
|
public void updateCurrentNormalExternally (Vector3 newValue)
|
|
{
|
|
currentNormal = newValue;
|
|
}
|
|
|
|
public bool changeDriverGravityWhenGetsOffActive ()
|
|
{
|
|
return changeDriverGravityWhenGetsOff;
|
|
}
|
|
|
|
public bool isSetVehicleRegularGravityOnDriverGetOffActive ()
|
|
{
|
|
return setVehicleRegularGravityOnDriverGetOff;
|
|
}
|
|
|
|
public void setGravityForcePausedState (bool state)
|
|
{
|
|
gravityForcePaused = state;
|
|
}
|
|
|
|
public bool isGravityPowerActive ()
|
|
{
|
|
return gravityPowerActive;
|
|
}
|
|
|
|
public bool isGravityControlEnabled ()
|
|
{
|
|
return gravityControlEnabled;
|
|
}
|
|
|
|
//CALL INPUT FUNCTIONS
|
|
public void inputEnableOrDisableGravityControl (bool enableGravityControl)
|
|
{
|
|
if (HUDManager.vehicleIsDestroyed ()) {
|
|
return;
|
|
}
|
|
|
|
if (!mainVehicleController.isPlayerMovingOn3dWorld ()) {
|
|
return;
|
|
}
|
|
|
|
//if the vehicle is being driving
|
|
if (gravityControlEnabled && settings.canUseGravityControl) {
|
|
//activate the gravity control to search a new surface in the camera direction
|
|
if (enableGravityControl) {
|
|
activateGravityPower (pivot.TransformDirection (Vector3.forward), pivot.TransformDirection (Vector3.right));
|
|
} else {
|
|
//deactivate the gravity control
|
|
deactivateGravityPower ();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void inputIncreasOrDecreaseGravitySpeed (bool increaseGravitySpeed)
|
|
{
|
|
if (HUDManager.vehicleIsDestroyed ()) {
|
|
return;
|
|
}
|
|
|
|
if (gravityControlEnabled && settings.canUseGravityControl) {
|
|
if (searchingSurface || searchingNewSurfaceBelow || gravityPowerActive) {
|
|
//if the vehicle is searching a new surface, increase its velocity, only when the gravity power is active
|
|
if (increaseGravitySpeed) {
|
|
accelerating = true;
|
|
|
|
vehicleCameraManager.usingBoost (true, "Quick Gravity Control", true, true);
|
|
} else {
|
|
//stop to increase the velocity of the vehiclee in the air
|
|
accelerating = false;
|
|
|
|
vehicleCameraManager.usingBoost (true, "Regular Gravity Control", true, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setCheckDownSpeedActiveState (bool state)
|
|
{
|
|
checkDownSpeedActive = state;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
//draw the ray distance radius in the vehicle
|
|
void OnDrawGizmosSelected ()
|
|
{
|
|
if (showGizmo) {
|
|
if (settings.centerOfMass != null) {
|
|
Gizmos.color = Color.yellow;
|
|
Gizmos.DrawWireSphere (settings.centerOfMass.position, settings.vehicleRadius);
|
|
|
|
Gizmos.color = Color.cyan;
|
|
Gizmos.DrawLine (settings.centerOfMass.position, settings.centerOfMass.position - settings.rayDistance * settings.centerOfMass.up);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
[System.Serializable]
|
|
public class otherSettings
|
|
{
|
|
public LayerMask layer;
|
|
public float speed = 10;
|
|
public float accelerateSpeed = 20;
|
|
public float velocityToSearch = 10;
|
|
public float gravityMultiplier = 1;
|
|
public float rayDistance;
|
|
public float vehicleRadius;
|
|
public Transform centerOfMass;
|
|
public bool canUseGravityControl;
|
|
public float massDivider = 1000;
|
|
public string tagForCircumnavigate = "sphere";
|
|
public string tagForMovingObjects = "moving";
|
|
}
|
|
} |