Puzz3l Posted April 28, 2014 Share Posted April 28, 2014 I have a sprite and a body that both rotate towards the pointer. On collision, though, the sprite sometimes gets turned away from the body. The body continues to point towards the mouse but the sprite does not (see image, definitely not the worst that it can be). I haven't found a way to fix this, anyone know how? Link to comment Share on other sites More sharing options...
george Posted April 28, 2014 Share Posted April 28, 2014 This shouldn't happen. Position and rotation are both applied to the sprite. Always. So maybe you have something that is overriding the rotation?Look at this example. A rotating polygon. Nothing special with it. http://examples.phaser.io/_site/view_full.html?d=p2%20physics&f=load+polygon+1.js&t=load%20polygon%201 Link to comment Share on other sites More sharing options...
Puzz3l Posted April 28, 2014 Author Share Posted April 28, 2014 It only seems to happen when I run into world bounds; it that useful? EDIT: The specific code I use, could it be because I'm using an arcade function of a P2 body?this.arrow.body.rotation = game.physics.arcade.angleToPointer(this.arrow); Link to comment Share on other sites More sharing options...
george Posted April 28, 2014 Share Posted April 28, 2014 Never ever mix physics! In this case it's not really that you use a arcade method. It look only like a helper method. But you're overwriting the rotation.So it's basically ignoring the p2 rotation. Remove it and you will see it works. If you want the ship to rotate in the direction of the pointer you have to use the property 'angularVelocity' or use the helper method rotateLeft & rotateRight on the body. You can calculate what's needed to rotate to a desired angle with that basic formula (in game#update )//that's the value which is missing to get to the desired angle//targetAngle would be the result of angleToPointer, currentAngle is the current rotation.deltaAngle = (targetAngle - currentAngle) //You could apply the full difference with rotateRight.//You don't need rotateLeft as this is done by passing negative values (or maybe you have to use rotateLeft.sprite.body.rotate.rotateRight(deltaAngle) //you could also use only a fraction of it so it's not a little bit lagging. Sometimes a desired effect.sprite.body.rotate.rotateRight(deltaAngle * 0.1)I hope that helps and works!Regards George Link to comment Share on other sites More sharing options...
Puzz3l Posted April 28, 2014 Author Share Posted April 28, 2014 There is no sprite.body.rotate.rotateRight() method, but there is a sprite.body.rotateRight(). Unfortunately it's giving worse results than before... Trying to figure out why atm. EDIT:I also don't understand why setting rotation directly is so bad; I'm not too concerned about complete accuracy of collisions, I just need the hitboxes to work and the sprite to line up with the body. Why doesn't this work?this.arrow.body.rotation = game.physics.arcade.angleToPointer(this.arrow);this.arrow.angle = (180/Math.PI) * this.arrow.body.rotation; Link to comment Share on other sites More sharing options...
george Posted April 29, 2014 Share Posted April 29, 2014 Sorry for the typo with 'body.rotate'. That tool is the right one but your solution is also nearly working.You have three possibilities:1. Set body to fixedRotation (body.fixedRotation = true). Now the rotation of the sprite is in your hands- but decoupled from the body- obviously not want you want.2. Update the rotation as you planned it. Simply do this: sprite.body.rotation = game.physics.arcade.angleToPointer(sprite) - Math.PI/2-Math.PI/2 is -90deg end normalize the value from Math.atan2 so that 0deg is the top of the sprite. The rotation you set here will be synced with the body later in the body update automatically. With a physic engine, you have to let the engine do the work. So never touch the rotation property of the sprite itself. Downside of this method: If you want to apply any other force to the rotation you have to calculate it yourself. That brings us to the angularVelocity method via rotateLeft/Right. 3. Rotate the sprite via a velocity value. The angular velocity. Here you have to calculate a little more, as the angle jumps when the phase of the angle changes. You won't notice it in example 2, as there are no substeps. This is the method I tested for you.function update() { //1. angleToPointer makes no assumption over our current angle- th thinks it's always 0 //2. so include the current rotation of our sprite in the expression //3. subtract Math.PI/2 as the angle of atan2 (which is sued by angleToPointer) is rotated by 90deg (this is Math.PI/2) //Result: Now we have a delta value that if applied directly to rotation would yield //in a value so that the sprites top center points to the mouse. deltaMouseRad = sprite.rotation - game.physics.arcade.angleToPointer(sprite) - Math.PI/2; //don't be confused. I want the P of 'Phaser' to point to the mouse so rotate it again by -90deg deltaMouseRad = deltaMouseRad - Math.PI/2 mod = Math.PI * 2 //modulo on float, works in js, means: clamp value to [-Math.PI*2,Math.PI*2] deltaMouseRad = deltaMouseRad % mod; //lets call it phase shift, angle would jump, lets fix it if (deltaMouseRad != deltaMouseRad % (mod/2) ) { deltaMouseRad = (deltaMouseRad < 0) ? deltaMouseRad + mod : deltaMouseRad - mod; } //speed is some factor to get the object faster to the target rotation. //remember we are wotking with the angle velocity and let the engine //rotate the body speed = 150 sprite.body.rotateLeft(speed * deltaMouseRad);}Here a fiddle of it. You can change the update method from update: update to update: updateSimple to watch the simple method mentioned in 2)http://jsfiddle.net/wvaJ3/1/ I only did this summary of this topic so I could verify what I thought. With a little more of endurance you should have found it yourself. Regards George Puzz3l and MishaShapo 2 Link to comment Share on other sites More sharing options...
Puzz3l Posted April 30, 2014 Author Share Posted April 30, 2014 Thanks! This works great. The only part I don't totally get isif (deltaMouseRad != deltaMouseRad % (mod/2) ) { deltaMouseRad = (deltaMouseRad < 0) ? deltaMouseRad + mod : deltaMouseRad - mod;}It seems like this further acts to limit the range of deltaMouseRad to [-Math.PI, Math.PI], correct? This keeps it from jumping as there is no need to turn 270 counterclockwise if you can just turn 90 clockwise. Link to comment Share on other sites More sharing options...
george Posted April 30, 2014 Share Posted April 30, 2014 You're correct. I spend quite some time on this formula by looking at the sine curve with my mind's eye and of course a lot of trial and error. It's much more clearer when using an if statement instead of that lazy ternary operator.if (delta > Math.PI){ //too far on the right, jump back at the same position on the previous phase delta = delta - Math.PI*2}else if (delta < Math.PI){ //too far on the left, jump back at the same position on the next phase delta = delta + Math.PI*2}Regards George MishaShapo 1 Link to comment Share on other sites More sharing options...
MishaShapo Posted June 11, 2015 Share Posted June 11, 2015 George, could you explain this line please? I really love your solution and I wish to understand it. deltaMouseRad = sprite.rotation - game.physics.arcade.angleToPointer(sprite) - Math.PI/2;Thank you very much! Link to comment Share on other sites More sharing options...
george Posted June 11, 2015 Share Posted June 11, 2015 Hey,notice the 'delta' in the variable name stands? Delta is the mathematical name for the difference of two numbers.So that line in question is basically: difference = currentRotation - newRotationwhere newRotation equals 'game.physics.arcade.angleToPointer(sprite) - Math.PI/2'and currentRotation is 'sprite.rotation'. If you add the calculated difference to the current rotation of the sprite, you would set the sprite instantly to the target angle (angle to the mouse pointer) you want to reach.But here that value is used to provide the correct direction for rotateLeft & rotateRight so you get a smooth transition calculated by the physics engine. You should read my comments in the code and fiddle with the given code example. Have fun.Regards George MishaShapo 1 Link to comment Share on other sites More sharing options...
FlashyGoblin Posted February 22, 2018 Share Posted February 22, 2018 This solution works great, @george. But what if we wanted the sprite to respond to a mouse drag while rotating? Sort of like a dial or knob that you can rotate and it locks to your cursor when you spin it. Even having momentum if you flick it fast and let go, like a roulette wheel. What would that look like? Link to comment Share on other sites More sharing options...
Recommended Posts