6.3 The animation cascade

This section discusses how the CPopApp:animateAllDocs(dt) cascades its calls down to the simulation objects of each open document.

Sequence diagram of the animation

In this subsection we'll give a description of the animation process and then we'll draw a UML sequence diagram of it.

First let's write out in words a description of how the animation process works.

  • The CPopApp::OnIdle function makes a call to the CPopApp:animateAllDocs(dt).

  • The cPerformanceTimer tick() method returns the time dt elapsed since the prior update.

  • CPopApp:animateAllDocs(dt) steps through the list of open CPopDoc documents and for each of these documents calls a CPopDoc::stepDoc(dt) function.

  • Firstly, CPopDoc::stepDoc(dt) calls the cGame::step(dt) method for the game inside the CPopDoc.

  • cGame::step(dt) updates the positions and appearances of an array of critters stored inside the game.

  • Secondly, CPopDoc::stepDoc calls CPopDoc::UpdateAllViews.

  • This sends down a CPopView::OnUpdate to each of the document's views, and each view generates a call to CPopView::OnDraw.

  • The OnDraw methods use the cGraphics *_pgraphics member of the CPopView to draw an image of the game and to display it in the onscreen view window.

  • Any remaining messages in the Windows message queue are processed.

  • CPopApp::OnIdle is called again.

Let's draw a sequence diagram (Figure 6.3) showing some of these steps. As we mentioned in Chapter 5: Software Patterns, UML sequence diagrams are used to show how objects interact over time. The diagram is set up as a series of columns, with one column for each object. Each column has a vertical lifeline showing lifetime of the object. Arrows are drawn from lifeline to lifeline to symbolize the passing of messages via method calls. Use a dotted-line arrow if the caller isn't shown. We label a message with the name of a method being called, and this method is expected to be a member method of the class column that the message points to. A call that an object makes to itself is drawn as an arrow that starts and ends on the object's own lifeline.

Figure 6.3. Sequence diagram of the animation cascade


We can draw activation boxes to symbolize the time during which a given method is active, although if it gets to be too messy we can leave out the activation boxes. These boxes are sometimes called 'candlesticks', because they're long and thin.

A sequence diagram is supposed to show the behavior of objects. Although there is a class name at the top of each lifeline, the line really refers to a particular instance of the class in question.

Our sequence diagram leaves out details relating to the innards of cGame::step and CPopView::OnDraw.

One minor point about the diagram. Why does OnDraw appear down after the end of the animateAllDocs candlestick? This has to do with the way the Windows architecture works. When you want to redraw a view, as in the OnUpdate method, you place a message onto the Windows message queue that tells Windows to redraw the view whenever it's done doing whatever it's currently involved in. Thus Windows doesn't get around to executing the requested OnDraw until animateAllDocs is over.

The stepDoc method

The purpose of the animateAllDocs(dt) code is to find all the open documents and call their stepDoc(dt) methods. For details about how this works, you can look at Chapter 23: Programming Windows with MFC in Part II of this book.

The stepDoc(dt) method does two things: it tells the active game to update the critters, and it tells the views to draw a fresh image of the critters. Remember that in the Document-View architecture we separate out the values of the data from the view of the data. The document is a kind of bridge between the numbers being computed and the images used to represent them. In a nutshell, the CPopDoc::stepDoc looks like this.

void CPopDoc::stepDoc(Real dt) 
    _pgame->step(dt); /* Move the critters and maybe add or 
        delete some. */ 
    cTimeHint timehint(dt); /* Wrap dt up so we can pass it to the 
        views. */ 
    UpdateAllViews(NULL, 0, &timehint); /* Redraw all the views and 
        possibly move the views' _pcritterviewer according to the dt 
        inside timehint. */ 

We'll discuss the details of cGame::step(dt) in Chapter 10: Games. And we'll talk about UpdateAllViews in the next section.

    Part I: Software Engineering and Computer Games
    Part II: Software Engineering and Computer Games Reference