Files
Robii Aragon fd87a6ffd5 add ckg
plantilla base para movimiento básico
2026-02-05 05:07:55 -08:00

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;
}
}