981 lines
21 KiB
C#
981 lines
21 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using System.Collections;
|
|||
|
|
|
|||
|
|
public class sphereController : vehicleController
|
|||
|
|
{
|
|||
|
|
[Header ("Custom Settings")]
|
|||
|
|
[Space]
|
|||
|
|
|
|||
|
|
public otherVehicleParts vehicleParts;
|
|||
|
|
public vehicleSettings settings;
|
|||
|
|
|
|||
|
|
[Space]
|
|||
|
|
[Header ("Physics Settings")]
|
|||
|
|
[Space]
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 100f)]
|
|||
|
|
float maxSpeed = 10f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 100f)]
|
|||
|
|
float maxClimbSpeed = 4f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 100f)]
|
|||
|
|
float maxBoostClimbSpeed = 4f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 100f)]
|
|||
|
|
float maxSwimSpeed = 5f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 100f)]
|
|||
|
|
float maxAcceleration = 10f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 100f)]
|
|||
|
|
float maxAirAcceleration = 1f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 100f)]
|
|||
|
|
float maxClimbAcceleration = 40f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 100f)]
|
|||
|
|
float maxSwimAcceleration = 5f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0, 5)]
|
|||
|
|
int maxAirJumps = 0;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0, 90)]
|
|||
|
|
float maxGroundAngle = 25f, maxStairsAngle = 50f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (90, 180)]
|
|||
|
|
float maxClimbAngle = 140f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 100f)]
|
|||
|
|
float maxSnapSpeed = 100f;
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
float probeDistance = 1f;
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
float submergenceOffset = 0.5f;
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
float submergenceRange = 1f;
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
float buoyancy = 1f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0f, 10f)]
|
|||
|
|
float waterDrag = 1f;
|
|||
|
|
|
|||
|
|
[SerializeField, Range (0.01f, 1f)]
|
|||
|
|
float swimThreshold = 0.5f;
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
LayerMask probeMask = -1, stairsMask = -1, climbMask = -1, waterMask = 0;
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
float sphereRadius = 0.5f;
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
float sphereAlignSpeed = 45;
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
float sphereAirRotation = 0.5f;
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
float sphereSwimRotation = 2f;
|
|||
|
|
|
|||
|
|
public bool useClimbEnabled = true;
|
|||
|
|
|
|||
|
|
[Space]
|
|||
|
|
[Header ("Debug")]
|
|||
|
|
[Space]
|
|||
|
|
|
|||
|
|
public bool anyOnGround;
|
|||
|
|
|
|||
|
|
public int stepsSinceLastJump;
|
|||
|
|
|
|||
|
|
public int climbContactCount;
|
|||
|
|
|
|||
|
|
public bool desiresClimbing;
|
|||
|
|
|
|||
|
|
public int groundContactCount;
|
|||
|
|
|
|||
|
|
public int steepContactCount;
|
|||
|
|
|
|||
|
|
public int stepsSinceLastGrounded;
|
|||
|
|
|
|||
|
|
public Vector3 velocity;
|
|||
|
|
|
|||
|
|
public Vector3 moveInput;
|
|||
|
|
|
|||
|
|
[Space]
|
|||
|
|
[Header ("Components")]
|
|||
|
|
[Space]
|
|||
|
|
|
|||
|
|
public Transform sphereTransform;
|
|||
|
|
|
|||
|
|
float originalJumpPower;
|
|||
|
|
|
|||
|
|
Transform vehicleCameraTransform;
|
|||
|
|
|
|||
|
|
Rigidbody connectedBody;
|
|||
|
|
Rigidbody previousConnectedBody;
|
|||
|
|
|
|||
|
|
Vector3 connectionVelocity;
|
|||
|
|
|
|||
|
|
Vector3 connectionWorldPosition;
|
|||
|
|
Vector3 connectionLocalPosition;
|
|||
|
|
|
|||
|
|
Vector3 upAxis, rightAxis, forwardAxis;
|
|||
|
|
|
|||
|
|
bool desiredJump;
|
|||
|
|
|
|||
|
|
Vector3 contactNormal, steepNormal, climbNormal, lastClimbNormal;
|
|||
|
|
|
|||
|
|
Vector3 lastContactNormal, lastSteepNormal, lastConnectionVelocity;
|
|||
|
|
|
|||
|
|
float submergence;
|
|||
|
|
|
|||
|
|
int jumpPhase;
|
|||
|
|
|
|||
|
|
float minGroundDotProduct, minStairsDotProduct, minClimbDotProduct;
|
|||
|
|
|
|||
|
|
|
|||
|
|
public override void Awake ()
|
|||
|
|
{
|
|||
|
|
base.Awake ();
|
|||
|
|
|
|||
|
|
OnValidate ();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void Start ()
|
|||
|
|
{
|
|||
|
|
base.Start ();
|
|||
|
|
|
|||
|
|
originalJumpPower = vehicleControllerSettings.jumpPower;
|
|||
|
|
|
|||
|
|
vehicleCameraTransform = mainVehicleCameraController.transform;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void vehicleUpdate ()
|
|||
|
|
{
|
|||
|
|
base.vehicleUpdate ();
|
|||
|
|
|
|||
|
|
if (isPlayerMovingOn3dWorld ()) {
|
|||
|
|
moveInput.x = horizontalAxis;
|
|||
|
|
moveInput.z = verticalAxis;
|
|||
|
|
} else {
|
|||
|
|
if (desiresClimbing) {
|
|||
|
|
moveInput.z = verticalAxis;
|
|||
|
|
|
|||
|
|
moveInput.x = 0;
|
|||
|
|
} else {
|
|||
|
|
moveInput.x = verticalAxis;
|
|||
|
|
moveInput.z = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
moveInput.y = 0;
|
|||
|
|
moveInput = Vector3.ClampMagnitude (moveInput, 1f);
|
|||
|
|
|
|||
|
|
if (isCameraTypeFree ()) {
|
|||
|
|
rightAxis = projectDirectionOnPlane (settings.vehicleCamera.transform.right, upAxis);
|
|||
|
|
|
|||
|
|
forwardAxis = projectDirectionOnPlane (settings.vehicleCamera.transform.forward, upAxis);
|
|||
|
|
} else {
|
|||
|
|
Transform currentLockedCameraTransform = mainVehicleCameraController.getLockedCameraTransform ();
|
|||
|
|
|
|||
|
|
if (currentLockedCameraTransform != null) {
|
|||
|
|
if (isPlayerMovingOn3dWorld ()) {
|
|||
|
|
rightAxis = projectDirectionOnPlane (currentLockedCameraTransform.right, upAxis);
|
|||
|
|
|
|||
|
|
forwardAxis = projectDirectionOnPlane (currentLockedCameraTransform.forward, upAxis);
|
|||
|
|
} else {
|
|||
|
|
rightAxis = projectDirectionOnPlane (currentLockedCameraTransform.right, upAxis);
|
|||
|
|
|
|||
|
|
forwardAxis = projectDirectionOnPlane (currentLockedCameraTransform.forward, upAxis);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
rightAxis = Vector3.zero;
|
|||
|
|
|
|||
|
|
forwardAxis = Vector3.zero;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (isSwimmingActive ()) {
|
|||
|
|
setDesiresClimbingState (false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
updateSphereState ();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void setDesiresClimbingState (bool state)
|
|||
|
|
{
|
|||
|
|
desiresClimbing = state;
|
|||
|
|
|
|||
|
|
if (desiresClimbing) {
|
|||
|
|
|
|||
|
|
} else {
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mainVehicleGravityControl.setGravityForcePausedState (desiresClimbing);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void FixedUpdate ()
|
|||
|
|
{
|
|||
|
|
anyOnGround = isOnGround ();
|
|||
|
|
|
|||
|
|
if (usingHoverBoardWaypoint) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
upAxis = mainVehicleGravityControl.getCurrentNormal ();
|
|||
|
|
|
|||
|
|
Vector3 gravity = -upAxis * mainVehicleGravityControl.getGravityForce ();
|
|||
|
|
|
|||
|
|
fixedUpdateSphereState ();
|
|||
|
|
|
|||
|
|
if (insideWater ()) {
|
|||
|
|
velocity *= 1f - waterDrag * submergence * Time.deltaTime;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
adjustVelocity ();
|
|||
|
|
|
|||
|
|
if (desiredJump) {
|
|||
|
|
desiredJump = false;
|
|||
|
|
|
|||
|
|
activeJump (gravity);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (isClimbingActive ()) {
|
|||
|
|
velocity -= contactNormal * (maxClimbAcceleration * 0.9f * Time.deltaTime);
|
|||
|
|
|
|||
|
|
} else if (insideWater ()) {
|
|||
|
|
velocity += gravity * ((1f - buoyancy * submergence) * Time.deltaTime);
|
|||
|
|
|
|||
|
|
} else if (isOnGround () && velocity.sqrMagnitude < 0.01f) {
|
|||
|
|
velocity += contactNormal * (Vector3.Dot (gravity, contactNormal) * Time.deltaTime);
|
|||
|
|
|
|||
|
|
} else if (desiresClimbing && isOnGround ()) {
|
|||
|
|
velocity += (gravity - contactNormal * (maxClimbAcceleration * 0.9f)) * Time.deltaTime;
|
|||
|
|
|
|||
|
|
} else {
|
|||
|
|
velocity += gravity * Time.deltaTime;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mainRigidbody.linearVelocity = velocity;
|
|||
|
|
|
|||
|
|
if (anyOnGround || isClimbingActive ()) {
|
|||
|
|
bool brakeActive = (braking || isBrakeActive ());
|
|||
|
|
|
|||
|
|
if (brakeActive) {
|
|||
|
|
float verticalVelocity = vehicleCameraTransform.InverseTransformDirection (mainRigidbody.linearVelocity).y;
|
|||
|
|
Vector3 downVelocity = vehicleCameraTransform.up * verticalVelocity;
|
|||
|
|
|
|||
|
|
mainRigidbody.linearVelocity = Vector3.Lerp (mainRigidbody.linearVelocity, Vector3.zero + downVelocity, Time.deltaTime * settings.brakeForce);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
clearState ();
|
|||
|
|
|
|||
|
|
currentSpeed = mainRigidbody.linearVelocity.magnitude;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void updateSphereState ()
|
|||
|
|
{
|
|||
|
|
Vector3 rotationPlaneNormal = lastContactNormal;
|
|||
|
|
|
|||
|
|
float rotationFactor = 1f;
|
|||
|
|
|
|||
|
|
if (isClimbingActive ()) {
|
|||
|
|
|
|||
|
|
} else if (isSwimmingActive ()) {
|
|||
|
|
|
|||
|
|
rotationFactor = sphereSwimRotation;
|
|||
|
|
} else if (!isOnGround ()) {
|
|||
|
|
if (isOnSteep ()) {
|
|||
|
|
rotationPlaneNormal = lastSteepNormal;
|
|||
|
|
} else {
|
|||
|
|
rotationFactor = sphereAirRotation;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Vector3 movement = (mainRigidbody.linearVelocity - lastConnectionVelocity) * Time.deltaTime;
|
|||
|
|
|
|||
|
|
movement -= rotationPlaneNormal * Vector3.Dot (movement, rotationPlaneNormal);
|
|||
|
|
|
|||
|
|
float distance = movement.magnitude;
|
|||
|
|
|
|||
|
|
Quaternion rotation = sphereTransform.localRotation;
|
|||
|
|
|
|||
|
|
if (connectedBody != null && connectedBody == previousConnectedBody) {
|
|||
|
|
rotation = Quaternion.Euler (connectedBody.angularVelocity * (Mathf.Rad2Deg * Time.deltaTime)) * rotation;
|
|||
|
|
|
|||
|
|
if (distance < 0.001f) {
|
|||
|
|
sphereTransform.localRotation = rotation;
|
|||
|
|
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
} else if (distance < 0.001f) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
float angle = distance * rotationFactor * (180f / Mathf.PI) / sphereRadius;
|
|||
|
|
|
|||
|
|
Vector3 rotationAxis = Vector3.Cross (rotationPlaneNormal, movement).normalized;
|
|||
|
|
|
|||
|
|
rotation = Quaternion.Euler (rotationAxis * angle) * rotation;
|
|||
|
|
|
|||
|
|
if (sphereAlignSpeed > 0f) {
|
|||
|
|
rotation = alignSphereRotation (rotationAxis, rotation, distance);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
sphereTransform.localRotation = rotation;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Quaternion alignSphereRotation (Vector3 rotationAxis, Quaternion rotation, float traveledDistance)
|
|||
|
|
{
|
|||
|
|
Vector3 sphereAxis = sphereTransform.up;
|
|||
|
|
|
|||
|
|
float dot = Mathf.Clamp (Vector3.Dot (sphereAxis, rotationAxis), -1f, 1f);
|
|||
|
|
|
|||
|
|
float angle = Mathf.Acos (dot) * Mathf.Rad2Deg;
|
|||
|
|
|
|||
|
|
float maxAngle = sphereAlignSpeed * traveledDistance;
|
|||
|
|
|
|||
|
|
Quaternion newAlignment = Quaternion.FromToRotation (sphereAxis, rotationAxis) * rotation;
|
|||
|
|
|
|||
|
|
if (angle <= maxAngle) {
|
|||
|
|
return newAlignment;
|
|||
|
|
} else {
|
|||
|
|
return Quaternion.SlerpUnclamped (rotation, newAlignment, maxAngle / angle);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void clearState ()
|
|||
|
|
{
|
|||
|
|
lastContactNormal = contactNormal;
|
|||
|
|
|
|||
|
|
lastSteepNormal = steepNormal;
|
|||
|
|
|
|||
|
|
lastConnectionVelocity = connectionVelocity;
|
|||
|
|
|
|||
|
|
groundContactCount = steepContactCount = climbContactCount = 0;
|
|||
|
|
|
|||
|
|
contactNormal = steepNormal = climbNormal = Vector3.zero;
|
|||
|
|
|
|||
|
|
connectionVelocity = Vector3.zero;
|
|||
|
|
|
|||
|
|
previousConnectedBody = connectedBody;
|
|||
|
|
|
|||
|
|
connectedBody = null;
|
|||
|
|
|
|||
|
|
submergence = 0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void fixedUpdateSphereState ()
|
|||
|
|
{
|
|||
|
|
stepsSinceLastGrounded += 1;
|
|||
|
|
|
|||
|
|
stepsSinceLastJump += 1;
|
|||
|
|
|
|||
|
|
velocity = mainRigidbody.linearVelocity;
|
|||
|
|
|
|||
|
|
if (checkClimbing () ||
|
|||
|
|
checkSwimming () ||
|
|||
|
|
isOnGround () ||
|
|||
|
|
snapToGround () ||
|
|||
|
|
checkSteepContacts ()) {
|
|||
|
|
|
|||
|
|
stepsSinceLastGrounded = 0;
|
|||
|
|
|
|||
|
|
if (stepsSinceLastJump > 1) {
|
|||
|
|
jumpPhase = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (groundContactCount > 1) {
|
|||
|
|
contactNormal.Normalize ();
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
contactNormal = upAxis;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (connectedBody != null) {
|
|||
|
|
if (connectedBody.isKinematic || connectedBody.mass >= mainRigidbody.mass) {
|
|||
|
|
updateConnectionState ();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void updateConnectionState ()
|
|||
|
|
{
|
|||
|
|
if (connectedBody == previousConnectedBody) {
|
|||
|
|
Vector3 connectionMovement = connectedBody.transform.TransformPoint (connectionLocalPosition) - connectionWorldPosition;
|
|||
|
|
|
|||
|
|
connectionVelocity = connectionMovement / Time.deltaTime;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
connectionWorldPosition = mainRigidbody.position;
|
|||
|
|
|
|||
|
|
connectionLocalPosition = connectedBody.transform.InverseTransformPoint (connectionWorldPosition);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool checkClimbing ()
|
|||
|
|
{
|
|||
|
|
if (isClimbingActive ()) {
|
|||
|
|
if (climbContactCount > 1) {
|
|||
|
|
climbNormal.Normalize ();
|
|||
|
|
|
|||
|
|
float upDot = Vector3.Dot (upAxis, climbNormal);
|
|||
|
|
|
|||
|
|
if (upDot >= minGroundDotProduct) {
|
|||
|
|
climbNormal = lastClimbNormal;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
groundContactCount = 1;
|
|||
|
|
|
|||
|
|
contactNormal = climbNormal;
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool checkSwimming ()
|
|||
|
|
{
|
|||
|
|
if (isSwimmingActive ()) {
|
|||
|
|
groundContactCount = 0;
|
|||
|
|
|
|||
|
|
contactNormal = upAxis;
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void updateMovingState ()
|
|||
|
|
{
|
|||
|
|
moving = verticalAxis != 0 || horizontalAxis != 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool snapToGround ()
|
|||
|
|
{
|
|||
|
|
if (stepsSinceLastGrounded > 1 || stepsSinceLastJump <= 2 || insideWater ()) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
float speed = velocity.magnitude;
|
|||
|
|
|
|||
|
|
if (speed > maxSnapSpeed) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
RaycastHit hit;
|
|||
|
|
|
|||
|
|
if (!Physics.Raycast (mainRigidbody.position, -upAxis, out hit, probeDistance, probeMask, QueryTriggerInteraction.Ignore)) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Vector3 hitNormal = hit.normal;
|
|||
|
|
|
|||
|
|
float upDot = Vector3.Dot (upAxis, hitNormal);
|
|||
|
|
|
|||
|
|
if (upDot < getMinDot (hit.collider.gameObject.layer)) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
groundContactCount = 1;
|
|||
|
|
|
|||
|
|
contactNormal = hitNormal;
|
|||
|
|
|
|||
|
|
float dot = Vector3.Dot (velocity, hitNormal);
|
|||
|
|
|
|||
|
|
if (dot > 0f) {
|
|||
|
|
velocity = (velocity - hitNormal * dot).normalized * speed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
connectedBody = hit.rigidbody;
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool checkSteepContacts ()
|
|||
|
|
{
|
|||
|
|
if (steepContactCount > 1) {
|
|||
|
|
steepNormal.Normalize ();
|
|||
|
|
|
|||
|
|
float upDot = Vector3.Dot (upAxis, steepNormal);
|
|||
|
|
|
|||
|
|
if (upDot >= minGroundDotProduct) {
|
|||
|
|
steepContactCount = 0;
|
|||
|
|
|
|||
|
|
groundContactCount = 1;
|
|||
|
|
|
|||
|
|
contactNormal = steepNormal;
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void adjustVelocity ()
|
|||
|
|
{
|
|||
|
|
float acceleration, speed;
|
|||
|
|
|
|||
|
|
Vector3 xAxis, zAxis;
|
|||
|
|
|
|||
|
|
float currentMaxSpeeed = maxSpeed * boostInput;
|
|||
|
|
|
|||
|
|
if (isClimbingActive ()) {
|
|||
|
|
acceleration = maxClimbAcceleration;
|
|||
|
|
|
|||
|
|
speed = maxClimbSpeed;
|
|||
|
|
|
|||
|
|
if (usingBoost) {
|
|||
|
|
speed = maxBoostClimbSpeed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
xAxis = Vector3.Cross (contactNormal, upAxis);
|
|||
|
|
|
|||
|
|
zAxis = upAxis;
|
|||
|
|
} else if (insideWater ()) {
|
|||
|
|
float swimFactor = Mathf.Min (1f, submergence / swimThreshold);
|
|||
|
|
|
|||
|
|
acceleration = Mathf.LerpUnclamped (isOnGround () ? maxAcceleration : maxAirAcceleration, maxSwimAcceleration, swimFactor);
|
|||
|
|
|
|||
|
|
speed = Mathf.LerpUnclamped (currentMaxSpeeed, maxSwimSpeed, swimFactor);
|
|||
|
|
|
|||
|
|
xAxis = rightAxis;
|
|||
|
|
zAxis = forwardAxis;
|
|||
|
|
} else {
|
|||
|
|
acceleration = isOnGround () ? maxAcceleration : maxAirAcceleration;
|
|||
|
|
|
|||
|
|
float currentClimbSpeed = maxClimbSpeed;
|
|||
|
|
|
|||
|
|
if (usingBoost) {
|
|||
|
|
currentClimbSpeed = maxBoostClimbSpeed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
speed = isOnGround () && desiresClimbing ? currentClimbSpeed : currentMaxSpeeed;
|
|||
|
|
|
|||
|
|
xAxis = rightAxis;
|
|||
|
|
zAxis = forwardAxis;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
xAxis = projectDirectionOnPlane (xAxis, contactNormal);
|
|||
|
|
zAxis = projectDirectionOnPlane (zAxis, contactNormal);
|
|||
|
|
|
|||
|
|
Vector3 relativeVelocity = velocity - connectionVelocity;
|
|||
|
|
|
|||
|
|
Vector3 adjustment;
|
|||
|
|
|
|||
|
|
adjustment.x = moveInput.x * speed - Vector3.Dot (relativeVelocity, xAxis);
|
|||
|
|
adjustment.z = moveInput.z * speed - Vector3.Dot (relativeVelocity, zAxis);
|
|||
|
|
|
|||
|
|
adjustment.y = isSwimmingActive () ? moveInput.y * speed - Vector3.Dot (relativeVelocity, upAxis) : 0f;
|
|||
|
|
|
|||
|
|
adjustment = Vector3.ClampMagnitude (adjustment, acceleration * Time.deltaTime);
|
|||
|
|
|
|||
|
|
velocity += (xAxis * adjustment.x + zAxis * adjustment.z) * boostInput;
|
|||
|
|
|
|||
|
|
if (isSwimmingActive ()) {
|
|||
|
|
velocity += upAxis * adjustment.y;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool isOnGround ()
|
|||
|
|
{
|
|||
|
|
return groundContactCount > 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool isOnSteep ()
|
|||
|
|
{
|
|||
|
|
return steepContactCount > 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool isClimbingActive ()
|
|||
|
|
{
|
|||
|
|
return climbContactCount > 0 && stepsSinceLastJump > 2;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool insideWater ()
|
|||
|
|
{
|
|||
|
|
return submergence > 0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool isSwimmingActive ()
|
|||
|
|
{
|
|||
|
|
return submergence >= swimThreshold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void preventSnapToGround ()
|
|||
|
|
{
|
|||
|
|
stepsSinceLastJump = -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnValidate ()
|
|||
|
|
{
|
|||
|
|
minGroundDotProduct = Mathf.Cos (maxGroundAngle * Mathf.Deg2Rad);
|
|||
|
|
|
|||
|
|
minStairsDotProduct = Mathf.Cos (maxStairsAngle * Mathf.Deg2Rad);
|
|||
|
|
|
|||
|
|
minClimbDotProduct = Mathf.Cos (maxClimbAngle * Mathf.Deg2Rad);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void activeJump (Vector3 gravity)
|
|||
|
|
{
|
|||
|
|
Vector3 jumpDirection;
|
|||
|
|
|
|||
|
|
if (isOnGround ()) {
|
|||
|
|
jumpDirection = contactNormal;
|
|||
|
|
} else if (isOnSteep ()) {
|
|||
|
|
jumpDirection = steepNormal;
|
|||
|
|
|
|||
|
|
jumpPhase = 0;
|
|||
|
|
} else if (maxAirJumps > 0 && jumpPhase <= maxAirJumps) {
|
|||
|
|
if (jumpPhase == 0) {
|
|||
|
|
jumpPhase = 1;
|
|||
|
|
}
|
|||
|
|
jumpDirection = contactNormal;
|
|||
|
|
} else {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
stepsSinceLastJump = 0;
|
|||
|
|
|
|||
|
|
jumpPhase += 1;
|
|||
|
|
|
|||
|
|
float jumpSpeed = Mathf.Sqrt (2f * gravity.magnitude * vehicleControllerSettings.jumpPower);
|
|||
|
|
|
|||
|
|
if (insideWater ()) {
|
|||
|
|
jumpSpeed *= Mathf.Max (0f, 1f - submergence / swimThreshold);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
jumpDirection = (jumpDirection + upAxis).normalized;
|
|||
|
|
|
|||
|
|
float alignedSpeed = Vector3.Dot (velocity, jumpDirection);
|
|||
|
|
|
|||
|
|
if (alignedSpeed > 0f) {
|
|||
|
|
jumpSpeed = Mathf.Max (jumpSpeed - alignedSpeed, 0f);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
velocity += jumpDirection * jumpSpeed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnCollisionEnter (Collision collision)
|
|||
|
|
{
|
|||
|
|
EvaluateCollision (collision);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnCollisionStay (Collision collision)
|
|||
|
|
{
|
|||
|
|
EvaluateCollision (collision);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void EvaluateCollision (Collision collision)
|
|||
|
|
{
|
|||
|
|
if (isSwimmingActive ()) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int layer = collision.gameObject.layer;
|
|||
|
|
|
|||
|
|
float minDot = getMinDot (layer);
|
|||
|
|
|
|||
|
|
for (int i = 0; i < collision.contacts.Length; i++) {
|
|||
|
|
Vector3 normal = collision.contacts [i].normal;
|
|||
|
|
|
|||
|
|
float upDot = Vector3.Dot (upAxis, normal);
|
|||
|
|
|
|||
|
|
if (upDot >= minDot) {
|
|||
|
|
groundContactCount += 1;
|
|||
|
|
|
|||
|
|
contactNormal += normal;
|
|||
|
|
|
|||
|
|
connectedBody = collision.rigidbody;
|
|||
|
|
} else {
|
|||
|
|
if (upDot > -0.01f) {
|
|||
|
|
steepContactCount += 1;
|
|||
|
|
|
|||
|
|
steepNormal += normal;
|
|||
|
|
|
|||
|
|
if (groundContactCount == 0) {
|
|||
|
|
connectedBody = collision.rigidbody;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (desiresClimbing && upDot >= minClimbDotProduct && (climbMask & (1 << layer)) != 0) {
|
|||
|
|
|
|||
|
|
climbContactCount += 1;
|
|||
|
|
|
|||
|
|
climbNormal += normal;
|
|||
|
|
|
|||
|
|
lastClimbNormal = normal;
|
|||
|
|
|
|||
|
|
connectedBody = collision.rigidbody;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnTriggerEnter (Collider other)
|
|||
|
|
{
|
|||
|
|
if ((waterMask & (1 << other.gameObject.layer)) != 0) {
|
|||
|
|
EvaluateSubmergence (other);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnTriggerStay (Collider other)
|
|||
|
|
{
|
|||
|
|
if ((waterMask & (1 << other.gameObject.layer)) != 0) {
|
|||
|
|
EvaluateSubmergence (other);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void EvaluateSubmergence (Collider collider)
|
|||
|
|
{
|
|||
|
|
RaycastHit hit;
|
|||
|
|
|
|||
|
|
if (Physics.Raycast (mainRigidbody.position + upAxis * submergenceOffset, -upAxis, out hit, submergenceRange + 1f, waterMask)) {
|
|||
|
|
//, QueryTriggerInteraction.Collide)) {
|
|||
|
|
submergence = 1f - hit.distance / submergenceRange;
|
|||
|
|
} else {
|
|||
|
|
submergence = 1f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (isSwimmingActive ()) {
|
|||
|
|
connectedBody = collider.attachedRigidbody;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Vector3 projectDirectionOnPlane (Vector3 direction, Vector3 normal)
|
|||
|
|
{
|
|||
|
|
return (direction - normal * Vector3.Dot (direction, normal)).normalized;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
float getMinDot (int layer)
|
|||
|
|
{
|
|||
|
|
if ((stairsMask & (1 << layer)) == 0) {
|
|||
|
|
return minGroundDotProduct;
|
|||
|
|
} else {
|
|||
|
|
return minStairsDotProduct;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//if the vehicle is using the gravity control, set the state in this component
|
|||
|
|
public override void changeGravityControlUse (bool state)
|
|||
|
|
{
|
|||
|
|
base.changeGravityControlUse (state);
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//the player is getting on or off from the vehicle, so
|
|||
|
|
public override void changeVehicleState ()
|
|||
|
|
{
|
|||
|
|
base.changeVehicleState ();
|
|||
|
|
|
|||
|
|
setDesiresClimbingState (false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void setTurnOnState ()
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void setTurnOffState (bool previouslyTurnedOn)
|
|||
|
|
{
|
|||
|
|
base.setTurnOffState (previouslyTurnedOn);
|
|||
|
|
|
|||
|
|
if (previouslyTurnedOn) {
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override bool isDrivingActive ()
|
|||
|
|
{
|
|||
|
|
return driving;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void setEngineOnOrOffState ()
|
|||
|
|
{
|
|||
|
|
base.setEngineOnOrOffState ();
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void turnOnOrOff (bool state, bool previouslyTurnedOn)
|
|||
|
|
{
|
|||
|
|
base.turnOnOrOff (state, previouslyTurnedOn);
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//the vehicle has been destroyed, so disabled every component in it
|
|||
|
|
public override void disableVehicle ()
|
|||
|
|
{
|
|||
|
|
base.disableVehicle ();
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//if the vehicle is using the boost, set the boost particles
|
|||
|
|
public override void usingBoosting ()
|
|||
|
|
{
|
|||
|
|
base.usingBoosting ();
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//use a jump platform
|
|||
|
|
public void useVehicleJumpPlatform (Vector3 direction)
|
|||
|
|
{
|
|||
|
|
mainRigidbody.AddForce (mainRigidbody.mass * direction, ForceMode.Impulse);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void useJumpPlatformParable (Vector3 direction)
|
|||
|
|
{
|
|||
|
|
Vector3 jumpForce = direction;
|
|||
|
|
|
|||
|
|
mainRigidbody.AddForce (jumpForce, ForceMode.VelocityChange);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void setNewJumpPower (float newJumpPower)
|
|||
|
|
{
|
|||
|
|
vehicleControllerSettings.jumpPower = newJumpPower * 100;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void setOriginalJumpPower ()
|
|||
|
|
{
|
|||
|
|
vehicleControllerSettings.jumpPower = originalJumpPower;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//CALL INPUT FUNCTIONS
|
|||
|
|
public override void inputJump ()
|
|||
|
|
{
|
|||
|
|
if (driving && !usingGravityControl && isTurnedOn && vehicleControllerSettings.canJump) {
|
|||
|
|
if (usingHoverBoardWaypoint) {
|
|||
|
|
pickOrReleaseHoverboardVehicle (false, false);
|
|||
|
|
|
|||
|
|
Vector3 totalJumpForce = mainRigidbody.mass * hoverboardJumpForce * (currentNormal + transform.forward);
|
|||
|
|
|
|||
|
|
if (useHoverboardJumpClamp) {
|
|||
|
|
totalJumpForce = Vector3.ClampMagnitude (totalJumpForce, hoverboardJumpClamp);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mainRigidbody.AddForce (totalJumpForce, ForceMode.Impulse);
|
|||
|
|
|
|||
|
|
transform.rotation = Quaternion.identity;
|
|||
|
|
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (isSwimmingActive ()) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (desiresClimbing) {
|
|||
|
|
if (!isClimbingActive ()) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
if (!anyOnGround) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setDesiresClimbingState (false);
|
|||
|
|
|
|||
|
|
desiredJump = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void inputHoldOrReleaseTurbo (bool holdingButton)
|
|||
|
|
{
|
|||
|
|
if (driving && !usingGravityControl && isTurnedOn && !usingHoverBoardWaypoint) {
|
|||
|
|
//boost input
|
|||
|
|
if (holdingButton) {
|
|||
|
|
if (vehicleControllerSettings.canUseBoost) {
|
|||
|
|
usingBoost = true;
|
|||
|
|
//set the camera move away action
|
|||
|
|
mainVehicleCameraController.usingBoost (true, vehicleControllerSettings.boostCameraShakeStateName,
|
|||
|
|
vehicleControllerSettings.useBoostCameraShake, vehicleControllerSettings.moveCameraAwayOnBoost);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
//stop boost input
|
|||
|
|
usingBoost = false;
|
|||
|
|
|
|||
|
|
//disable the camera move away action
|
|||
|
|
mainVehicleCameraController.usingBoost (false, vehicleControllerSettings.boostCameraShakeStateName,
|
|||
|
|
vehicleControllerSettings.useBoostCameraShake, vehicleControllerSettings.moveCameraAwayOnBoost);
|
|||
|
|
|
|||
|
|
usingBoosting ();
|
|||
|
|
|
|||
|
|
boostInput = 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void inputHoldOrReleaseBrake (bool holdingButton)
|
|||
|
|
{
|
|||
|
|
if (driving && !usingGravityControl && isTurnedOn && anyOnGround) {
|
|||
|
|
braking = holdingButton;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void inputSetTurnOnState ()
|
|||
|
|
{
|
|||
|
|
if (driving && !usingGravityControl) {
|
|||
|
|
if (mainVehicleHUDManager.canSetTurnOnState) {
|
|||
|
|
setEngineOnOrOffState ();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void inputSetClimbState (bool state)
|
|||
|
|
{
|
|||
|
|
if (driving && !usingGravityControl && isTurnedOn) {
|
|||
|
|
if (!useClimbEnabled) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (isSwimmingActive ()) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setDesiresClimbingState (state);
|
|||
|
|
|
|||
|
|
if (state) {
|
|||
|
|
if (usingBoost) {
|
|||
|
|
mainVehicleCameraController.usingBoost (false, vehicleControllerSettings.boostCameraShakeStateName,
|
|||
|
|
vehicleControllerSettings.useBoostCameraShake, vehicleControllerSettings.moveCameraAwayOnBoost);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void inputToggleClimbState ()
|
|||
|
|
{
|
|||
|
|
if (driving && !usingGravityControl && isTurnedOn) {
|
|||
|
|
inputSetClimbState (!desiresClimbing);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[System.Serializable]
|
|||
|
|
public class otherVehicleParts
|
|||
|
|
{
|
|||
|
|
public Transform COM;
|
|||
|
|
public GameObject chassis;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[System.Serializable]
|
|||
|
|
public class vehicleSettings
|
|||
|
|
{
|
|||
|
|
public LayerMask layer;
|
|||
|
|
public GameObject vehicleCamera;
|
|||
|
|
public float brakeForce = 5;
|
|||
|
|
}
|
|||
|
|
}
|