- Home /
Building a speed limit and deceleration system, need help fixing/optimising
I'm trying to make a spaceship dogfighting game, and have been trying to make my ships move like airplanes - always moving forward and cancelling sideways momentum, cancelling angular momentum when none of the pitch, roll or yaw keys are held down, and so on.
I've got a pair of scripts at the moment that are reasonably functional, one to control my test ship's orientation, and one to control its movement. Currently I want to rewrite the movement code to do a bunch of things:
I want the player to be able to increase or decrease the top speed (up to a set limit), whereupon the ship will accelerate to that speed, then stop accelerating and hold to its current forward velocity.
If the ship changes direction, I want it to re-accelerate until it's back up to full speed again. If the player reduces the ship's top speed, I want the ship to decelerate to match it.
I also want it to be possible to make the ship stop entirely, and go into reverse, with the same rules as going forwards.
Unfortunately, my current script is a broken mess, and I don't know what's going wrong. The ship will only move forward at a very limited rate, will accelerate backwards indefinitely, and if I alter the ship's orientation while moving it starts accelerating out of control in seemingly random directions.
I would greatly appreciate it if someone could review my script and point out any problems they can see, or offer any pointers on how my code could be made more efficient (I'm sure what I've got right now is very messy). I know that's quite a lot to ask, but I'm seriously struggling to untangle this stuff myself.
Here's my script:
using UnityEngine;
using System.Collections;
public class Thrust : MonoBehaviour
{
public float accelRate;
public float maxSpeed;
public Rigidbody rb;
float speed;
float reverseSpeed;
int throttle;
int reverseThrottle;
int speedKeyState;
void Start ()
{
rb = GetComponent<Rigidbody>();
speed = 0f;
throttle = 0;
reverseSpeed = 0f;
reverseThrottle = 0;
speedKeyState = 0;
Vector3 localVel = rb.transform.InverseTransformDirection (GetComponent<Rigidbody> ().velocity);
localVel.z = maxSpeed;
}
void FixedUpdate ()
{
Vector3 localVel = rb.transform.InverseTransformDirection (GetComponent<Rigidbody> ().velocity);
//This thrust is applied constantly, but limited by the state of the throttle variables
rb.AddRelativeForce (Vector3.forward * (throttle * (accelRate * Time.deltaTime)));
rb.AddRelativeForce (Vector3.back * (reverseThrottle * (accelRate * Time.deltaTime)));
//These two if blocks are meant to stop the ship from accelerating beyond the max speed, forwards or backwards, and apply a decelerating force in either direction to bring the ship back to the limit
if (localVel.z >= maxSpeed * speed) {
if (speed != 0) {
throttle = 0;
rb.AddRelativeForce (Vector3.back * ((accelRate * Time.deltaTime) * 0.1f));
}
throttle = 0;
} else {
throttle = 1;
}
if (localVel.z <= -(maxSpeed * reverseSpeed)) {
if (reverseSpeed != 0) {
reverseThrottle = 0;
rb.AddRelativeForce (Vector3.back * ((accelRate * Time.deltaTime) * 0.1f));
}
reverseThrottle = 0;
} else {
reverseThrottle = 1;
}
//These if blocks are intended to cancel out momentum on all axes besides Z, so the ship doesn't end up drifting sideways while flying
if (localVel.x > 0f)
{
rb.AddRelativeForce (Vector3.left * (speed * ((accelRate * 2) * Time.deltaTime)));
rb.AddRelativeForce (Vector3.left * (reverseSpeed * ((accelRate * 2) * Time.deltaTime)));
}
if (localVel.x < 0f)
{
rb.AddRelativeForce (Vector3.right * (speed * ((accelRate * 2) * Time.deltaTime)));
rb.AddRelativeForce (Vector3.right * (reverseSpeed * ((accelRate * 2) * Time.deltaTime)));
}
if (localVel.y > 0f)
{
rb.AddRelativeForce (Vector3.down * (speed * ((accelRate * 2) * Time.deltaTime)));
rb.AddRelativeForce (Vector3.down * (reverseSpeed * ((accelRate * 2) * Time.deltaTime)));
}
if (localVel.y < 0f)
{
rb.AddRelativeForce (Vector3.up * (speed * ((accelRate * 2) * Time.deltaTime)));
rb.AddRelativeForce (Vector3.up * (reverseSpeed * ((accelRate * 2) * Time.deltaTime)));
}
//This if block and the switch below are the controls that allow the player to increase or decrease the top speed, or go into reverse
if (Input.GetKey (KeyCode.UpArrow))
speedKeyState = 1;
if (Input.GetKey (KeyCode.DownArrow))
speedKeyState = 2;
if (!Input.GetKey (KeyCode.UpArrow) && !Input.GetKey (KeyCode.DownArrow))
speedKeyState = 0;
switch (speedKeyState)
{
case 1:
speed += 0.01f;
break;
case 2:
if (speed == 0f)
reverseSpeed += 0.01f;
else
speed -= 0.01f;
break;
case 0:
if (reverseSpeed > 0f)
reverseSpeed -= 0.01f;
break;
}
//These if blocks ensure that the speed variables cannot rise or fall below certain thresholds, so that the ship will always be limited to 100% top speed going forwards, and 20% top speed going backwards
if (speed > 1f)
speed = 1f;
if (speed < 0f)
speed = 0f;
if (reverseSpeed > 0.2f)
reverseSpeed = 0.2f;
if (reverseSpeed < 0f)
reverseSpeed = 0f;
//Some print functions for debug purposes
print ("speed is: " + speed);
print ("throttle is: " + throttle);
print ("localVel is: " + localVel);
print ("reverseThrottle is: " + reverseThrottle);
print ("reverseSpeed is: " + reverseSpeed);
}
}