/
Car_PlayerMovement.cs
131 lines (114 loc) · 4.09 KB
/
Car_PlayerMovement.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class Car_PlayerMovement : MonoBehaviour
{
[Header("Control")]
public float throttle = 1;
public float screenUse = 0.8f; // How much of the screen to use for turning? max turn is when touch at screenUse of screen width
[Header("Body")]
public Transform centerOfMass;
public Transform groundTrigger;
public LayerMask wheelCollidables;
public float drag = 1f;
[Header("Engine")]
public float driveForce = 1;
[Header("Suspension and Steering")]
public float activeVisualSteeringAngleEffect = 1;
public float maxVisualSteeringSpeed = 1;
public float maxVisualSteeringAngle = 30;
public float maxAngularAcceleration = 30; // degrees per second
public List<Transform> steeringWheels;
public List<Transform> driveWheels;
private Rigidbody _rb;
public float driftAngleThreshold = 10.0f;
void Start()
{
_rb = GetComponent<Rigidbody>();
}
void Update()
{
// Point wheels
float wheelAngle = -Vector3.Angle(_rb.velocity.normalized, GetDriveDirection()) * Vector3.Cross(_rb.velocity.normalized, GetDriveDirection()).y;
wheelAngle = Mathf.Min(Mathf.Max(-maxVisualSteeringAngle, wheelAngle), maxVisualSteeringAngle);
PointDriveWheelsAt(wheelAngle);
}
private float GetRawDriftAngle() {
if (! WheelsGrounded()) return 0;
return Vector3.Angle(_rb.velocity.normalized, GetDriveDirection()) * Vector3.Cross(_rb.velocity.normalized, GetDriveDirection()).y;
}
public float GetDriftAngle() {
return GetRawDriftAngle();
}
public bool IsFrontWheelDrift() {
return Mathf.Abs(GetDriftAngle()) > maxVisualSteeringAngle;
}
public bool IsDrifting() {
return Mathf.Abs(GetDriftAngle()) > driftAngleThreshold;
}
void FixedUpdate()
{
// Body
_rb.centerOfMass = centerOfMass.localPosition; // Doing each frame allows it to be changed in inspector
_rb.AddForce(-GetDragForce() * _rb.velocity.normalized);
// If rear wheels on ground
if (WheelsGrounded())
{
// Engine
_rb.AddForce(GetDriveDirection() * GetDriveForce());
// Steering
_rb.angularVelocity += -transform.up * GetSteeringAngularAcceleration() * Time.fixedDeltaTime;
}
}
/// Point the drive wheels at angle
/// angle relative to car direction
/// angle = 0 means wheels point forward
/// Does it smoothly
void PointDriveWheelsAt(float targetAngle)
{
foreach (Transform wheel in steeringWheels)
{
float currentAngle = wheel.localEulerAngles.y;
float change = ((((targetAngle - currentAngle) % 360) + 540) % 360) - 180;
float newAngle = currentAngle + change * Time.deltaTime * maxVisualSteeringSpeed;
wheel.localEulerAngles = new Vector3(0, newAngle, 0);
}
}
/// Are the drive wheels grounded
/// Can the car accelerate?
public bool WheelsGrounded()
{
return Physics.OverlapBox(groundTrigger.position, groundTrigger.localScale / 2, Quaternion.identity, wheelCollidables).Length > 0;
}
/// How fast do we spin car?
float GetSteeringAngularAcceleration()
{
return GetSteering() * maxAngularAcceleration * Mathf.PI / 180;
}
/// How much should we be turning?
/// Between -1 and 1
float GetSteering()
{
return Mathf.Clamp(TouchInput.centeredScreenPosition.x / screenUse, -1, 1);
}
/// What way car pointing
/// Is normalized
Vector3 GetDriveDirection()
{
return _rb.transform.forward.normalized;
}
/// How many beans will the car push itself with
/// in newtown
float GetDriveForce()
{
return driveForce * throttle;
}
/// Magnitude of drag
/// velocity squared times drag coefficient
/// Uses overall velocity, doesn't care about what direction car pointing
float GetDragForce()
{
return Mathf.Pow(_rb.velocity.magnitude, 2) * drag;
}
}