Jump to content

Incremental sprite rotation based on mouse position.


symof
 Share

Recommended Posts

var game = new Phaser.Game(1024, 600, Phaser.auto, 'phaser-example', { preload: preload, create: create, update: update, render: render });

var result = 'Press a key';

function preload() {
	//load assets
    game.load.image("single_turret","./img/single_turret_64x64.png");
    game.load.image("mouse","./img/mouse.png");
}

function create() {
	//start physics
	game.physics.startSystem(Phaser.Physics.P2JS);
	
	single_turret = game.add.sprite(400,300,'single_turret');
	mousep = game.add.sprite(50,50,'mouse');

	
	//enable psysics on all items and enable debugged
	game.physics.p2.enable([single_turret,mousep], true);

	mousep.body.setCircle(4);
	mousep.body.kinematic = true;
	
	single_turret.body.setCircle(4);
	single_turret.body.kinematic = true;	

}

function update() { 
}

function render(){
	game.debug.text(result, 32, 32);
	
	mousep.body.x = game.input.x;
	mousep.body.y = game.input.y;

	lookAtObject(single_turret, mousep, 0.005);
}

function lookAtObject(obj, target, rotspeed){
	var angle = Math.atan2(target.body.y - obj.body.y, target.body.x - obj.body.x);
	result = obj.body.rotation + '**'+ (angle + game.math.degToRad(90))+ '**'+obj.body.angle;
	obj.body.rotation = angle + game.math.degToRad(90);
     
}

The code above rotates the "turret" to always be pointed towards the mouse so that it can fire at the mouse position.

The code works, but I want to add a rotation speed to it, however I can't figure out how to code that in. The lookAtObject() function is where I have the problem.

function lookAtObject(obj, target, rotspeed){
	var angle = Math.atan2(target.body.y - obj.body.y, target.body.x - obj.body.x);
	result = obj.body.rotation + '**'+ (angle + game.math.degToRad(90))+ '**'+obj.body.angle;
    
	if (obj.body.rotation <= angle + game.math.degToRad(90)){
		obj.body.rotation += rotspeed;
	}else{
		obj.body.rotation -= rotspeed;
	}
}

This statement does not work as intended because of how p2js works, so when It gets at ( -x , 0) the radians go from -1.5 to 4.7 and the rotation will reverse.

I am really stumped atm, so any ideas on how to approach this?

Link to comment
Share on other sites

Hi symof,

Try this out:

function lookAtObject(obj, target, rotspeed){
    var angle = Math.atan2(target.body.y - obj.body.y, target.body.x - obj.body.x);
    var da = angle - obj.body.rotation;
    
    if (da > Math.PI) {
        da -= game.math.PI2;
    } else if (da < -Math.PI) {
        da += game.math.PI2;
    }
    
    result = (angle - obj.body.rotation) + " : " + da;
    
    if (da < 0){
	obj.body.rotation -= rotspeed;
    } else {
	obj.body.rotation += rotspeed;
    }

    if (obj.body.rotation > Math.PI) {
        obj.body.rotation -= game.math.PI2;
    } else if (obj.body.rotation < -Math.PI) {
        obj.body.rotation += game.math.PI2;
    }
}

Here's the explanation.

At line 3:

    var da = angle - obj.body.rotation;

We're getting the difference between the angle of the mouse compared to the target and the target's current rotation.

If you were to output the result of da right after line 3, you would get a value of -4 or +4 when you attempt to rotate more than 180 degrees. 

This happens especially when you cross the 180 degree rotation point that turns into -180 degrees. As a result you get the values constantly jumping between a positive and negative value. I'm guessing you would already know this.

The value of PI is 3.14159265359 and this represents 180 degrees. The top half goes from 0 to -180 degrees while the bottom goes from 0 to 180 degrees like so:

rotation1.png

If the difference in angle happens to be more than 180 degrees or more than the value of PI, your sprite ends up rotating in the wrong direction. That's currently happening with your code.

That's where this part comes in:

    if (da > Math.PI) {
        da -= game.math.PI2;
    } else if (da < -Math.PI) {
        da += game.math.PI2;
    }

The first if checks for counter clockwise movement. The else if checks for clockwise movement.

Let's look at the da < -Math.PI condition. Before you cross the 180 degree line:

rotation2.png

When you cross the 180 degree line:

rotation3.png

The arrow indicates the direction your sprite rotates in. Which is not what we want.

To correct it we need to offset the result of da by 360 degrees. That's where the da += game.math.PI2 or da -= game.math.PI2 part comes in.

The result looks like this now:

rotation4.png

Make sense??

Okay, the last part here:

    if (obj.body.rotation > Math.PI) {
        obj.body.rotation -= game.math.PI2;
    } else if (obj.body.rotation < -Math.PI) {
        obj.body.rotation += game.math.PI2;
    }

This part is crucial. Missing it out would make your sprite rotate correctly only for one 360 degree turn. You can try leaving it out and rotate more than 2 turns and you'll see what I mean.

To keep the values and calculations correct, we need to ensure that when the sprite crosses the 180 degree line, we need to reset it back to its correct value.

Using the attached image example above, let's say the sprite has rotated towards the mouse cursor. Assume the value of obj.body.rotation = 4. We need to correct that value so it doesn't keep adding up if the sprite continues rotating clockwise.

Looking at the code above, the correction is the same as what we did for the da variable. Now you sprite can rotate as much as it wants without causing any problems.

Let me know if you need further clarification.

 

Link to comment
Share on other sites

I think you can simplify things a bit by using the vector dot product to find the shortest angle of rotation and then the vector cross product to find the direction of rotation (CW or CCW). You'll eliminate all those checks for direction. I touched on the topic in an older thread :

But the best resource I've found on this and related topics is the following :

http://natureofcode.com/book/chapter-6-autonomous-agents/

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...