Trigonometric Strafing Math

So, in the little game I’m developing the character moves around with his front facing the mouse. The character is in the center of the screen and the tiled background updates behind him according to how he moves.

If he moves forwards or backwards, he moves toward the mouse or away from it. That part works fine. The problem is I can’t get the left/right or a/d strafing movement to work right. Here are the methods I’m using:

public int move_directional_x_2(int quadrant, int r, double gamma, boolean left)  {
		int xa = 0;
		if (quadrant == 1)  {
			gamma = gamma + Math.PI / 2;
			
			if (left) xa -= r * Math.cos(gamma);
			else xa += r * Math.cos(gamma);
			
			return xa;
			//ya -= r * Math.sin(gamma);
		}
		if (quadrant == 2)  {
			gamma = gamma - Math.PI / 2;
			
			if (left) xa -= r * Math.cos(gamma);
			else xa += r * Math.cos(gamma);

			return xa;
			//ya -= r * Math.sin(gamma);
		}
		if (quadrant == 3)  {
			gamma = gamma - Math.PI;
			
			if (left)  xa += r * Math.cos(gamma);
			else xa -= r * Math.cos(gamma);

			return xa;
			//ya += r * Math.sin(gamma);
		}
		if (quadrant == 4)  {
			gamma = gamma - Math.PI * 1.5;
			
			if (left)  xa += r * Math.cos(gamma);
			else xa -= r * Math.cos(gamma);
			
			return xa;
			//ya += r * Math.sin(gamma);
		}
		return xa;
	}
	
	public int move_directional_y_2(int quadrant, int r, double gamma, boolean left)  {
		int ya = 0;
		if (quadrant == 1)  {
			gamma = gamma + Math.PI / 2;
			
			if (left) ya -= r * Math.sin(gamma);
			else ya += r * Math.sin(gamma);
			
			return ya;
		}
		if (quadrant == 2)  {
			gamma = gamma - Math.PI / 2;
			
			//xa -= r * Math.cos(gamma);
			if (left) ya += r * Math.sin(gamma);
			else ya -= r * Math.sin(gamma);
			
			return ya;
		}
		if (quadrant == 3)  {
			gamma = gamma - Math.PI;
			
			//xa -= r * Math.cos(gamma);
			if (left)  ya += r * Math.sin(gamma);
			else ya -= r * Math.sin(gamma);	
			
			return ya;
		}
		if (quadrant == 4)  {
			gamma = gamma - Math.PI * 1.5;
			
			//xa += r * Math.cos(gamma);
			if (left)  ya -= r * Math.sin(gamma);
			else ya += r * Math.sin(gamma);
			
			return ya;
		}
		return ya;
	}

xa and ya are the amounts of pixels the character moves by each frame. As I said forward/backwards works right but although I have tried a lot of different math things I can’t get the side to side movement to work right. I posted on here about low fps a week or two ago and the responses I got were helpful so I thought I’d try again. I just spent a little while working out the math on paper (not for the first time) and I was surprised when the movement did not work at all how I expected.

This is one example where using angles/trigonometry makes the whole thing unnecessarily complicated.
What you are currently doing is:

  1. get the mouse cursor position and convert it to an angle (likely with atan/atan2)
  2. use that angle and convert it back to length-projections on the X/Y axes

You can completely skip step 1. AND 2. by sticking to linear algebra and using the (normalized) mouse coordinates as a vector.
Assuming, you have the mouse/cursor coordinates, where (x=0, y=0) is the center, x increases towars the right and y increases towards the top edge of the viewport/screen, then the normalized vectors you need for forward/backward and left/right motion are simply this:


// mouse cursor coordinates with the origin at the viewport/screen center
float mx = <your mouse cursor x coordinate>;
float my = <your mouse cursor y coordinate>;
float invlen = 1.0f / (float) Math.sqrt(mx*mx + my*my);
// vectors for forward/backward
float forwardX = mx * invlen, forwardY = my * invlen;
float backwardX = -forwardX, backwardY = -forwardY;
// vectors for left/right
float leftX = -my * invlen, leftY = mx * invlen;
float rightX = -leftX, rightY = -leftY;

You absolutely do not need an angle and you do not need some “quadrant” information. Simply stick to your mouse cursor vector and do calculations with it, instead of converting that vector into an angle and back to a vector.

So, simply increment your character’s (x, y) position by the corresponding (scaled) vector.

Optionally, using floats will avoid aliasing in the coordinates after computations, so preferably work with floats and at the very end of translating the coordinates to the screen truncate them to int.

@KaiHH

Thank you! Not only was I able to get that code to work, but it’s a heck of a lot less unneeded code blotting up my screen.

I had to switch left and right for some reason and make sure the numbers weren’t turned into ints until the last step. I multiplied the vectors by another value, “r”, which is is the speed constant in my code. Just in case anyone else tries to use this code for their project.

Like I wrote above, those calculations assume that mx increases to the right and my to the top. Your mouse y coordinate likely increases to the bottom, as is typical in about every windowing system/toolkit.