6

I am making a billiards game, so my gravity is set to zero and I apply impulse to make a cue ball move. Because there is no gravity, I use both, linear and angular damping to slow the balls down.

While the balls have some decent velocity, they slow down realistically. The problem start’s when they slowdown a lot and are about to stop but don’t actually stop for like 4-5 seconds, and that’s look’s very unrealistic.

One of the solutions that I thought was to check every frame the velocity of the ball and if it’s bellow some number (i.e. when the ball is about to stop), make it zero to stop the object. The problem with this approach is that I am making a multiplayer game, where two players can have a slightly different frame rate and thus making two simulations of the same shot inconsistent.

Can anyone think of any other solution?

André Puel
  • 8,741
  • 9
  • 52
  • 83
Alex
  • 129
  • 1
  • 1
  • 8
  • I am not sure if box2d support's it, but what you are looking for is friction. – André Puel Jan 19 '12 at 23:33
  • I thought of that too, but there is nothing under the ball to friction with. The balls can only collide with other balls or cushions but not with the table (i.e. table cloth, as they move only in x and y but not in z). – Alex Jan 19 '12 at 23:41
  • 1
    I think you should replace damping with a fixed force always opposite to the balls movement direction, the amount of force you may tune until you find something that is visually acceptable. – André Puel Jan 20 '12 at 00:14

3 Answers3

4

My guess is that you need non linear damping, so try to edit the linear damping value on every frame, with a formula based on the current speed.

Rui Campos
  • 453
  • 2
  • 11
  • The problem is that I don't want to do calculations on a frame basis as this could break multiplayer game (i.e. two players having slightly different frame rate would probably result in a different simulation of the same shot). – Alex Jan 20 '12 at 16:31
  • @Alex: If you don't use the fixed time step on both devices the simulation will differ a bit in any case. – Andrew Jan 20 '12 at 18:47
  • I'm not sure if I understood what you mean. I have tested my game on both, 60 FPS and 10 FPS (with the same shot velocity, position, etc, just changed FPS) and they provide exactly the same result (although it is much slower on 10 FPS). – Alex Jan 21 '12 at 02:17
  • What he is talking about is those vars which you pass to the box2d stepping method. They define how much you want to advance the physics world in time. You can define this based on the time between frames, resulting in a visually realistic behaviour all the time, or use a fixed time step and trust that it will always run at 60fps. If you choose the latter, you can then trust that the game will always be the same, even if slower on one side. Or you can use the best player's pc to be the only one simulating the physics, and synchronize by the network. – Rui Campos Jan 21 '12 at 13:20
3

Try to use linear damping parameter of b2Body:

body->SetLinearDamping(0.1f);
Andrew
  • 24,218
  • 13
  • 61
  • 90
  • 2
    I have done that, and while it works well when the velocity is big (i.e. slows down realistically), it looks weird when the balls are about to stop, but don't actually stop for like 5-10 seconds. I get this weird effect when you would think that the ball is about to stop but it just keeps sliding slightly for an awful lot of time, until it either hits a cushion or come's to sleep. I have tried adding angular dumping as well, which kind of helped, but it still takes long to stop at small velocity. – Alex Jan 20 '12 at 16:37
  • @Alex: You can try applying manually some external force in the opposite direction to the body's speed when it's speed is less then some value and set the speed to zero when it's less the some other predefined value – Andrew Jan 20 '12 at 18:46
  • 2
    Like I have mentioned, I am making a multiplayer game. From my understanding, having to mess with physics on a frame level will mess up the synchronization between two players as it it possible that they will have a slightly different frame rate. What I want to do is, say player 1 takes a shot, and sends shot specific data over to player 2, and then they both simulate the shot on their own. What you are saying sounds easy enough to implement, however I am worried that this will break the multiplayer game. – Alex Jan 21 '12 at 01:48
  • I am wondering if there is some tuning I can do to the engine it self so I don't have to worry about frame rate. Maybe modify some parameter that will just stop the object when it's velocity is under some value. I'm guessing that's what happens behind the scenes anyway, I just need to increase this "stopping" number somehow. – Alex Jan 21 '12 at 01:54
  • 3
    Alex: Offtopic, but your synchronisation is bad. It's not enough just to test a couple of time that the results of simulation are the same. They may look the same, but if frame rates were different - different calculations were made by the engine. So there is no guaranty the result will be the same and the difference will grow with time and complexity of the simulation. I think you should simulate physics only on one device and then transfer bodies positions/rotations to the other devices. Actually the second device have only to draw the results of simulation and should not even have a b2world – Andrew Jan 21 '12 at 07:09
  • it will be the same if he has a fixed time step. As long as he passes the turn, only when both players say that their scenario has reached a sleeping state on all bodies. (the slower pc will be slower to reach this state, but will reach the same) – Rui Campos Jan 21 '12 at 13:22
  • @Rui Campos: That's exactly what I have noticed. I use a fixed time step which is independent of frame rate, and both PC's that I run the same simulation with different FPS produced the same result, just the slower FPS machine took much longer to finish. That's why I believe if I don't mess with physics on the frame level, my synchronization will be fine across different machines with different FPS. Might be mistaken, but that's how I understand it. – Alex Jan 21 '12 at 13:51
  • Yes, as long as the time step is the same, its ok. And you can use my other answer, its ok if you edit the linear damping each frame, because the frames will the same on each computer, it will only take longer on one of them. The result is the same because the frames are the same. – Rui Campos Jan 21 '12 at 14:04
  • I see now what you mean. I was confused a bit about the frames and how they interact with the fixed time step, but I think I understand now. Thanks a lot everyone! – Alex Jan 21 '12 at 15:09
  • Using `setLinearDamping` will take forever to make your object velocity = 0.0, even after updating the velocity = 0.0, there's small amount of force here. I'm having the same trouble with @Alex making multipleplayer game. You can read my question here: http://stackoverflow.com/questions/39716111/cocos2dx-unable-to-set-velocity-0-0 – TomSawyer Sep 27 '16 at 06:42
2

If you are making a multi-player game you need a referee to make sure that there are no inconsistencies. Either a server that both clients connect to or one (or both) of the clients can be the host.

The important thing is that each shot is calculated and sent to both parties before it is shown. Since billiards is turn based. Each client can host their own shot and sent the result to be "replayed" in the opponents game instance. Also this means that latency shouldn't be too much of an issue so you can send frame by frame ball positions (although this is not optimal, it is the easiest to implement).

If you want something that you can use for connection without the hastle of setting up a server have a look at pubnub (http://www.pubnub.com/). Account set-up and development is free and it's relatively easy to set up.

Hope this helps! ^^

Goran
  • 677
  • 3
  • 22