4.4. Moving Object Interaction

In a game we usually want the various moving objects to interact with each other (for example beads bounce off each other). This is easy to to implement that within the OnGameIdle() method. We can use the method TooClose() that has been used in the ButtonUp() method in Listing 1.3.C so that the following code would do the task.

// Listing A
void CGame::CheckPositions()
{
	for(int j=0; j < m_Nbounce-1; j++) {
		for(int i=j+1; i < m_Nbounce; i++) {
			if(m_bouncer[j].TooClose(&(m_bouncer[i])) == TRUE) {
				/* ... have beads bounce ... */
			}
		}
	}
}

void CGame::OnGameIdle()
{
	/* ... */
	CheckPositions();
	/* ... */
}

While this works fine when the beads move using idle time (the array of beads is directly accessible) it does not when using multithreading. The beads are still accessible (thread functions updates the bead array through the pointer passed as its argument) but if you implement this solution you will see that many bead encounters are missed. What is happening? The cause of the "misses" is that the idle time function is called when there are no messages waiting to be processed. Because each bead moves independently and asks for the screen to be repainted (DrawArea() statement in Listing 2.1.C) it may take a long time to call the idle time method and the meantime beads may have moved a lot.

The solution is to use another thread to monitor the beads. Here is the code.

// Listing B
UINT CGame::Monitor(LPVOID pParam)
{
	CGame *gp = (CGame *)pParam;
	while(gp->m_Monitor==TRUE) {
		gp->CheckPositions();
		::Sleep(50);
	}
	return 0;
}

Now checking of positions is done in parallel with all the other tasks rather than waiting for the message queue to be empty. Notice that we have added to the game object a variable m_Monitor that is set to TRUE before the monitor thread is started and to FALSE when we want to stop the monitor.

There is one last question when using threads for animation. What to do when we pause a game? The documentation of the MFC software contains functions such as SuspendThread() and ResumeThread(). It is tempting to try to use those, but it is risky for the reasons we discussed in Section 2.3. The best way to implement a pause is to terminate a thread, save the state of the object, and restart it later.

Previous Section Next Section