-
Notifications
You must be signed in to change notification settings - Fork 0
/
CarController.cs
158 lines (131 loc) · 4.85 KB
/
CarController.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using System;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.InputSystem;
[RequireComponent(typeof(AudioSource))]
public class CarController : MonoBehaviour
{
public Action<float> SpeedChanged;
[Header("Car Options")]
[SerializeField] private float maxForwardSpeed;
[SerializeField] private float maxReverseSpeed;
[SerializeField] private float steerRate;
[SerializeField] private float acceleration;
[SerializeField] private float brakingForce;
[SerializeField][Range(0f, 1f)] private float driftAmount;
[SerializeField] private float minimumDriftSpeed;
[SerializeField] private float maximumDrag;
[SerializeField] private float timeToChangeGear;
[Header("Sound Settings")]
[SerializeField] private float minEnginePitch;
[SerializeField] private float maxEnginePitch;
[SerializeField] private float maxPitchSpeed;
[NonSerialized] public float SteerInput;
[NonSerialized] public float AccelerationInput;
[NonSerialized] public float BrakeInput;
private bool _isReversing;
private bool _isEngineOn;
private float _rotationAngle;
private float _changeGearTimer;
private AudioSource _engineSound;
public float VelocityVsUp { get; private set; }
private PlayerInput _playerInput;
private Rigidbody2D _rigidbody;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody2D>();
_engineSound = GetComponent<AudioSource>();
_changeGearTimer = timeToChangeGear;
}
private void FixedUpdate()
{
Vector2 up = transform.up;
// Calculate our "forward" velocity, as opposed to actual velocity
VelocityVsUp = Vector2.Dot(up, _rigidbody.velocity);
// Add acceleration and control engine
ApplyEngineForce(up);
// Drag
_rigidbody.drag = maximumDrag * (1 - Mathf.Abs(AccelerationInput)); // Account for analogue input
// Steering
float turningCircle = Mathf.Clamp01(_rigidbody.velocity.magnitude / minimumDriftSpeed); // Limits cars ability to turn while slow
_rotationAngle -= SteerInput * steerRate * turningCircle * Time.fixedDeltaTime;
_rigidbody.MoveRotation(_rotationAngle);
// Drifting
Vector2 forwardVelocity = up * Vector2.Dot(_rigidbody.velocity, up);
Vector2 rightVelocity = transform.right * Vector2.Dot(_rigidbody.velocity, transform.right);
_rigidbody.velocity = forwardVelocity + rightVelocity * driftAmount;
SpeedChanged?.Invoke(_rigidbody.velocity.magnitude);
// Sound logic
float pitchPercent = Mathf.Abs(VelocityVsUp) / maxPitchSpeed;
pitchPercent = Mathf.Clamp01(pitchPercent);
_engineSound.pitch = (maxEnginePitch - minEnginePitch) * pitchPercent + minEnginePitch;
}
private void ApplyEngineForce(Vector2 up)
{
Vector2 engineForce = new();
float accel;
float brake;
float maxSpeed;
Vector2 direction;
if (_isReversing)
{
accel = BrakeInput;
brake = AccelerationInput;
maxSpeed = maxReverseSpeed;
direction = -up;
}
else
{
accel = AccelerationInput;
brake = BrakeInput;
maxSpeed = maxForwardSpeed;
direction = up;
}
// Acceleration
if (accel > 0)
{
if (VelocityVsUp > maxSpeed) // Limit forward speed
return;
if (_rigidbody.velocity.sqrMagnitude > maxSpeed * maxSpeed) // Limit speed in any direction while accelerating
return;
float currentAcceleration = accel * acceleration;
engineForce = direction * (currentAcceleration * Time.fixedDeltaTime);
}
// Braking
float currentBrake = brake * brakingForce;
if (brake > 0)
{
if (Mathf.Abs(VelocityVsUp) > 0.1)
engineForce += -direction * (currentBrake * Time.fixedDeltaTime);
else
_rigidbody.velocity = Vector2.zero;
}
// Apply forces
_rigidbody.AddForce(engineForce);
// Switch reversing using timer
if (brake > 0 && VelocityVsUp == 0)
{
_changeGearTimer -= Time.fixedDeltaTime;
if (_changeGearTimer <= 0)
{
_isReversing = !_isReversing;
_changeGearTimer = timeToChangeGear;
}
}
else
{
_changeGearTimer = timeToChangeGear;
}
}
public void ToggleEngine(bool engineOn)
{
if (engineOn)
{
_rigidbody.bodyType = RigidbodyType2D.Dynamic;
}
else
{
_rigidbody.bodyType = RigidbodyType2D.Kinematic;
}
}
}