2d game synchronising

Started by
4 comments, last by alparslan 18 years, 3 months ago
hi everyone, we are a couple of friends programming a 2d billard-like game, we have done the physics and trying to set-up the game rules but there is an annoying problem about synchronising :( assume we have 3 balls on the table and thus we have 3 seperate threads for each's move() function. they move smoothly since they have sleep() calls in each of thems move(). and we have a thread that runs checkcollision() which check collision for each ball like: void checkcollision() { while('at least one ball is moving') { if(ball1==ball2) //overloaded '==' to check collision between 2 objects { 'calculate new velocities 'set new velocities } else if(ball2==ball3) { //the same above } else if(ball3==ball1) { //the same above } } } the problem is that, this thread sucks CPU's whole power and the objects dont move sychronized after the collision. we thought of checking collision in the move() but that was not a good idea because if we do like that ball1 will check himself with ball2 while ball2 is already checking himself with ball1. one of the collisionchecks is waste and we have the same problem when drawing shapes as they move. the draw area should be refreshed after each dx the balls take and so we put a drawarea->refresh(); line for each iteration of the move functions and the same problem is that if two balls are moving there are two refreshes where one of them shouldnt be there and if there are more balls than 2-3 the screen starts to shake :S we thought of putting refresh in a seperate thread but that would either kill the CPU or cant catch the synchronosization of the ball's moves. as you can see all our problem is to be beginners :( how should we synchronise the events to make it run smoothly? can you hand a helpful stick for us? :) thanks
5EED422A7DB44521136C5E5A9A146D77
Advertisement
That is why most games just have on loop overall objects, draw everythin to hidden surface and than when all objects are rendered bring this surface to the display.

If you want to know more about mechanism to thread synchronisation read the following thread, there you find some stuff anf if you need more just ask:
Win32 Threads
Why are you doing a thread per ball? That's a very bad idea. No game does a thread per entity.
thx Sparhawk42, i get the idea but i guess its hard to implement it since we dont use a DC or something, we just do it over a form with simple shapes on borland C++ builder :S but i get the idea ;)

and DrEvil, this is our project and we are led by our teacher this way :S he asked us to open seperate threads for each ball's move function. if thats not the correct approach, can you please tell me alittle about how to think on this case, because seperate threads was a good idea for me :S

and incase it helps, let me give details on the work.
for visual stuff we have a button on a form and two shapes(circle).
we have a class name fubsy for balls:
class fubsy
{
public:
//get, set functions
//////
operator==(); //for collision-check
operator*(); //for collision-response
void Move();
void Stop();
private:
TShape *Me; //pointer to the shape on the form that represent this instance
Vector2d velocity;
double mass;
};

and on form load we create two fubsy objects representing two balls, and a single button on the form will work like that:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Ball1->setVelocity(Vector2d(-70,-90));
Ball2->setVelocity(Vector2d(60,80));
MoveAll();
}

moveall() opens threads for each ball and a thread for collisioncheck() and starts them at the same time.
void collisioncheck()
{
while('atleast one ball is moving')
{
if(ball1==ball2)
{
ball1*ball2; //* operator will stop the balls and set the new values but wont
//make them restart because they should be restarted via multithreading in this
//example :s
MoveAll();
break;
}}}

as * operator is called the balls will stop and balls' move threads will end,
calling MoveAll() will restart the threads for the balls whose new velocity values are set and "break;" will end the last thread from the old session of MoveAll();


thats all we could think :( dont hasitate to tell too much, we are fast-readers and fast-learners :)
5EED422A7DB44521136C5E5A9A146D77
1 thread for rendering, updating - basically everyting.

1 manager for updating physics. Let the balls register themselves in the manager,
and let the manager check for collisions (maybe not every frame, maybe every 16 ms/62.5 Hz or so, but that's another topic).

There's quite a lot approaches to this.
This is just something basic, I've wrapped up in my head while writing this, so there can be errors:

struct Ball{Vector3f position;Vector3f velocity;Vector3f color;};class PhysicsManager{public:void Register(Ball &ball);void Update(float dt); (dt = delta time);private:std::vector<Ball &> m_balls;};void PhysicsManager::Register(Ball &ball){m_balls.push_back(ball);};void PhysicsManager::Update(float dt){for (int a = 0; a < m_balls.size(); a++) // Iterate through all the registered ballsfor (int b = 0; b < m_balls.size(); b++) // Iterate through all the registered balls again to check collision againstif (a != b) // if it's not the same ballif (CheckCollision(m_balls[a], m_balls)) // check for collisionResolveCollision(m_balls[a], m_balls) // resolve collision}


Okay, that was a very basic example, but I hope you get the point. Here you'd just call PhysicsManager::Update once every frame to update the balls (all in one thread), and everything will be fine.
Killers don't end up in jailThey end up on a high-score!
ok thats simple but when to call move functions? i guess in update function, like m_balls[c].move(dt) just after manuplation the move to move the ball only for a dt, right?
5EED422A7DB44521136C5E5A9A146D77

This topic is closed to new replies.

Advertisement