|
|
|
|
using UnityEngine;
|
|
|
|
|
using CnControls;
|
|
|
|
|
|
|
|
|
|
public enum SurfaceDetection
|
|
|
|
|
{
|
|
|
|
|
RayCast,
|
|
|
|
|
SphereCast
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class VehicleController : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
[SerializeField] float currentSpeed = 0f;
|
|
|
|
|
[SerializeField] float steeringAI = 0f;
|
|
|
|
|
[SerializeField] bool isAIControlled = false;
|
|
|
|
|
[SerializeField] SurfaceDetection groundDetection = SurfaceDetection.RayCast;
|
|
|
|
|
[SerializeField] LayerMask driveableSurface = -1;
|
|
|
|
|
[SerializeField] float maxSpeed = 100f;
|
|
|
|
|
[SerializeField] float baseAcceleration = 10f;
|
|
|
|
|
[SerializeField] float steeringSensitivity = 10f;
|
|
|
|
|
[SerializeField] float gravityForce = 9.8f;
|
|
|
|
|
[SerializeField] float downforce = 5f;
|
|
|
|
|
[SerializeField] float brakeThreshold = 30f;
|
|
|
|
|
[SerializeField] float targetStoppingDistance = 5f;
|
|
|
|
|
[SerializeField] bool allowAirControl = false;
|
|
|
|
|
[SerializeField] AnimationCurve _frictionCurve = new AnimationCurve();
|
|
|
|
|
[SerializeField] AnimationCurve _turnCurve = new AnimationCurve();
|
|
|
|
|
|
|
|
|
|
[SerializeField, Range(0, 10)] float bodyTiltAmount = 0.5f;
|
|
|
|
|
[SerializeField] Transform carBodyVisual = null;
|
|
|
|
|
[SerializeField, Range(0.1f, 1f)] float skidMarkWidth = 0.25f;
|
|
|
|
|
[SerializeField, Range(0.1f, 10f)] float skidMarkDuration = 5f;
|
|
|
|
|
[SerializeField] Transform wheelFrontLeft = null;
|
|
|
|
|
[SerializeField] Transform wheelFrontRight = null;
|
|
|
|
|
[SerializeField] Transform wheelRearLeft = null;
|
|
|
|
|
[SerializeField] Transform wheelRearRight = null;
|
|
|
|
|
[SerializeField] Transform frontLeftAxle = null;
|
|
|
|
|
[SerializeField] Transform frontRightAxle = null;
|
|
|
|
|
[SerializeField] GameObject speedVisualEffects = null;
|
|
|
|
|
|
|
|
|
|
[SerializeField] Rigidbody sphereRigidbody = null;
|
|
|
|
|
[SerializeField] PhysicMaterial wheelFrictionMaterial = null;
|
|
|
|
|
[SerializeField] Transform cameraFollowTarget = null;
|
|
|
|
|
|
|
|
|
|
private bool isRunning = false;
|
|
|
|
|
private bool isOnGround = false;
|
|
|
|
|
private bool hasTurboBoost = true;
|
|
|
|
|
public bool nosActive = false;
|
|
|
|
|
|
|
|
|
|
private float accelerationInput = 0f;
|
|
|
|
|
private float brakeInput = 0f;
|
|
|
|
|
private float accelerationForce = 0f;
|
|
|
|
|
private float steeringSign = 0f;
|
|
|
|
|
private float inputHorizontal = 0f;
|
|
|
|
|
private float inputVertical = 0f;
|
|
|
|
|
private float wheelRadius = 0f;
|
|
|
|
|
private float desiredTurnAngle = 0f;
|
|
|
|
|
private float distanceToTarget = 0f;
|
|
|
|
|
private float angleDifference = 0f;
|
|
|
|
|
private float maxGroundDistance = 0f;
|
|
|
|
|
private float counterSteerValue = 0f;
|
|
|
|
|
private float steeringMultiplier = 0f;
|
|
|
|
|
|
|
|
|
|
private Vector3 velocityLocal = Vector3.zero;
|
|
|
|
|
private Vector3 forwardDirection = Vector3.zero;
|
|
|
|
|
private Vector3 directionToTarget = Vector3.zero;
|
|
|
|
|
private Vector3 movementDirection = Vector3.zero;
|
|
|
|
|
|
|
|
|
|
private RaycastHit surfaceHit;
|
|
|
|
|
private Rigidbody vehicleRigidbody = null;
|
|
|
|
|
private VehicleTracker targetTracker = null;
|
|
|
|
|
|
|
|
|
|
public bool AIControlled => isAIControlled;
|
|
|
|
|
public bool Running => isRunning;
|
|
|
|
|
public bool Grounded => isOnGround;
|
|
|
|
|
public float SkidWidth => skidMarkWidth;
|
|
|
|
|
public float SkidDuration => skidMarkDuration;
|
|
|
|
|
public float CurrentSpeed => velocityLocal.z;
|
|
|
|
|
public float MaximumSpeed => maxSpeed;
|
|
|
|
|
public bool InputsActive => inputHorizontal != 0 || inputVertical != 0 || nosActive;
|
|
|
|
|
public NOSController nosController;
|
|
|
|
|
internal float SteeringSensitivity
|
|
|
|
|
{
|
|
|
|
|
get => steeringSensitivity;
|
|
|
|
|
set => steeringSensitivity = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Vector3 LocalVelocity => velocityLocal;
|
|
|
|
|
public Transform FollowTarget => cameraFollowTarget;
|
|
|
|
|
[Range(0.3f, 1f)] public float steeringFactor = 1f;
|
|
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
|
{
|
|
|
|
|
vehicleRigidbody = GetComponent<Rigidbody>();
|
|
|
|
|
targetTracker = GetComponent<VehicleTracker>();
|
|
|
|
|
wheelRadius = sphereRigidbody.GetComponent<SphereCollider>().radius;
|
|
|
|
|
nosController = GetComponent<NOSController>();
|
|
|
|
|
// maxGroundDistance = 1.1f;
|
|
|
|
|
maxGroundDistance = wheelRadius + 0.5f;
|
|
|
|
|
InitializeVehicle();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void InitializeVehicle()
|
|
|
|
|
{
|
|
|
|
|
isRunning = true;
|
|
|
|
|
if (!isAIControlled)
|
|
|
|
|
accelerationForce = baseAcceleration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StopVehicle()
|
|
|
|
|
{
|
|
|
|
|
isRunning = false;
|
|
|
|
|
velocityLocal = Vector3.zero;
|
|
|
|
|
currentSpeed = 0f;
|
|
|
|
|
steeringAI = 0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
|
{
|
|
|
|
|
if (!isRunning) return;
|
|
|
|
|
ProcessInputs();
|
|
|
|
|
ApplyControls();
|
|
|
|
|
UpdateVisuals();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void FixedUpdate()
|
|
|
|
|
{
|
|
|
|
|
if (!isRunning) return;
|
|
|
|
|
CheckGround();
|
|
|
|
|
HandleMovement();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ProcessInputs()
|
|
|
|
|
{
|
|
|
|
|
inputVertical = CnInputManager.GetAxis("Vertical");
|
|
|
|
|
inputHorizontal = CnInputManager.GetAxis("Horizontal");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateVisuals()
|
|
|
|
|
{
|
|
|
|
|
counterSteerValue = (Mathf.Abs(velocityLocal.x) > 20f) ? -1f : 1f;
|
|
|
|
|
|
|
|
|
|
if (wheelFrontLeft) wheelFrontLeft.localRotation = Quaternion.Slerp(wheelFrontLeft.localRotation, Quaternion.Euler(0, 45f * counterSteerValue * steeringAI, 0), 0.1f);
|
|
|
|
|
if (wheelFrontRight) wheelFrontRight.localRotation = Quaternion.Slerp(wheelFrontRight.localRotation, Quaternion.Euler(0, 45f * counterSteerValue * steeringAI, 0), 0.1f);
|
|
|
|
|
|
|
|
|
|
frontLeftAxle?.Rotate(Vector3.right * (CurrentSpeed * 0.75f));
|
|
|
|
|
frontRightAxle?.Rotate(Vector3.right * (CurrentSpeed * 0.75f));
|
|
|
|
|
wheelRearLeft?.Rotate(Vector3.right * (CurrentSpeed * 0.75f));
|
|
|
|
|
wheelRearRight?.Rotate(Vector3.right * (CurrentSpeed * 0.75f));
|
|
|
|
|
|
|
|
|
|
if (speedVisualEffects)
|
|
|
|
|
speedVisualEffects.SetActive(velocityLocal.z > 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyControls()
|
|
|
|
|
{
|
|
|
|
|
Vector3 targetPoint = targetTracker.TargetPos;
|
|
|
|
|
targetPoint.y = transform.position.y;
|
|
|
|
|
directionToTarget = (targetPoint - transform.position).normalized;
|
|
|
|
|
forwardDirection = transform.forward.normalized;
|
|
|
|
|
|
|
|
|
|
desiredTurnAngle = Mathf.Abs(Vector3.Angle(forwardDirection, Vector3.ProjectOnPlane(directionToTarget, transform.up)));
|
|
|
|
|
distanceToTarget = Vector3.Distance(transform.position, targetTracker.TargetPos);
|
|
|
|
|
movementDirection = (targetTracker.TargetPos - transform.position).normalized;
|
|
|
|
|
float alignment = Vector3.Dot(transform.forward, movementDirection);
|
|
|
|
|
angleDifference = Vector3.Angle(transform.forward, movementDirection);
|
|
|
|
|
|
|
|
|
|
brakeInput = 0f;
|
|
|
|
|
|
|
|
|
|
if (distanceToTarget > targetStoppingDistance)
|
|
|
|
|
{
|
|
|
|
|
accelerationInput = alignment > 0f ? inputVertical : (distanceToTarget > 5f ? inputVertical : -1f);
|
|
|
|
|
steeringAI = (Vector3.SignedAngle(transform.forward, movementDirection, Vector3.up) > 0f ? 1f : -1f)
|
|
|
|
|
* _turnCurve.Evaluate(desiredTurnAngle / 160f);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
steeringAI = 0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isAIControlled)
|
|
|
|
|
steeringAI += inputHorizontal;
|
|
|
|
|
|
|
|
|
|
currentSpeed = Mathf.Round(CurrentSpeed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CheckGround()
|
|
|
|
|
{
|
|
|
|
|
//isOnGround = true;
|
|
|
|
|
|
|
|
|
|
if (groundDetection == SurfaceDetection.RayCast)
|
|
|
|
|
{
|
|
|
|
|
isOnGround = Physics.Raycast(sphereRigidbody.position, Vector3.down, out surfaceHit, maxGroundDistance, driveableSurface)
|
|
|
|
|
|| Physics.Raycast(sphereRigidbody.position + Vector3.forward * 3f, Vector3.down, out surfaceHit, maxGroundDistance, driveableSurface)
|
|
|
|
|
|| Physics.Raycast(sphereRigidbody.position - Vector3.forward * 3f, Vector3.down, out surfaceHit, maxGroundDistance, driveableSurface);
|
|
|
|
|
}
|
|
|
|
|
else if (groundDetection == SurfaceDetection.SphereCast)
|
|
|
|
|
{
|
|
|
|
|
isOnGround = Physics.SphereCast(sphereRigidbody.position + wheelRadius * Vector3.up, wheelRadius + 0.25f, -transform.up, out surfaceHit, maxGroundDistance, driveableSurface);
|
|
|
|
|
}
|
|
|
|
|
else isOnGround = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleMovement()
|
|
|
|
|
{
|
|
|
|
|
velocityLocal = vehicleRigidbody.transform.InverseTransformDirection(vehicleRigidbody.velocity);
|
|
|
|
|
|
|
|
|
|
if (float.IsNaN(velocityLocal.z) || float.IsInfinity(velocityLocal.z))
|
|
|
|
|
{
|
|
|
|
|
velocityLocal = Vector3.zero;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (angleDifference > brakeThreshold && velocityLocal.z > 15f)
|
|
|
|
|
{
|
|
|
|
|
wheelFrictionMaterial.dynamicFriction = 0.01f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
wheelFrictionMaterial.dynamicFriction = _frictionCurve.Evaluate(Mathf.Abs(velocityLocal.x / 100));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
steeringMultiplier = _turnCurve.Evaluate(velocityLocal.magnitude / maxSpeed);
|
|
|
|
|
|
|
|
|
|
if (Grounded)
|
|
|
|
|
{
|
|
|
|
|
steeringSign = Mathf.Sign(velocityLocal.z);
|
|
|
|
|
|
|
|
|
|
if (Mathf.Abs(accelerationInput) > 0.1f)
|
|
|
|
|
vehicleRigidbody.AddTorque(Vector3.up * (steeringAI * steeringSign * steeringSensitivity * 100f * steeringMultiplier * steeringFactor));
|
|
|
|
|
|
|
|
|
|
if (Mathf.Abs(accelerationInput) > 0.1f)
|
|
|
|
|
sphereRigidbody.velocity = Vector3.Lerp(sphereRigidbody.velocity, vehicleRigidbody.transform.forward * (accelerationInput * maxSpeed), accelerationForce / 10f * Time.fixedDeltaTime);
|
|
|
|
|
|
|
|
|
|
sphereRigidbody.AddForce(-transform.up * (downforce * sphereRigidbody.mass));
|
|
|
|
|
vehicleRigidbody.MoveRotation(
|
|
|
|
|
Quaternion.Slerp(
|
|
|
|
|
vehicleRigidbody.rotation,
|
|
|
|
|
Quaternion.FromToRotation(vehicleRigidbody.transform.up, surfaceHit.normal) * vehicleRigidbody.transform.rotation,
|
|
|
|
|
0.12f
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (allowAirControl)
|
|
|
|
|
vehicleRigidbody.AddTorque(Vector3.up * (steeringAI * steeringSensitivity * 100f * steeringMultiplier * steeringFactor));
|
|
|
|
|
|
|
|
|
|
sphereRigidbody.velocity = Vector3.Lerp(
|
|
|
|
|
sphereRigidbody.velocity,
|
|
|
|
|
(vehicleRigidbody.transform.forward * (accelerationInput * maxSpeed)) + Vector3.down * (gravityForce * 9.8f),
|
|
|
|
|
(accelerationForce / 25f) * Time.deltaTime
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void DisableVehicle()
|
|
|
|
|
{
|
|
|
|
|
enabled = false;
|
|
|
|
|
sphereRigidbody.gameObject.SetActive(false);
|
|
|
|
|
sphereRigidbody.velocity = Vector3.zero;
|
|
|
|
|
sphereRigidbody.Sleep();
|
|
|
|
|
vehicleRigidbody.velocity = Vector3.zero;
|
|
|
|
|
vehicleRigidbody.Sleep();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ActivateNOS()
|
|
|
|
|
{
|
|
|
|
|
ActivateNOS(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ActivateNOS(bool active, float bonusAcceleration = 10f)
|
|
|
|
|
{
|
|
|
|
|
nosActive = active;
|
|
|
|
|
accelerationForce = active ? accelerationForce + bonusAcceleration : baseAcceleration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void EnableVehicle()
|
|
|
|
|
{
|
|
|
|
|
enabled = true;
|
|
|
|
|
sphereRigidbody.gameObject.SetActive(true);
|
|
|
|
|
}
|
|
|
|
|
private void OnCollisionEnter(Collision collision)
|
|
|
|
|
{
|
|
|
|
|
Debug.Log("collision with: " + collision.gameObject.name, collision.gameObject);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//using UnityEngine;
|
|
|
|
|
//using CnControls;
|
|
|
|
|
//using Fusion;
|
|
|
|
|
|
|
|
|
|
//public enum SurfaceDetection
|
|
|
|
|
//{
|
|
|
|
|
// RayCast,
|
|
|
|
|
// SphereCast
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
//public class VehicleController : NetworkBehaviour
|
|
|
|
|
//{
|
|
|
|
|
// [SerializeField] float currentSpeed = 0f;
|
|
|
|
|
// [SerializeField] float steeringAI = 0f;
|
|
|
|
|
// [SerializeField] bool isAIControlled = false;
|
|
|
|
|
// [SerializeField] SurfaceDetection groundDetection = SurfaceDetection.RayCast;
|
|
|
|
|
// [SerializeField] LayerMask driveableSurface = -1;
|
|
|
|
|
// [SerializeField] float maxSpeed = 100f;
|
|
|
|
|
// [SerializeField] float baseAcceleration = 10f;
|
|
|
|
|
// [SerializeField] float steeringSensitivity = 10f;
|
|
|
|
|
// [SerializeField] float gravityForce = 9.8f;
|
|
|
|
|
// [SerializeField] float downforce = 5f;
|
|
|
|
|
// [SerializeField] float brakeThreshold = 30f;
|
|
|
|
|
// [SerializeField] float targetStoppingDistance = 5f;
|
|
|
|
|
// [SerializeField] bool allowAirControl = false;
|
|
|
|
|
// [SerializeField] AnimationCurve _frictionCurve = new AnimationCurve();
|
|
|
|
|
// [SerializeField] AnimationCurve _turnCurve = new AnimationCurve();
|
|
|
|
|
|
|
|
|
|
// [SerializeField, Range(0, 10)] float bodyTiltAmount = 0.5f;
|
|
|
|
|
// [SerializeField] Transform carBodyVisual = null;
|
|
|
|
|
// [SerializeField, Range(0.1f, 1f)] float skidMarkWidth = 0.25f;
|
|
|
|
|
// [SerializeField, Range(0.1f, 10f)] float skidMarkDuration = 5f;
|
|
|
|
|
// [SerializeField] Transform wheelFrontLeft = null;
|
|
|
|
|
// [SerializeField] Transform wheelFrontRight = null;
|
|
|
|
|
// [SerializeField] Transform wheelRearLeft = null;
|
|
|
|
|
// [SerializeField] Transform wheelRearRight = null;
|
|
|
|
|
// [SerializeField] Transform frontLeftAxle = null;
|
|
|
|
|
// [SerializeField] Transform frontRightAxle = null;
|
|
|
|
|
// [SerializeField] GameObject speedVisualEffects = null;
|
|
|
|
|
|
|
|
|
|
// [SerializeField] Rigidbody sphereRigidbody = null;
|
|
|
|
|
// [SerializeField] PhysicMaterial wheelFrictionMaterial = null;
|
|
|
|
|
// [SerializeField] Transform cameraFollowTarget = null;
|
|
|
|
|
|
|
|
|
|
// private bool isRunning = false;
|
|
|
|
|
// private bool isOnGround = false;
|
|
|
|
|
// private bool hasTurboBoost = true;
|
|
|
|
|
// public bool nosActive = false;
|
|
|
|
|
|
|
|
|
|
// private float accelerationInput = 0f;
|
|
|
|
|
// private float brakeInput = 0f;
|
|
|
|
|
// private float accelerationForce = 0f;
|
|
|
|
|
// private float steeringSign = 0f;
|
|
|
|
|
// private float inputHorizontal = 0f;
|
|
|
|
|
// private float inputVertical = 0f;
|
|
|
|
|
// private float wheelRadius = 0f;
|
|
|
|
|
// private float desiredTurnAngle = 0f;
|
|
|
|
|
// private float distanceToTarget = 0f;
|
|
|
|
|
// private float angleDifference = 0f;
|
|
|
|
|
// private float maxGroundDistance = 0f;
|
|
|
|
|
// private float counterSteerValue = 0f;
|
|
|
|
|
// private float steeringMultiplier = 0f;
|
|
|
|
|
|
|
|
|
|
// private Vector3 velocityLocal = Vector3.zero;
|
|
|
|
|
// private Vector3 forwardDirection = Vector3.zero;
|
|
|
|
|
// private Vector3 directionToTarget = Vector3.zero;
|
|
|
|
|
// private Vector3 movementDirection = Vector3.zero;
|
|
|
|
|
|
|
|
|
|
// private RaycastHit surfaceHit;
|
|
|
|
|
// private Rigidbody vehicleRigidbody = null;
|
|
|
|
|
// private VehicleTracker targetTracker = null;
|
|
|
|
|
|
|
|
|
|
// public bool AIControlled => isAIControlled;
|
|
|
|
|
// public bool Running => isRunning;
|
|
|
|
|
// public bool Grounded => isOnGround;
|
|
|
|
|
// public float SkidWidth => skidMarkWidth;
|
|
|
|
|
// public float SkidDuration => skidMarkDuration;
|
|
|
|
|
// public float CurrentSpeed => velocityLocal.z;
|
|
|
|
|
// public float MaximumSpeed => maxSpeed;
|
|
|
|
|
// public bool InputsActive => inputHorizontal != 0 || inputVertical != 0 || nosActive;
|
|
|
|
|
// public NOSController nosController;
|
|
|
|
|
// internal float SteeringSensitivity
|
|
|
|
|
// {
|
|
|
|
|
// get => steeringSensitivity;
|
|
|
|
|
// set => steeringSensitivity = value;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// public Vector3 LocalVelocity => velocityLocal;
|
|
|
|
|
// public Transform FollowTarget => cameraFollowTarget;
|
|
|
|
|
// [Range(0.3f, 1f)] public float steeringFactor = 1f;
|
|
|
|
|
// public override void Spawned()
|
|
|
|
|
// {
|
|
|
|
|
// base.Spawned();
|
|
|
|
|
// InitializeVehicle();
|
|
|
|
|
// bool isLocalPlayer = Object.HasInputAuthority; // true on the runner that owns this object
|
|
|
|
|
// bool isHostRunner = Runner.IsServer; // true on the host’s runner
|
|
|
|
|
// Debug.Log("Spawned");
|
|
|
|
|
// // if (local && hostRunner) OR (remote && clientRunner) ⇒ this is the host’s car
|
|
|
|
|
// if (isLocalPlayer == isHostRunner)
|
|
|
|
|
// gameObject.name = "PlayerHost";
|
|
|
|
|
// else
|
|
|
|
|
// gameObject.name = "PlayerClient";
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // 1) Fusion will call this every tick to collect local input
|
|
|
|
|
// public override void FixedUpdateNetwork()
|
|
|
|
|
// {
|
|
|
|
|
// if (!isRunning || !RaceCountdownManager.Instance || !RaceCountdownManager.Instance.RaceStarted)
|
|
|
|
|
// return;
|
|
|
|
|
|
|
|
|
|
// if (!Object.HasInputAuthority) return;
|
|
|
|
|
// Debug.Log("HasInputAuthority");
|
|
|
|
|
// if (/*Object.HasInputAuthority &&*/GetInput(out CarNetworkInput data))
|
|
|
|
|
// {
|
|
|
|
|
// inputHorizontal = data.Horizontal;
|
|
|
|
|
// inputVertical = data.Vertical;
|
|
|
|
|
// if (data.NOS) ActivateNOS();
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // ✅ Only simulate physics on authoritative runner
|
|
|
|
|
|
|
|
|
|
// ApplyControls();
|
|
|
|
|
// CheckGround();
|
|
|
|
|
// HandleMovement();
|
|
|
|
|
|
|
|
|
|
// UpdateVisuals(); // OK on all clients
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // 2) Fusion runs your simulation here instead of Update/FixedUpdate
|
|
|
|
|
// //public override void FixedUpdateNetwork()
|
|
|
|
|
// //{
|
|
|
|
|
// // if (!isRunning || !RaceCountdownManager.Instance || !RaceCountdownManager.Instance.RaceStarted)
|
|
|
|
|
// // return;
|
|
|
|
|
|
|
|
|
|
// // if (!Object.HasInputAuthority)
|
|
|
|
|
// // {
|
|
|
|
|
// // Debug.Log("🚫 No Input Authority on this player");
|
|
|
|
|
// // return;
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
|
|
// // if (Object.HasInputAuthority && GetInput(out CarNetworkInput data))
|
|
|
|
|
// // {
|
|
|
|
|
// // inputHorizontal = data.Horizontal;
|
|
|
|
|
// // inputVertical = data.Vertical;
|
|
|
|
|
// // Debug.Log("inputVertical: " + inputVertical);
|
|
|
|
|
// // Debug.Log("inputHorizontal : " + inputHorizontal);
|
|
|
|
|
// // if (data.NOS)
|
|
|
|
|
// // ActivateNOS();
|
|
|
|
|
// // ApplyControls();
|
|
|
|
|
// // CheckGround();
|
|
|
|
|
// // HandleMovement();
|
|
|
|
|
// // }
|
|
|
|
|
// // UpdateVisuals();
|
|
|
|
|
// //}
|
|
|
|
|
// private void Awake()
|
|
|
|
|
// {
|
|
|
|
|
// vehicleRigidbody = GetComponent<Rigidbody>();
|
|
|
|
|
// targetTracker = GetComponent<VehicleTracker>();
|
|
|
|
|
// wheelRadius = sphereRigidbody.GetComponent<SphereCollider>().radius;
|
|
|
|
|
// nosController = GetComponent<NOSController>();
|
|
|
|
|
// maxGroundDistance = wheelRadius + 0.5f;
|
|
|
|
|
// InitializeVehicle();
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// public void InitializeVehicle()
|
|
|
|
|
// {
|
|
|
|
|
// isRunning = true;
|
|
|
|
|
// if (!isAIControlled)
|
|
|
|
|
// accelerationForce = baseAcceleration;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// public void StopVehicle()
|
|
|
|
|
// {
|
|
|
|
|
// isRunning = false;
|
|
|
|
|
// velocityLocal = Vector3.zero;
|
|
|
|
|
// currentSpeed = 0f;
|
|
|
|
|
// steeringAI = 0f;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// //private void Update()
|
|
|
|
|
// //{
|
|
|
|
|
// // if (!isRunning) return;
|
|
|
|
|
// // UpdateVisuals();
|
|
|
|
|
// // ProcessInputs();
|
|
|
|
|
// // ApplyControls();
|
|
|
|
|
// //}
|
|
|
|
|
|
|
|
|
|
// private void ProcessInputs()
|
|
|
|
|
// {
|
|
|
|
|
// inputVertical = CnInputManager.GetAxis("Vertical");
|
|
|
|
|
// inputHorizontal = CnInputManager.GetAxis("Horizontal");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// private void UpdateVisuals()
|
|
|
|
|
// {
|
|
|
|
|
// counterSteerValue = (Mathf.Abs(velocityLocal.x) > 20f) ? -1f : 1f;
|
|
|
|
|
|
|
|
|
|
// if (wheelFrontLeft) wheelFrontLeft.localRotation = Quaternion.Slerp(wheelFrontLeft.localRotation, Quaternion.Euler(0, 45f * counterSteerValue * steeringAI, 0), 0.1f);
|
|
|
|
|
// if (wheelFrontRight) wheelFrontRight.localRotation = Quaternion.Slerp(wheelFrontRight.localRotation, Quaternion.Euler(0, 45f * counterSteerValue * steeringAI, 0), 0.1f);
|
|
|
|
|
|
|
|
|
|
// frontLeftAxle?.Rotate(Vector3.right * (CurrentSpeed * 0.75f));
|
|
|
|
|
// frontRightAxle?.Rotate(Vector3.right * (CurrentSpeed * 0.75f));
|
|
|
|
|
// wheelRearLeft?.Rotate(Vector3.right * (CurrentSpeed * 0.75f));
|
|
|
|
|
// wheelRearRight?.Rotate(Vector3.right * (CurrentSpeed * 0.75f));
|
|
|
|
|
|
|
|
|
|
// //if (carBodyVisual)
|
|
|
|
|
// //{
|
|
|
|
|
// // if (velocityLocal.z > 1)
|
|
|
|
|
// // carBodyVisual.localRotation = Quaternion.Slerp(carBodyVisual.localRotation,
|
|
|
|
|
// // Quaternion.Euler(Mathf.Lerp(0, -5, velocityLocal.z / maxSpeed), 0, Mathf.Clamp(desiredTurnAngle * steeringAI, -bodyTiltAmount, bodyTiltAmount)), 0.05f);
|
|
|
|
|
// // else
|
|
|
|
|
// // carBodyVisual.localRotation = Quaternion.Slerp(carBodyVisual.localRotation, Quaternion.identity, 0.05f);
|
|
|
|
|
// //}
|
|
|
|
|
|
|
|
|
|
// if (speedVisualEffects)
|
|
|
|
|
// speedVisualEffects.SetActive(velocityLocal.z > 10);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// private void ApplyControls()
|
|
|
|
|
// {
|
|
|
|
|
// Vector3 targetPoint = targetTracker.TargetPos;
|
|
|
|
|
// targetPoint.y = transform.position.y;
|
|
|
|
|
// directionToTarget = (targetPoint - transform.position).normalized;
|
|
|
|
|
// forwardDirection = transform.forward.normalized;
|
|
|
|
|
|
|
|
|
|
// desiredTurnAngle = Mathf.Abs(Vector3.Angle(forwardDirection, Vector3.ProjectOnPlane(directionToTarget, transform.up)));
|
|
|
|
|
// distanceToTarget = Vector3.Distance(transform.position, targetTracker.TargetPos);
|
|
|
|
|
// movementDirection = (targetTracker.TargetPos - transform.position).normalized;
|
|
|
|
|
// float alignment = Vector3.Dot(transform.forward, movementDirection);
|
|
|
|
|
// angleDifference = Vector3.Angle(transform.forward, movementDirection);
|
|
|
|
|
|
|
|
|
|
// brakeInput = 0f;
|
|
|
|
|
|
|
|
|
|
// if (distanceToTarget > targetStoppingDistance)
|
|
|
|
|
// {
|
|
|
|
|
// accelerationInput = alignment > 0f ? inputVertical : (distanceToTarget > 5f ? inputVertical : -1f);
|
|
|
|
|
// steeringAI = (Vector3.SignedAngle(transform.forward, movementDirection, Vector3.up) > 0f ? 1f : -1f)
|
|
|
|
|
// * _turnCurve.Evaluate(desiredTurnAngle / 160f);
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// steeringAI = 0f;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (!isAIControlled)
|
|
|
|
|
// steeringAI += inputHorizontal;
|
|
|
|
|
|
|
|
|
|
// currentSpeed = Mathf.Round(CurrentSpeed);
|
|
|
|
|
// Debug.Log("CurrentSpeed: " + currentSpeed);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// //private void FixedUpdate()
|
|
|
|
|
// //{
|
|
|
|
|
// // if (!isRunning) return;
|
|
|
|
|
// // CheckGround();
|
|
|
|
|
// // HandleMovement();
|
|
|
|
|
// //}
|
|
|
|
|
|
|
|
|
|
// private void CheckGround()
|
|
|
|
|
// {
|
|
|
|
|
// isOnGround = true;
|
|
|
|
|
// //if (groundDetection == SurfaceDetection.RayCast)
|
|
|
|
|
// //{
|
|
|
|
|
// // isOnGround = Physics.Raycast(sphereRigidbody.position, Vector3.down, out surfaceHit, maxGroundDistance, driveableSurface)
|
|
|
|
|
// // || Physics.Raycast(sphereRigidbody.position + Vector3.forward * 3f, Vector3.down, out surfaceHit, maxGroundDistance, driveableSurface)
|
|
|
|
|
// // || Physics.Raycast(sphereRigidbody.position - Vector3.forward * 3f, Vector3.down, out surfaceHit, maxGroundDistance, driveableSurface);
|
|
|
|
|
// //}
|
|
|
|
|
// //else if (groundDetection == SurfaceDetection.SphereCast)
|
|
|
|
|
// //{
|
|
|
|
|
// // isOnGround = Physics.SphereCast(sphereRigidbody.position + wheelRadius * Vector3.up, wheelRadius + 0.25f, -transform.up, out surfaceHit, maxGroundDistance, driveableSurface);
|
|
|
|
|
// //}
|
|
|
|
|
// //else isOnGround = false;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// private void HandleMovement()
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
|
|
// //if (!Object.HasInputAuthority)
|
|
|
|
|
// //{
|
|
|
|
|
// // Debug.LogWarning("Client without InputAuthority is simulating movement — this should not happen!");
|
|
|
|
|
// //}
|
|
|
|
|
// //else
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
|
|
// //if (Object.HasStateAuthority || Object.HasInputAuthority)
|
|
|
|
|
// //{
|
|
|
|
|
// // velocityLocal = vehicleRigidbody.transform.InverseTransformDirection(vehicleRigidbody.velocity);
|
|
|
|
|
// //}
|
|
|
|
|
|
|
|
|
|
// velocityLocal = vehicleRigidbody.transform.InverseTransformDirection(vehicleRigidbody.velocity);
|
|
|
|
|
|
|
|
|
|
// if (float.IsNaN(velocityLocal.z) || float.IsInfinity(velocityLocal.z))
|
|
|
|
|
// {
|
|
|
|
|
// Debug.LogWarning($"⚠ Detected invalid velocity: {velocityLocal}. Resetting to zero.");
|
|
|
|
|
// velocityLocal = Vector3.zero;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (angleDifference > brakeThreshold && velocityLocal.z > 15f)
|
|
|
|
|
// {
|
|
|
|
|
// wheelFrictionMaterial.dynamicFriction = 0.01f;
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// wheelFrictionMaterial.dynamicFriction = _frictionCurve.Evaluate(Mathf.Abs(velocityLocal.x / 100));
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// steeringMultiplier = _turnCurve.Evaluate(velocityLocal.magnitude / maxSpeed);
|
|
|
|
|
|
|
|
|
|
// if (Grounded)
|
|
|
|
|
// {
|
|
|
|
|
// steeringSign = Mathf.Sign(velocityLocal.z);
|
|
|
|
|
|
|
|
|
|
// if (Mathf.Abs(accelerationInput) > 0.1f)
|
|
|
|
|
// vehicleRigidbody.AddTorque(Vector3.up * (steeringAI * steeringSign * steeringSensitivity * 100f * steeringMultiplier * steeringFactor));
|
|
|
|
|
|
|
|
|
|
// if (Mathf.Abs(accelerationInput) > 0.1f)
|
|
|
|
|
// sphereRigidbody.velocity = Vector3.Lerp(sphereRigidbody.velocity, vehicleRigidbody.transform.forward * (accelerationInput * maxSpeed), accelerationForce / 10f * Time.fixedDeltaTime);
|
|
|
|
|
|
|
|
|
|
// sphereRigidbody.AddForce(-transform.up * (downforce * sphereRigidbody.mass));
|
|
|
|
|
// vehicleRigidbody.MoveRotation(
|
|
|
|
|
// Quaternion.Slerp(
|
|
|
|
|
// vehicleRigidbody.rotation,
|
|
|
|
|
// Quaternion.FromToRotation(vehicleRigidbody.transform.up, surfaceHit.normal) * vehicleRigidbody.transform.rotation,
|
|
|
|
|
// 0.12f
|
|
|
|
|
// )
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// if (allowAirControl)
|
|
|
|
|
// vehicleRigidbody.AddTorque(Vector3.up * (steeringAI * steeringSensitivity * 100f * steeringMultiplier * steeringFactor));
|
|
|
|
|
|
|
|
|
|
// sphereRigidbody.velocity = Vector3.Lerp(
|
|
|
|
|
// sphereRigidbody.velocity,
|
|
|
|
|
// (vehicleRigidbody.transform.forward * (accelerationInput * maxSpeed)) + Vector3.down * (gravityForce * 9.8f),
|
|
|
|
|
// (accelerationForce / 25f) * Time.deltaTime
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// internal void DisableVehicle()
|
|
|
|
|
// {
|
|
|
|
|
// enabled = false;
|
|
|
|
|
// sphereRigidbody.gameObject.SetActive(false);
|
|
|
|
|
// sphereRigidbody.velocity = Vector3.zero;
|
|
|
|
|
// sphereRigidbody.Sleep();
|
|
|
|
|
// vehicleRigidbody.velocity = Vector3.zero;
|
|
|
|
|
// vehicleRigidbody.Sleep();
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// public void ActivateNOS()
|
|
|
|
|
// {
|
|
|
|
|
// ActivateNOS(true);
|
|
|
|
|
// //nosController._isBoosting = true;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// public void ActivateNOS(bool active, float bonusAcceleration = 10f)
|
|
|
|
|
// {
|
|
|
|
|
// nosActive = active;
|
|
|
|
|
// accelerationForce = active ? accelerationForce + bonusAcceleration : baseAcceleration;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// internal void EnableVehicle()
|
|
|
|
|
// {
|
|
|
|
|
// enabled = true;
|
|
|
|
|
// sphereRigidbody.gameObject.SetActive(true);
|
|
|
|
|
// }
|
|
|
|
|
//}
|