Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (475)
Games in Android Showcase (106)
games submitted by our members
Games in WIP (530)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Phys2D Performing a Collision please need your help  (Read 5446 times)
0 Members and 1 Guest are viewing this topic.
Offline kapocris

Senior Newbie





« Posted 2009-12-06 18:26:05 »

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.
Offline h3ckboy

JGO Coder


Medals: 5



« Reply #1 - Posted 2009-12-06 18:52:16 »

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

JGO Coder


Medals: 12



« Reply #2 - Posted 2009-12-07 09:23:21 »

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.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline kapocris

Senior Newbie





« Reply #3 - Posted 2009-12-07 13:15:57 »

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.
Offline Bonbon-Chan

JGO Coder


Medals: 12



« Reply #4 - Posted 2009-12-07 14:12:01 »

I see your misstake  Grin

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.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #5 - Posted 2009-12-07 18:09:28 »

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?

See my work:
OTC Software
Offline Bonbon-Chan

JGO Coder


Medals: 12



« Reply #6 - Posted 2009-12-08 09:12:11 »

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.

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.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #7 - Posted 2009-12-09 16:59:46 »

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.

See my work:
OTC Software
Offline kapocris

Senior Newbie





« Reply #8 - Posted 2009-12-12 17:12:59 »

I see your misstake  Grin

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 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.  Sad


I'm so sorry to bother you, this little game is causing me much more trouble than I expected. Undecided


Thanks again both of you.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #9 - Posted 2009-12-13 00:24:27 »

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.

See my work:
OTC Software
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline kapocris

Senior Newbie





« Reply #10 - Posted 2009-12-13 12:41:35 »

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.

Offline h3ckboy

JGO Coder


Medals: 5



« Reply #11 - Posted 2009-12-13 14:44:29 »

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
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #12 - Posted 2009-12-13 19:36:58 »

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.


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:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
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.

See my work:
OTC Software
Offline Bonbon-Chan

JGO Coder


Medals: 12



« Reply #13 - Posted 2009-12-14 09:14:34 »

Ok back from a business trip  Grin

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 :
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
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.
Offline kapocris

Senior Newbie





« Reply #14 - Posted 2009-12-14 20:10:55 »

Finally some progress !   Grin 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.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #15 - Posted 2009-12-14 20:20:57 »

Finally some progress !   Grin 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.

See my work:
OTC Software
Offline Bonbon-Chan

JGO Coder


Medals: 12



« Reply #16 - Posted 2009-12-15 09:14:25 »

 Grin

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.

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.
Offline kapocris

Senior Newbie





« Reply #17 - Posted 2009-12-15 13:05:24 »

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.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #18 - Posted 2009-12-15 15:59:40 »

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.

See my work:
OTC Software
Offline Bonbon-Chan

JGO Coder


Medals: 12



« Reply #19 - Posted 2009-12-15 16:12:16 »

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.
Offline h3ckboy

JGO Coder


Medals: 5



« Reply #20 - Posted 2009-12-15 17:02:39 »

do you have the world.step() in your updating method or do you only do it whent he mouse is moved?

cause that would kinda make a difference Wink
Offline kapocris

Senior Newbie





« Reply #21 - Posted 2009-12-17 19:25:28 »

What I did is to add a temporary static body in the exact position the pointer is resting so that the puck crashes against it instead of going through it, also  I adjusted puck's dumping and the achieved effect is pretty realistic to me. When mouse moves again I delete the temporary body from the world. I know this solution is trash but hey...it works.

There's something that I still need to know : How do you know when a body is moving or not ?

Finally, I see some light at the end of the tunnel...
Offline h3ckboy

JGO Coder


Medals: 5



« Reply #22 - Posted 2009-12-17 19:49:13 »

chekc the api....

there is probably a getVelocity() somewhere in the body class.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11


Game Engineer


« Reply #23 - Posted 2009-12-18 17:51:43 »

What I did is to add a temporary static body in the exact position the pointer is resting so that the puck crashes against it instead of going through it, also  I adjusted puck's dumping and the achieved effect is pretty realistic to me. When mouse moves again I delete the temporary body from the world. I know this solution is trash but hey...it works.

There's something that I still need to know : How do you know when a body is moving or not ?

Finally, I see some light at the end of the tunnel...
Instead of deleting and recreating a body every time the mouse moves, why not directly change the position of the same body?

See my work:
OTC Software
Offline kapocris

Senior Newbie





« Reply #24 - Posted 2009-12-29 20:51:54 »

Instead of deleting and recreating a body every time the mouse moves, why not directly change the position of the same body?

Because It's like I'm teleporting the pusher around the world instead of actually moving it so it has a velocity....I figured it out...can't waste any more time on the physics...it works...that's what matters right? this is my first proyect, my professor is pushing me, deadline is pusing me...you know.

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

ctomni231 (32 views)
2014-07-18 06:55:21

Zero Volt (28 views)
2014-07-17 23:47:54

danieldean (24 views)
2014-07-17 23:41:23

MustardPeter (25 views)
2014-07-16 23:30:00

Cero (40 views)
2014-07-16 00:42:17

Riven (42 views)
2014-07-14 18:02:53

OpenGLShaders (29 views)
2014-07-14 16:23:47

Riven (29 views)
2014-07-14 11:51:35

quew8 (27 views)
2014-07-13 13:57:52

SHC (63 views)
2014-07-12 17:50:04
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!