How to handle motion in a specific angle direction?

There are a number of questions about this it seems, but I don’t quite follow them well. Many of them seem to be confused in wording, and as a result, they are not answered for what I am wondering.

I have a clone of Asteroids that I am working on, which as you know is a 2D game. I already allow the player to rotate themselves (like in Asteroids, you turn left or right). Now I want to implement them moving forward, or in other words, in the direction of their spaceship’s nose cone. I am still unfamiliar with some of Unity’s intricacies, unfortunately, and so I am having difficulty implementing this ability, or understanding resources on how it is to be done. This is my code thus far. There are certain traits missing so far, but the biggest is the issue I brought up.

void Update () {
		VelocityUpdate();
		PositionUpdate();
	}
	
	void VelocityUpdate()
	{
		if(Input.GetKey(KeyCode.D))
        {
			if (ForwardVelocity == 0) ForwardVelocity = 1;
			if (ForwardVelocity < MaxVelocity)
				ForwardVelocity *= Acceleration;
	    }
        if(Input.GetKey(KeyCode.S))
        {
			transform.RotateAroundLocal(new Vector3(0,0,1),RotationSpeed);
	    }
        if(Input.GetKey(KeyCode.F))
        {
			transform.RotateAroundLocal(new Vector3(0,0,1),-RotationSpeed);
		}
	}
	
	void PositionUpdate()
	{
		transform.Translate(Vector3.forward * ForwardVelocity * Time.deltaTime);
	}

As I hope to have implied through this post, I want the ship to move in the direction of its facing based on the rotations done using the S and F keys. I believe it is the PositionUpdate which needs better methods. If anyone can help me to better implement that sort of asteroids-style movement, then I would greatly appreciate it.

You ask for movement “direction of their spaceship’s nose cone.” Transform.Translate() is in local coordinates, so it will move your ship in the forward direction when you use Vector3.forward as a parameter. If that is not in the direction of the cone, then your cone is not on the ‘forward’ of the object. Programming for Unity is far easier if you setup your model so that the forward (side facing positive ‘z’ when rotation is (0,0,0)), is the physical forward of the object. I suspect this is not the case for your setup, both because of the question and because of the parameters you use for RotateAroundLocal(). There are several fixes for the problem. The best is to fix it in the modeling program, but it can also be fixed by using an empty game object as a parent or by it can also be fixed in code.

But even if you fix this problem, you will not be mimicking Asteroids. In Asteroids the ship does not fly in the direction it is pointed. Instead they use “real” physics in that a burn modifies the existing velocity. For example in order to come to a stop, you need to rotate the ship 180 degrees fro the movement and apply a counter burn.

And there are a couple of other things for you to look at in your code:

  • RotateAroundLocal() is not documented. I’m not sure of its behavior, and I believe that, unlike document functions, uses Radians. I suggest using Transform.Rotate() instead.
  • Your rotation code also needs to be scaled by Time.deltaTime.

Here is a some sample code that implements a basic Asteroids-like movement. I threw in some wrapping code that causes the ship to wrap from one side of the screen to another. It doesn’t behave exactly like Asteroids (where I believe you saw a partial ship on each side of the screen). You will need to adjust the values for the screen size and the size of your ship.

using UnityEngine;
using System.Collections;
 
public class Bug25b : MonoBehaviour 
{
	float maxVelocity = 3.0f;
	float rotationSpeed = 180.0f;
	float acceleration = 1.0f;
	
	Vector3 velocity = Vector3.zero;
	
	void Update () {
		if (Input.GetKey (KeyCode.D)) {
			velocity += transform.forward * acceleration * Time.deltaTime;	
		}
		
		if (Input.GetKey (KeyCode.S)) {
			transform.Rotate(new Vector3(0,-rotationSpeed * Time.deltaTime, 0));
		}
		
		if (Input.GetKey (KeyCode.F)) {
			transform.Rotate(new Vector3(0,rotationSpeed * Time.deltaTime, 0));
		}		
		
		velocity = Vector3.ClampMagnitude (velocity, maxVelocity);
		transform.Translate(velocity * Time.deltaTime, Space.World);
		
		// Wrap object across viewport
		Vector3 viewportPos = Camera.main.WorldToViewportPoint(transform.position);
		if (viewportPos.x < -0.05f)
			viewportPos.x = 1.04f;
		if (viewportPos.y < -0.05f)
			viewportPos.y = 1.04f;
		if (viewportPos.x > 1.05f)
			viewportPos.x = -.04f;
		if (viewportPos.y > 1.05f)
			viewportPos.y = -.04f;
		transform.position = Camera.main.ViewportToWorldPoint(viewportPos);
    }
}

You can use the local space to move objects in relation to the current rotation. You can change between local and world space by clicking a button at the top of the screen (it’s there with pivot point and the other gizmos) transform.forward is (I think) the blue arrow of the GameObject. Vector3.forward is the world space z axis; it’s always a constant.

How that all relates to your problem: in your PositionUpdate, use transform.forward instead of Vector3.forward.