-
Notifications
You must be signed in to change notification settings - Fork 0
/
Vehicle.cs
355 lines (288 loc) · 11.9 KB
/
Vehicle.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Player))]
[RequireComponent(typeof(Rigidbody))]
public class Vehicle : MonoBehaviour
{
/* Manages AG-Vehicle Physics*/
// 2Do:
// - clean up
// - change all those "input" publics to Serialize-field-privates.
// - use private + get{} for variables that are "read only"
// - move all remaining audio-events to audio-script!
public bool groundContact = false;
public bool roadContact = false;
private float currentMaxSpeed = 100f;
public float currentGravity = 5;
public float standardGravity = 5; // <- from GM
public Vector3 gravityDirection = Vector3.down;
private float currentBanking = 0;
// private Vector3 velocity;
public float currentAcceleration = 0; // for engine-audio
public float currentSpeed = 0;
public float overDriveBoost = 0; // to boostscript...
public LayerMask groundLayer;
[Header("Transforms")]
public GameObject vehicleModel;
public Transform[] hoverPoints;
public GameObject collisionParticle;
// public ParticleSystem dustParticles; // to modify particles if inflight etc.
private VehicleAudio audioScript;
[HideInInspector]
public Player player; // <- now holds the vehiclestats aswell. does this make sense? i'm not sure yet
// this really depends on how i will load the player/vehicle, as in
// how the whole player setup will work.
private Rigidbody rb;
public CameraManager cameraScript;
private Spring bankingSpring = new Spring(); // move to Top
//---------------------------------------
void Start()
{
rb = GetComponent<Rigidbody>(); // required
player = GetComponent<Player>(); // required
audioScript = GetComponent<VehicleAudio>();
// set initial gravity:
gravityDirection = Vector3.down;
currentGravity = standardGravity;
}
//----------------------------------------------------------------
// Physics
//----------------------------------------------------------------
#region physics
void FixedUpdate()
{
RaycastHit hit;
Vector3 upForce;
float strength;
groundContact = false;
roadContact = false;
Vector3 normal = Vector3.zero;
for (int i = 0; i < hoverPoints.Length; i++)
{
if (Physics.Raycast(hoverPoints[i].position, transform.up * -1, out hit, player.vehicle.hoverHeight * 4f, groundLayer))
{
strength = (player.vehicle.hoverHeight - hit.distance) / player.vehicle.hoverHeight * 100f;
if (strength < 0) strength *= player.vehicle.holdForce;
else strength *= player.vehicle.liftForce * Mathf.Abs(strength / 2);
upForce = transform.up * strength;
rb.AddForceAtPosition(upForce, hoverPoints[i].position);
normal += hit.normal;
groundContact = true;
if (hit.transform.tag == "raceTrack") roadContact = true;
Debug.DrawRay(hoverPoints[i].position, upForce / 10f, Color.red);
}
}
normal.Normalize(); // averaged up-vector
ApplyDrag(groundContact);
if (groundContact) // align to ground!
{
AlignRotation(normal);
}
else // flying
{
ApplyGravity(gravityDirection);
AlignRotation(-gravityDirection);
}
// increase max speed if you are on the racetrack!
if (roadContact) currentMaxSpeed = player.vehicle.maxSpeed + player.vehicle.maxSpeed * player.vehicle.roadSpeedIncrease;
else currentMaxSpeed = player.vehicle.maxSpeed;
// charge booster
UpdateBoost(); // just move this to the boostscript already...
UpdateBanking();
// update variables
currentSpeed = rb.velocity.magnitude;
}
//---------------------------------------
// align to current up-axis
private void AlignRotation(Vector3 up)
{
Quaternion rotationCorrection = Quaternion.FromToRotation(transform.up, up) * transform.rotation;
rb.MoveRotation(Quaternion.Lerp(rb.rotation, rotationCorrection, Time.fixedDeltaTime * 10));
}
//---------------------------------------
// move to boost-script
private void UpdateBoost()
{
if (currentSpeed > currentMaxSpeed && currentMaxSpeed > 0)
GetComponent<VehicleBoost>().ChargeBoost();
overDriveBoost = GetComponent<VehicleBoost>().energyPool;
player.vehicle.maxOverDriveBoost = GetComponent<VehicleBoost>().energyPoolMax; // no need to set every time...! -> move to start
}
//---------------------------------------
private void ApplyGravity(Vector3 dir)
{
rb.velocity += dir * currentGravity;
// rb.AddForce(dir * gravity, ForceMode.Acceleration);
}
//---------------------------------------
private void ApplyDrag(bool isGrounded)
{
Vector3 vel = transform.InverseTransformDirection(rb.velocity);
if (isGrounded)
{
vel = Vector3.Scale(vel, (Vector3.one - player.vehicle.drag));
}
else // flying
{
vel *= (1f - player.vehicle.airDrag);
}
vel = transform.TransformDirection(vel);
rb.velocity = vel;
rb.angularVelocity *= 1f - player.vehicle.angularDrag;
// forward alignment!
// rotate velocity vector towards the ships forward!
float side = Vector3.Dot(transform.right, rb.velocity.normalized);
rb.velocity += transform.forward * Mathf.Abs(side) * player.vehicle.forwardAlignmentSpeed;
rb.velocity -= transform.right * side * player.vehicle.forwardAlignmentSpeed;
}
#endregion
//----------------------------------------------------------------
// steering
//----------------------------------------------------------------
#region steering
public void Accelerate(float amount)
{
if (!player.isInputEnabled) return; // shouldn't even be called from inputScript, but just to be sure
if (rb.velocity.magnitude < currentMaxSpeed - player.vehicle.acceleration)
// rb.AddForce(transform.forward * acceleration * amount);
rb.velocity += transform.forward * player.vehicle.acceleration * amount;
currentAcceleration = amount;
}
//---------------------------------------
public void Deccelerate(float amount)
{ //0->1
Vector3 vel = transform.InverseTransformDirection(rb.velocity);
if (vel.z > 0)
// rb.AddForce(transform.forward * -decceleration * amount);
rb.velocity -= transform.forward * player.vehicle.decceleration * amount;
}
//---------------------------------------
public void Turn(float amount)
{
if (!player.isInputEnabled) return;
// some lerping might be nice?
Quaternion rot = rb.rotation;
rot *= Quaternion.Euler(0, player.vehicle.turnSpeed * amount, 0);
rb.MoveRotation(rot);
Bank(amount);
}
//---------------------------------------
public void Pitch(float amount)
{
// if (!isInputEnabled) return; // nope, always allow this, so the player can confirm that inputs are working!
// only pitch when flying! // if i do that, then i maybe shoudln't align to gravity direction? ... hmmmm....
// if (groundContact) return;
Quaternion rot = rb.rotation;
rot *= Quaternion.Euler(-player.vehicle.turnSpeed * amount, 0, 0);
rb.MoveRotation(rot);
}
//---------------------------------------
public void Strafe(float amount) // strave? -> check your spelling!
{
if (!player.isInputEnabled) return;
// rb.AddForce(transform.right * amount * straveSpeed);
// rb.MovePosition(transform.position + transform.right * amount * straveSpeed); // !?? warum kippt des!?
rb.velocity += transform.right * player.vehicle.straveSpeed * amount;
SpringBank(-amount);
}
//---------------------------------------
public void Boost()
{
if (!player.isInputEnabled) return;
if (GetComponent<VehicleBoost>().ApplyBoost() < 0) return;
if (GetComponent<CameraManager>())
GetComponent<CameraManager>().Boost();
if (cameraScript != null) cameraScript.Boost();
// play boost audio
audioScript.Turbo();
}
//---------------------------------------
// player controlled gravity
public void EnableGravity()
{
if (!player.isInputEnabled) return;
if (!groundContact) return; // gravity already applied
ApplyGravity(gravityDirection);// actually there's really no need to pass the direction...!
// rb.AddForce(gravityDirection * gravity * 1f, ForceMode.Acceleration);
}
//---------------------------------------
// remove the spring, use animation blend tree for this...! much clean, very simple, WOW!
private void SpringBank(float amount)
{
currentBanking += bankingSpring.Update(amount);
}
private void Bank(float amount)
{
// float bankAmount = 20;
currentBanking += amount;
}
private void UpdateBanking()
{
float bankAmount = currentBanking * 20f;
// bankAmount = Mathf.Clamp(bankAmount, -20, 20);
//vehicleModel.transform.eulerAngles = transform.eulerAngles + Vector3.forward * bankAmount;
// currentBanking = 0;
bankAmount = -currentBanking * 0.5f + 0.5f;
vehicleModel.GetComponent<Animator>().SetFloat("Bank", bankAmount);
currentBanking = 0;
}
#endregion
//---------------------------------------
public float GetSpeed() { return currentSpeed; }
//---------------------------------------
public void Respawn()
{
// todo:
// disable input, trigger animation, on animation-end: re-enable inputs
Transform spawnPoint = GetComponent<CurrentPositionManager>().GetRespawnPoint();
rb.velocity *= 0.0f;
rb.angularVelocity *= 0.0f;
rb.rotation = spawnPoint.rotation;
rb.position = spawnPoint.position + Vector3.up * 5; // remove z-offset! (and place waypoints properly!)
// move to new player.reset() function?
player.health = player.vehicle.maxHealth;
// reset gravity?
// reset Boost
foreach (Boost b in GetComponentsInChildren<Boost>())
{
b.RemoveBoost();
}
//play respawnaudio - will move to new respawn Routine / maybe even called from a respawn animation!
audioScript.Respawn();
/*
FMOD.Studio.EventInstance rspwn = FMODUnity.RuntimeManager.CreateInstance(respawnSoundEvent);
rspwn.set3DAttributes(FMODUnity.RuntimeUtils.To3DAttributes(gameObject, rb));
rspwn.start();
rspwn.release();
*/
Debug.Log(player.name + " respawned");
}
//---------------------------------------
void OnCollisionEnter(Collision col)
{
// audio
audioScript.Collision( col.relativeVelocity.magnitude);
//particles
for (int i = 0; i < col.contacts.Length; i++)
{
GameObject p = Instantiate(collisionParticle, col.contacts[i].point, Quaternion.identity) as GameObject;
p.transform.parent = this.transform;
}
// player health
if (player.isRacing)
{
if (col.impulse.magnitude < 1000)
player.health -= col.impulse.magnitude * 0.1f;
else player.health -= 100; // maximum damage
}
if (player.health <= 0)
{
Respawn();
}
if (col.transform.tag == "deathZone") // map/sector boundaries
{
Respawn();
}
}
}