Get direction of velocity

I’m pulling my hair out trying to figure out the direction of travel of a moving body, using MatterJS. The eventual end purpose is to be able to rotate the object in the opposite direction so it can decelerate.

I would have thought this would be built-in, but apparently not (or at least, I can’t find any reference to it in any documentation).

So the formula I’ve got now is, given a known Vx and Vy:

angle = Math.atan2(Vy,Vx) + Math.PI/2

The addition of Math.PI/2 basically rotates the result 1/4 circle CCW, as atan2() gives a number from the horizontal axis.

This works, mostly:

Vx Vy Direction angle
0 -1 N 0
1 -1 NE Pi * 1/4
1 0 E Pi * 2/4
1 1 SE Pi * 3/4
0 1 S Pi * 4/4
-1 1 SW Pi * 5/4
-1 0 W Pi * 6/4
-1 -1 NW -(Pi * 1/4)

What’s the deal with that last row? Is the NW quadrant a special case that requires this formula instead?

angle = 2*Math.PI + Math.atan2(-1,-1) + Math.PI/2;
angle = 5*Math.PI/2 + Math.atan2(-1,-1);// reduced formula

If you’re trying to get direction of velocity, can’t you just use slope?

(-1, -1) is the 3rd quadrant

That’s what atan2() is getting me - the angle/slope.

(-1,-1) is up and to the left. If you’re considering the first quadrant to be down and to the right, then yes, it’s the third quadrant.

In math, on an x and y grid, (-1,-1) is in the 3rd quadrant. It’s not quite clear to me what you’re doing… Maybe converting your coordinates would make it easier for you since Math.atan2 isn’t taking into account the inversion of your x and y coordinates…

For sake of simplicity I’ll speak in degrees. Math.atan2(-1,-1) gives -135 degrees, which would point you in the 3rd quadrant, mathematically speaking. I suppose you could normalize this angle by doing 360 - 135 = 225. That is to say, -135 degrees is counter-clockwise, 225 degrees is clockwise, both put you in the 3rd quadrant. It is more efficient to traverse 135 degrees in a counter-clockwise motion than 225 degrees in a clockwise motion, hence why you are given -135 and not 225.

Thanks for the explanation. I realize in math, (-x,-y) is down and to the left. However, from what I’ve seen (-x,-y) is up and to the left. Note that i’m referring to velocities, not Cartesian coordinates. I realize I alluded to that in my original post, but didn’t state it explicitly.

What I’m trying to do is come up with a formula/algorithm for determining the angle of velocity so I can point my sprite in the opposite direction of motion.

The universe as I understand it is:

  • angle 0/360/2Pi radians = up (as setting .rotation to 0 points a sprite up)
  • angle 180/Pi radians = down (as setting rotation to 180 points a sprite down)
  • a circle consists of 2Pi (as this is how all the Math.* trig functions operate)
  • X velocities follow the Cartesian standard of left of 0 = negative, right = positive.
  • Y velocities are inverted, in that above 0 = negative, below 0 = positive. (this is evidenced by the fact that giving a sprite a velocity of (-1,-1) will move it up and to the left)

The algorithm I have now is:

velAngle = function(x,y){
	if(x < 0 && y < 0){
		return 5*Math.PI/2 + Math.atan2(y,x);
	}
	else{
		return Math.atan2(y,x) + (Math.PI/2);
	}
}

Which is implemented to reverse the direction of the sprite like so:

let thetaV 		  = Game.Math.velAngle(x,y);
	reverseThetaV = Phaser.Math.Angle.Reverse(thetaV),
	diff          = Phaser.Math.Angle.ShortestBetween(
                      Phaser.Math.RadToDeg(reverseThetaV),
                      Game.Player.angle
                   ),
	increment     = (diff > 0) ? -anglePower : anglePower;

if(Math.abs(diff) > anglePower){
	Game.Player.angle += increment;
}
else{
	Game.Player.rotation = reverseThetaV;
}

I’m not married to any of my assumptions or methods. What I’ve come up with works through what I’ve discovered via experimentation but if there’s a better way to approach or understand any of this I’m more than willing to change.

Thanks for your help.

However, from what I’ve seen (-x,-y) is up and to the left

Only in Phaser 3 and similar WebGL frameworks. But Math.atan2() is a native Javascript function, it’s not beholden to this inverted coordinate system. I think that’s where you’re getting mixed up.

I’ll look at this more a bit later…

FYI, I’ve simplified the algorithm a bit to:

let angle = Math.atan2(y,x) + (Math.PI/2);
return (angle > 0) ? angle : Phaser.Math.PI2 + angle;

Can you help me better understand your goal…Are you trying to send the sprite back in a straight line to the point of its origin from which it began this movement? Or send it back in a straight line based off of its most recent trajectory? Or are you trying to send it back and retrace an exact path/arc?

I’ve got a spaceship that flies around. I want to be able to press the down arrow and have the ship rotate to be in the opposite direction of its trajectory. So if it’s moving exactly Northeast, pressing the down arrow should - regardless of the direction the ship is facing - rotate the ship around so it’s facing Southwest. If the ship is pointed North, it will rotate CCW until it faces Southwest. If the ship is pointed East, it’ll rotate CW until it faces Southwest.

Where it came from or the path it took doesn’t matter. The point of this action will be for the player to stop the ship from moving.

This isn’t very elegant but hopefully it can convey how I would go about doing it

var previous_x = 0;
var previous_y = 0;
var slope = 0;
var angle = 0;
var sprite_rotation = 0;

update(delta, time){

this.input.on(‘pointerdown’, (pointer) => {
slope = previous_y/previous_x;
angle = Math.atan(slope);
//find the angle of the pointer relative to your position
//phaser has .angle() for degrees or .rotation() for radians
//also setAngle() and setRotation()
if(pointer_angle > 180){
//calculate difference of 360-angle
//rotate sprite CCW by difference, setAngle(-difference), and set velocity to previous_x and previous_y to some magnitude
//maybe set velocity to 0 first before rotating and setting new velocity
}
else{
//same thing as in the if-block sort of but rotate CW
}
});

previous_x = this.sprite.x;
previous_y = this.sprite.y;
}

edit: I just saw you want it to rotate on the ‘down’ key

Thanks for looking into it.

I think you may be over complicating it. I put together what I think is what you want. Paste the below code here.

var config = {
    width: 800,
    height: 600,
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

var game = new Phaser.Game(config);
var img, v;

function preload ()
{
    this.load.image('pixel', 'assets/sprites/16x16.png');
}

function create ()
{
    v = {x: Phaser.Math.FloatBetween(-1, 1), y: Phaser.Math.FloatBetween(-1, 1)};
    img = this.add.image(300, 300, 'pixel').setScale(3, 1).setRotation(Math.atan2(v.y,v.x));

    this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN).on('down', (key, event)=>{
        this.tweens.add({ targets: v, x: v.x*-1, y: v.y*-1 });
        this.tweens.add({ targets: img, rotation: Math.atan2(v.y*-1,v.x*-1) });
    });
}

function update()
{
    img.setPosition(img.x + v.x, img.y + v.y);
}

Thanks @Jake.Caron, that did it. You didn’t exactly recreate what I wanted, but this line:

Math.atan2(v.y*-1,v.x*-1);

basically does the work of my velAngle() function and the call to Phaser.Math.Angle.Reverse().

Curiously though, I have to add (Math.PI/2) to that, otherwise I’m off by 90 degrees. Regardless, the reversal algorithm is much simpler now. Thanks.

Gotcha. Maybe because your sprite/graphic is facing up instead of right? Glad you were able to figure out a solution. :+1:

Just to throw in an explanation of the y inversion… This is very standard in game frameworks and graphical systems in general because the top of the screen becomes zero and then it extends forth from there into the positive. Like on a webpage the top of the screen is y=0 then as the page expands, even beyond the screen, it continues into the positive.

If this wasn’t the case, this would be very confusing. If the screen were 800px tall, the top of the screen would be y=800, the bottom would be zero, and as the page continues beneath the screen it would go negative. This kind of makes sense if we stop there but what if we scroll? What if we resize the window? Why do we need to know how big the screen is if we simply want to place something at the beginning (top) of the page? It rapidly gets insane trying to make downwards be negative.

It’s always good to take a little time at the beginning of a project and try to thoroughly understand the coordinate systems in play, define for yourself how your own game’s coordinate system will work, and then design adapters between your coordinate system, the game framework coordinate system, math coordinate systems, etc. Once you have those systems tied down then everything will Just Work as expected, no need to write special code around compensating for system differences into your ship reorientation code, just plug into your adapters. It’s also a great place to put the code that handles aspect ratio, landscape/portrait reorientation, resizing, etc.

thanks @jcwilk. That makes sense.

Initially I was going the route of making adapters, but then I thought “why make adapters when I can just change the way I’m thinking - then existing stuff will Just Work”.

The only “conversion” I’ve resigned myself to is converting between atan2's coordinate system (East is 0), and the game’s coordinate system (North is 0).

Yeah that’s reasonable, sometimes doing it the “clean” way is just unnecessary work and mess. For larger projects having a layer in there somewhere to handle these things is generally a good rule of thumb but for quickie things and prototypes yeah, cut corners are always nice for sure

I’m planning on breaking all the functionality out into Model objects, so the functionality will at least be encapsulated there.