# Player controls for top-down space shooter - any simpler way to do this?

I’m making a 2D game with a top-down camera perspective (think classic asteroids game), and I wrote this code to control the player movement.
It seems like a lot of manual work for a rather simple problem. Is there any simpler way to do this? I would have thought that for sure there are probably simple ways to do this provided by Unity, but haven’t found anything myself. Is there any?

``````using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour
{
[SerializeField] private float m_maxVelocity;
[SerializeField] private float m_force;					//to apply forward movement
[SerializeField] private float m_rotateSpeed;

//to indicate rotation direction
//unity's z rotation seems to be anti-clockwise
private int m_left  		=  1;
private int m_right 		= -1;

private Vector3 m_spinAxis = new Vector3 (0, 0, 1f);	//spin around z axis

private float m_zRotation;								//to keep object's z rotation from transform
private float m_x;										//for direction vector x component
private float m_y;										//for direction vector y component
private float m_angle;									//to keep angle of triangle when calculating vector
private Vector2 m_direction;							//vector to keep direction to apply force when moving

private Animator anim;

void Start()
{
anim = GetComponent<Animator>();
}

//no need for Time.deltaTime in FixedUpdate()
void FixedUpdate()
{
bool up 				= Input.GetKey("up");
bool right				= Input.GetKey("right");
bool left				= Input.GetKey("left");
bool space				= Input.GetKey("space");

if(up)
{
anim.SetFloat("speed", 1);						//set animation to "move"

//if total speed does not exceed max, move.
if((rigidbody2D.velocity.x + rigidbody2D.velocity.y) < m_maxVelocity)
{Move();}
}
else {anim.SetFloat("speed", 0);}					//when not moving, set animation to "idle"

if(left) {Rotate(m_left);}

if(right) {Rotate(m_right);}

m_zRotation = transform.rotation.eulerAngles.z;
}

void Rotate(int p_direction)
{
transform.Rotate(m_spinAxis, m_rotateSpeed * p_direction);
}

void Move()
{
//calc direction vector
m_direction = GetVector(m_zRotation);
}

Vector2 GetVector(float p_zRotation)
{
//find which quadrant we are in to calculate angle of triangle
if(p_zRotation > 0  p_zRotation < 90) 			//we are in first quadrant, angle is 90 - rotation
{
m_angle = 90f - p_zRotation;
//find x and y components for direction vector
m_x = CAH(m_angle, -1);							//in first quadrant, x is negative
m_y = SOH(m_angle);
}

else if(p_zRotation > 90  p_zRotation < 180) 		//we are in the second quadrant, angle is rotation - 90
{
m_angle = p_zRotation - 90f;
m_x = CAH(m_angle, -1);							//in second quadrant, x is negative
m_y = SOH(m_angle, -1);							//in second quadrant, y is negative
}

else if(p_zRotation > 180  p_zRotation < 270) 	//we are in the third quadrant, angle is 270 - rotation
{
m_angle = 270f - p_zRotation;
m_x = CAH(m_angle);
m_y = SOH(m_angle, -1);							//in third quadrant, y is negative
}

else if(p_zRotation > 270  p_zRotation < 360) 	//we are in the fourth quadrant, angle is rotation - 270
{
m_angle = p_zRotation - 270f;
m_x = CAH(m_angle);
m_y = SOH(m_angle);
}

else 												//angle is 0 degrees, we are moving straight up
{
m_x = 0f;
m_y = 1f;
}

return new Vector2(m_x, m_y);
}

float CAH(float p_angle, int p_sign = 1)
{
return (Mathf.Cos(p_angle)) * p_sign;
}

float SOH(float p_angle, int p_sign = 1)
{
return (Mathf.Sin(p_angle)) * p_sign;
}

{
return ((Mathf.PI / 180f) * p_angle);
}
}
``````

This works fine, just the way I want it, but since I’m new to programming I want to learn to find the simplest of solutions to simple problems and this doesn’t seem to be it, so I would appreciate any advice from someone more experienced.

Edit:
I forgot to articulate the actual “simple” problem that I’m trying to solve! The problem is that I need a direction vector to apply force. Since the player object can be rotated around the z axis, this force needs to be applied in the same direction as where the player object is facing.

You should be able to simply use transform.forward. Instead of keeping separate variables for rotation, direction, etc. (and re-doing all the math that Unity is doing behind the scenes anyway) just use the current orientation/rotation of your object. Instead of defining “m_spinAxis” you can just use “Vector3.up”. A better solution might be to use “transform.up” then it will be correct even if the ship changes its orientation.

If you are using a rigidbody, you want to use MoveRotation on the rigidbody (make sure rotations are frozen) instead of manipulating the transform directly for efficiency reasons (and will also provide proper collisions for the rotation). I have not used the 2D physics at all yet so I’m not sure if they have implemented MoveRotation for rigidbody2D yet, but that is something to keep in mind.

You also want to avoid checking input in FixedUpdate(). You are fine with GetKey() since that checks a flag inside the input manager that is set while a key is pressed, but for one-time key events such as GetKeyUp() or GetKeyDown() you will occasionally miss events in FixedUpdate(). The input manager refreshes its state every Update(). Just a heads up if you find you are missing key presses in the future.

I’ve looked at transform.forward before, but it doesn’t actually work out as an easy means to apply force towards the current orientation/rotation of my object, because this is along the z-axis, which doesn’t exist in 2D space.
But transform.up is exactly what I need. I don’t know why I didn’t look more closely at the reference for transform after I ditched transform.forward. Could have saved myself a few hours! Thanks for leading me back to the reference page!

Vector3.up is (0, 1, 0). I think you meant to say Vector3.forward, which is what I’m using (0, 0, 1). I prefer to have a more understandable variable here because when I later come back to this code it won’t immediately make sense why I’m rotating around “forward”.

No MoveRotation on RigidBody2D yet, but I’ll keep this in mind for 3D

Good point on getting input inside Update() instead of FixedUpdate()!

Thanks for the good tips