6
\$\begingroup\$

I am building a pool game, and I want to make the cue rotate around the white ball.

Here is the live code:

http://199.26.84.223/nocol.html

Here is the code for the white ball:

balls = game.add.group();
balls.enableBody = true;
balls.physicsBodyType = Phaser.Physics.P2JS;
wball = balls.create(350, 240 , 'ballW');
wball.body.setCircle(15);
wball.body.setCollisionGroup(wballCollisionGroup);
wball.body.collides([wballCollisionGroup, ballsCollisionGroup , sidesCollisionGroup , holesCollisionGroup , playerCollisionGroup]);            
game.physics.p2.setImpactEvents(true);

Here is the code for the cue, which I call player:

    player = game.add.sprite( 0   , 0   , 'player');
    game.physics.p2.enable(player , true );
    player.enableBody = true;
    player.body.setCollisionGroup(playerCollisionGroup);
    player.body.setZeroVelocity();
    player.body.createBodyCallback(wball, ballHit , this);
    player.anchor.setTo(-0.5, 0.5);   
    player.pivot.x = wball.x +150;
    player.pivot.y = 0;

    player.body.x = wball.x  ;
    player.body.y = 240 ;

The problem is that all pivot or anchor does is change the sprite image position. I got the cue to appear in the right place by using both pivot/anchor and it seems to work fine... the cue was rotating around the ball, but after enabling debug mode here is what I saw:

Debug mode of the game

Basically only the position of the image has been changed but the sprite still rotates around the center which is the red part. If I run this code, the ball and cue are already colliding and the ball jumps around without player doing anything.

How can I rotate the cue around the ball without them colliding?

\$\endgroup\$
  • \$\begingroup\$ Well you know the ball's position. So what you can do is limit your math to having the ball as position 0,0,0 for the queue only. You then rotate around the origin. This is usually known as a frame of reference. stackoverflow.com/questions/8602408/… \$\endgroup\$ – moonshineTheleocat Oct 20 '15 at 6:06
1
\$\begingroup\$

I've never used Phaser but did a quick look at the documentation. The Achor.setTo you are using seems to only offset the texture, so it's not what you need.

I couldn't find any Vectors or Matrices in the docs but you should create a rotation matrix with the angle of the cue. Something like this:

var myMatrix = Matrix.RotationY(userDefinedAngle); 

Then with some vectors you can get the new cue position.

var offsetVector = Vector2(distanceToBall, 0);
var newpos = Vector2.Transform(offsetVector, myMatrix);

Now create a vector pointing to the ball from the cue position.

var direction = ballPos - newpos;
direction.normalize();

this direction vector is the one you apply when the player shoots, instead of just adding to x like you do today.

if (cursors.down.isDown )
{
    player.body.velocity += direction * someSpeedValue;

}

Please note that I have no idea if the methods or objects work like this but I would be very surprised if there weren't something similar in Phaser.

Edit.

PIXI.Matrix seems to be the objects you need, please look into that.

\$\endgroup\$
1
\$\begingroup\$

You are manipulating the sprite, but not the underlying body. The sprite affects the visual appearance while the body affects the physics behavior.


There are a number of ways you can fix this:

Quick hack: I am not sure if this will work and I recommend one of the other solutions, but this might get your desired result with the least amount of effort:

Each time you adjust the sprite with pivot and/or anchor, call setRectangleFromSprite() to realign the physics body with the new sprite position.

player.anchor.setTo(-0.5, 0.5);   
player.pivot.x = wball.x +150;
player.pivot.y = 0;
player.body.setRectangleFromSprite();
player.body.setCollisionGroup(playerCollisionGroup);  // setRectangleFromSprite() may reset the collision groups


Slightly more elegant solution: Takes advantage of the simple relationship between the cue stick and cue ball to avoid some hairy trigonometric math.

  • Keep using pivot and anchor to visually show the cue rotating/moving, but don't add a physics body to this sprite.
  • Handle the collision between the cue and the white ball by manually adding a force to wball.body based on the speed and orientation of the cue about the time they "hit."
  • Use wball.body.applyImpulse(...) or wball.body.applyImpulseLocal(...) depending on how you calculate the location of the collision (relative to the the world or the cue ball?)


Physically most accurate solution:

Instead of modifying player.anchor and player.pivot to move the cue stick, modify player.body. The sprite is automatically adjusted to move/rotate along with its physics body.

  • Instead of anchor, change player.body.x and player.body.y to alter the cue stick's position.
  • Instead of pivot, change player.body.angle or player.body.rotation to alter the cue stick's rotation.
  • Getting the cue stick to rotate around the ball will not be as simple as using anchor and pivot. It will require some trigonometric calculations to place the cue stick at an appropriate position and angle relative to the cue ball!
\$\endgroup\$
  • \$\begingroup\$ thanx , second option seems to be the best one , but here is the thing .. how can i get the impulse point based on the cue position ? the cue and the ball are already colliding it most be impossible the get some kind of angle between them \$\endgroup\$ – max Oct 16 '15 at 21:58
  • \$\begingroup\$ Don't use the position of the cue. Use the fact the collision happens on the stationary ball (which is a perfect circle). You already know the angle from the cue's orientation (might have to use some trig to get the actual angle). \$\endgroup\$ – Leftium Oct 18 '15 at 2:58
  • \$\begingroup\$ Just recalled some billiards knowledge that simplifies the impulse point: the point of collision with the cue does not really affect the angle of the cue ball, only its spin. So you can set the impulse point as the center of the cue ball. Anyways, your pool game currently only allows hitting the cue ball in the center, so there would be no spin. (If you want, you could manually add spin based on the offset of the cue stick.) \$\endgroup\$ – Leftium Oct 22 '15 at 2:46
0
\$\begingroup\$

If you make the x/y set to the sender of the white ball, and then add padding (not a lot, but enough to make it balance on the outside of the white ball). Or instead of padding, make the cue have a small area of unused space, just enough to make it balance on the outside of the white ball

\$\endgroup\$
0
\$\begingroup\$

As your sprite is in the desired position, you should try to define a collision body for it manually.

player.body.clearShapes();
player.body.addRectangle(300, 20, 0, -150); // trial an error the values
player.body.updateCollisionMask();

The addRectangle method takes the following parameters:

addRectangle(width, height, offsetX, offsetY, rotation)

See here.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.