Phys2D Performing a Collision please need your help

Ok, Hi all. This is my first post.

Phys2d lib is wonderful but there’s something that I couldnt manage yet. How to perform a collision ?

I know how to detect a collision when two bodies touch using Arbiter, Contact classes.
I can list the bodies, the point of collision, but how do I apply movement to body2 when body1 touches it ? I am making an “AirHockey” game.

This is my first attempt which of course does not work (I wouldnt be here asking for help, hehe)

I thought I could use static method collide but I think I am not invoking it the right way because nothing happens. Note that body1/body2 must be the pusher/puck (there are other bodies in the world, “the walls”).

public void detectsColision(){
Body body1 = null;
Body body2 = null;
ArbiterList arbs = world.getArbiters();
Arbiter arb = null;
if(arbs.size() > 0){
for(int i=0;i<arbs.size();i++){
arb = arbs.get(i);
int numContacts = arb.getNumContacts();
if(numContacts > 0){
Contact[] Contacts = arb.getContacts();

       Vector2f punto = (Vector2f)Contacts[0].getPosition();
        body1 = arb.getBody1();
        body2 = arb.getBody2();

System.out.println("BODY1: “+body1+” BODY2: "+body2);
if(body1.equals(this.puck) && body2.equals(this.pusher) ||
(body1.equals(this.pusher) && body2.equals(this.puck)))
Collide.collide(Contacts, this.puck, this.pusher,1000);
}
}
}

Also, the harder the collision, the higher the speed of the puck, I have no idea how to implement that.

I appreciate your help.

couldnt you just give the pusher force, and then that force will be transfered to the puck on contact?

I don’t really get what you want to do. When two bodies collide, Phys2D calculates forces to bump them back. You can play with mass and coef to change how bodies react from collision.

Now in your case, when you detect a collision (like you do), calculate the forces to push back body and apply them with the Body.setForce(float x,float y) method.

Thanks both of you for your responses. I’m going to explain myself better. I have two bodies in the world (besides the walls which represent the limits of the table).

The pusher: I set its position by invoking setPosition method every time a mouseEvent (mouseMoved) occurs. The method I posted above allows me to indentify when a collision between pusher-puck has occured and also the exact point of collision. When this happens, the pusher just drags the puck, it does not transmit a force at the point of collision so that the puck moves in the right direction.

Think of a pool game, when the stick hits a ball, the stick stays static after the impact while the ball is moved.

If I use the addForce method that you describe, when both bodies collide, the puck does not take the proper direction and the pusher starts moving aswell.

It’s obvious that I am missing something. Please if you just could give me a hand with this.

I see your misstake ;D

The Body.setPosition() method moves a body not like dragging it but like you teleport it : it doesn’t get a speed.

I see 2 solutions :

  • don’t use Phys2D collision schem to init the move. Detect manualy the collision (circle against circle is not difficult) then convert the mouse/body speed to initial speed or a force for the puck.
  • use Phys2D collision schem. Set pusher weight like 80000(g), the puck 250(g). Move the pusher with the Body.setForce() method. The problem of this method is the latency between the mouse move and the pusher move.

I would go solution 1 myself.

I don’t know if that’s the issue. If you use setPosition with Phys2D, Bonbon-Chan is right that you’re sort of breaking the system, but this really only turns the collision system from continuous to discrete. Wherever the pusher is, collision should result (if it exists). By directly moving it, you only eliminate the steps in between each position. If your position is updating frequently enough, however, then this should unnoticeable.

Either way the pusher should be a static body, and the puck shouldn’t.

Did you add both bodies to the world?

If I have understand his problem, the collision system works but the resulting speed after the collision is wrong since the pusher don’t have the expected speed before the collision.

Oh, on that I think you’re right. As I recall Phys2D just violently pushes things off each other if there is overlap.

In any case it’s unwise to directly set position in a physics-based environment, so you would indeed be better off if you dampen the velocity of the pusher a lot (give it a lot of friction) and then just apply velocity. If you do this, you can simulate direct setting of position without breaking your physics system.

I need to ask you a couple more questions, I’m still confused.

  • By manually detect the collision, this would be enough, right ?

Contact[] Contacts = arb.getContacts(); int x = (int) Contacts[0].getPosition().getX(); int y = (int) Contacts[0].getPosition().getY();

  • About the mouse speed, you mean that I need to capture the pusher’s center initial point/time (when mouse starts movement, the pusher’s center final point/time (when the pusher hits the puck), then calculate distance between them an divide it by time…that would be the speed right?

-Once I have collected all this info, what am I supposed to do? You said I needed to convert the mouse speed to a force for the puck but how? Simply using puck.addForce() does not produce the desired effect.

I get that I am teleporting the pusher instead of actually moving it so it transmits its speed to the puck. All I’m doing is calling puck.addForce() when a collision occurs, and then passing as coordinates contact.x and contact.y but of course the puck moves too fast, or too slow, sometimes it moves in the wrong direction. :frowning:

I’m so sorry to bother you, this little game is causing me much more trouble than I expected. :-\

Thanks again both of you.

You shouldn’t be doing the collision manually. Instead, you should just avoid moving the pusher instantly, and instead change its velocity.

To do that, give the pusher a lot of friction and change its velocity to match the change in mouse position. Then just hide the mouse so that instead of an exact 1:1 movement ratio, it will work more like in an fps (move the mouse left, the pusher moves left, move the mouse right, the pusher moves right). That should work much better.

Ok, I understand your perspective and I also think it should work better. However, here’s the problem.

I set a start position for the pusher. When mouse enters the board (which is a jPanel implementing a MouseMotionListener) mouseMoved event fires. So I capture new position for the mouse. Now that I’ve got it, How do I use it ? Directly passing it to pusher.adjustVelocity(e.getX(),e.getY()) method results in the pusher moving to the right. No matter the direction I move the mouse, the pusher will move to the right until it goes outside the board. So there’s the problem. As you said, if I move the mouse to the left, pusher should go to left but it goes to the right no matter what.

I understand that friction must be really high since the pusher can only move in half of the board, I don’t want it to cross the middle line or the goal, is that ok if I set it like setFriction(10000) ?

I appreciate so much your responses, this is a final project for one subject, so it is really important for me.

waht you need to do is check on what side the cursor is AFTER it has moved, and just move towards there.

I suppose you could use a 2d Vector

Yeah, that’s how you set the friction as I recall, but I also think I remember that using a value like 1000 for friction will be way too high. You might want to look into the docs or just experiment until you get a value that works, but start with like 0.5 and work your way up.

To get the change in mouse position, do this:


int lastMouseX, lastMouseY;


public void mouseMoved(MouseEvent e)
{
    int changeX = e.getX() - lastMouseX;
    int changeY = e.getY() - lastMouseY;

    //Note that I don't remember the exact method call for this.
    pusher.adjustVelocity(changeX, changeY);
}

You’re going to want to add to the velocity, not set it directly. That will look a little better.

Ok back from a business trip ;D

When I was speaking to do collision manually, it was to avoid all problem of latency between the pusher and the mouse (all depend if it is acceptable or not in your game). I was thinking of something like :



int lastMouseX, lastMouseY;
long lastTime;


public void mouseMoved(MouseEvent e)
{
    int px = e.getX();                  // px,py is the position of the pusher.
    int py = e.getY();                  // the pusher is NOT in the Phys2D world and is NOT a body
    long pt = e.getWhen();

    double dx = this.puck.getPosition().getX()-e.getX();
    double dy = this.puck.getPosition().getY()-e.geY();
    double l  = Math.sqrt(dx*dx+dy*dy);

    if(l < r_puck+r_pusher)
   { // Collision

      dx /= l;
      dy /= l;

      double mouse_speed_x = (double)(px-lastMouseX)/(double)(pt-lastTime);
      double mouse_speed_y = (double)(py-lastMouseY)/(double)(pt-lastTime);
   
      double speed = mouse_speed_x*dx+mouse_speed_y*dy; // mouse speed projection on direction

      double induce_speed_x = dx*speed*COEF; // COEF has to be determinated
      double induce_speed_y = dy*speed*COEF;

      puck.setSpeed(induce_speed_x,induce_speed_y); // If you are sure that puck do not have any speed
      puck.setForce(induce_speed_x,induce_speed_y); // Else
   }
   else
  {
     lastMouseX = px;
     lastMouseY = py;
     lastTime = pt;
  }
}

You can make it better. It can be use or not depending of your game. If pusher can only collide with puck, it can be a good solution.

Finally some progress ! ;D I want to thank Demonpants,h3ckboy and of course Bonbon-Chan, I hope you had a great trip.

The puck now moves in the right direction. I literally copied your solution, just made a couple of changes (like not allowing the pusher run across the puck, stuff like that). I was playing with it and it feels very realistic.

I still have some doubts, I’d be glad if you can give me ideas…remember this is my first game ever.

Suppose I hit the puck once and now it is moving in one direction. If I hit it for a second time in the exact opposite direction it will simply get stuck in one of the static rectangles I use as barriers. I mean, it gets inside of them.

I did like you said, if puck is moving apply force instead of adjusting velocity (I tried both methods anyways)

The same happens if I push the puck very fast, in that case it doesn’t matter if it is the first time the puck is being hit or not.

Some more data:

coef is set to 75
puck friction to 0
puck weight to 250

As I always say, any clue / information that you can give is very appreciated.

Really if you’re circumventing Phys2D in one place it’s possibly going to cause problems in another place - that’s just how it goes. You either have to use entirely Phys2D (in which case you don’t want to manually set anything, you want adjust everything), or you’re going to have to constantly write your own adjustments to Phys2D, until finally you’ve basically rewritten the whole engine. :wink:

Anyway, if you really want to try another hotfix, maybe you should just manually check for collision with the walls, and if it ever exists manually move the puck off the wall onto the correct side.

;D

[quote]The same happens if I push the puck very fast, in that case it doesn’t matter if it is the first time the puck is being hit or not.
[/quote]
When I use Phys2D, I have to pass a long trial&error course. First, I play with the frictions and weight to try to have the speeds that I want. Then I play with coef used in collision. And last, I play with the number of steps used by frame to avoid object to pass through another.

It can be a good idea to do several World.step() in one frame (you will have to decrease the speed of all objects). It lets Phys2D to do more accurate collision detections.

For friction, if you set 0 it is like “perfect ice” : your puck will never stop moving. As I remember, I allways use friction near 1 and very little change can do a big difference.

Ok guys, It’s done. It took me some time to find out the problem: “pt” and “lastTime” sometimes were equal, that means “mouse_speed_x” and “mouse_speed_y” were Infinity and that’s why the puck simply disappeared from the board when it was hit too fast.

The only problem is that if pusher is not moving collision will simply not be detected and the puck will go through it.

You could force it to always be moving by a very very tiny amount.

I think you problem is a more general problem on your game design. For dynamic games, I avoid using anything that deal with event.

For example when dealing with awt/swing, MouseEvent / KeyboardEvent only store mouse/keyboard state in a Mouse/Keyboard object. Then I deal with the input in the logic/rendering loop.

So in your case, I would test collision every frame and not only when an event occured.