Design Programming Patterns - Dan Frost

Design Programming Patterns - Dan Frost

Sorry, the audio does not seem to be automatically starting when you go to a new slide. Youll have to press the play icon. (Move the cursor over the speaker icon to see the play icon.) Game Programming Patterns Update From the book by Robert Nystrom Much activity that takes place in a game has to be synchronized with the render cycle, so that one quantum of activity happens per frame. It doesnt work to move a character without regard to the frame rate. In this example, the skeleton moves (its x value changes), but the player doesnt see any movement:

while (true) { // Patrol right. for (double x = 0; x < 100; x++) { skeleton.setX(x); } // Patrol left. for (double x = 100; x > 0; x--) { skeleton.setX(x); } } Of course what we really want to do is move the skeleton once per frame: // Main game loop:

while (true) { if (patrollingLeft) { x--; if (x == 0) patrollingLeft = false; } else { x++; if (x == 100) patrollingLeft = true; } skeleton.setX(x); // Handle user input and render game...

} This works fine, so we keep going and put more stuff into the main loop: // Main game loop: while (true) { // Skeleton moving code from before... if (++leftStatueFrames == 90) { leftStatueFrames = 0; leftStatue.shootLightning(); } if (++rightStatueFrames == 80) { rightStatueFrames = 0; rightStatue.shootLightning();

} // Handle user input and render game... } You can tell this isnt trending towards code wed enjoy maintaining. Weve got an increasingly large pile of variables and imperative code all stuffed in the game loop, each handling one specific entity in the game. To get them all up and running at the same time, weve mushed their code together. The pattern to fix this: each entity in the game should encapsulate its own behavior. This will keep the game loop uncluttered and make it easy to add and remove entities. To do this, we need an abstraction layer, and we create that by defining an abstract update() method. The Update Pattern:

The game world maintains a collection of objects. Each object implements an update method that simulates one frame of the objects behavior. Each frame, the game updates every object in the collection by calling every objects update method. class Entity { public: Entity() : x_(0), y_(0) {} virtual ~Entity() {} virtual void update() = 0; double x() const { return x_; } double y() const { return y_; }

void setX(double x) { x_ = x; } void setY(double y) { y_ = y; } private: double x_; double y_; }; class World { public: World() : numEntities_(0) {} void gameLoop(); // body on next slide private: Entity* entities_[MAX_ENTITIES];

int numEntities_; }; void World::gameLoop() { while (true) { // Handle user input... // Update each entity. for (int i = 0; i < numEntities_; i++) { entities_[i]->update(); } // Physics and rendering... } }

Aside: This approach involves making a subclass of Entity for everything which has a different behavior in the game. Lots of subclassing often leads to problems. Instead, we could use the Component pattern (in the book, not discussed in class) or the Type Object pattern (discussed in class in January). For the purposes of simple exposition of the Update pattern, well use subclassing. class Skeleton : public Entity { public: Skeleton() : patrollingLeft_(false)

{} virtual void update() { if (patrollingLeft_) { setX(x() - 1); if (x() == 0) patrollingLeft_ = false; } else { setX(x() + 1); if (x() == 100) patrollingLeft_ = true; } }

private: bool patrollingLeft_; // field not local variable }; class Statue : public Entity { public: Statue(int delay) : frames_(0), delay_(delay) {} virtual void update() { if (++frames_ == delay_) { shootLightning();

// Reset the timer. frames_ = 0; } } private: int frames_; int delay_; void shootLightning() { // Shoot the lightning... } }; Its now much easier to add new entities to the game world because each one brings along everything it needs to take care of itself. Some wrinkles and options:

1. We can support variable time steps by passing an elapsed time parameter to the update() method. void Skeleton::update(double elapsed) 2. If some update() methods add to or remove from the object list, we need to handle this. Perhaps int numObjectsThisTurn = numObjects_; for (int i = 0; i < numObjectsThisTurn; i++) { objects_[i]->update(); } 3. Does it matter if A.update() is called before or after B.update()? If we want to control the order of update calls, we need to add some additional logic. 4. How are dormant (disabled, off-screen, invisible) Entity

objects handled? Maybe with an enabled flag; or put them into another list.

Recently Viewed Presentations

  • Management of Chronic Gastric Volvulus -

    Management of Chronic Gastric Volvulus -

    Management of Chronic Gastric Volvulus Kenny K Y Yuen ... 32% Abnormal attachments, adhesions, or bands - 9% Asplenism - 5% Small and large bowel malformations - 4% Pyloric stenosis - 2% Colonic distension - 1% Rectal atresia - 1%...
  • Poetry Analytic Strategies

    Poetry Analytic Strategies

    After reading a poem are you left lost & confused? Never fear! Here are some strategies out there to help you out. While there are many more out there than just these, (Which I will call "The Big Four of...
  • IT Major Incident Management Response and Communication A

    IT Major Incident Management Response and Communication A

    Early "Heads Up" Advisory to Hospital AC's (Administrative Coordinators). IT to provide Hospital Administration* with "head ups" alert if IT impact assessment suggests widespread or extended systems outage (analogous to weather "advisory")
  • Recreation, Leisure, and Society - USM Aquadro

    Recreation, Leisure, and Society - USM Aquadro

    Society. Group lives longer than individuals. New members acquired. United to system of action. Self-sufficient. Different societies=Dif Needs. Societydefined is an enduring and cooperating social group whose members have developed organized patterns of relationships through interactions with one another.. The...
  • Rx for Change

    Rx for Change

    Ask-Advise-Refer Brief Interventions for Assisting Dental Patients with Quitting
  • Cryptanalysis of Polar Bear - Universitetet i Bergen

    Cryptanalysis of Polar Bear - Universitetet i Bergen

    Outline Introduction Description of the Shannon Differential Properties of the f2 Function Fault Analysis Our Differential Distinguishing Attack Implementation Results Conclusion Introduction The Shannon stream cipher was proposed by Philip Hawkes et al. for Ecrypt/eStream competitive.
  • Scaling and Fault Tolerance for Distributed Messages in a ...

    Scaling and Fault Tolerance for Distributed Messages in a ...

    Scaling and Fault Tolerance for Distributed Messages in a Service and Streaming Architecture Hasan Bulut [email protected] Motivation Videoconferencing systems; AccessGrid, VRVS, H.323 based systems (i.e. Polycom) Streaming media; client-server architecture. Client has control over the stream.
  • The Gambia - Geog

    The Gambia - Geog

    In 1965 the Gambia became independent, and President Kairaba was finally able to hoise the Gambian flag. * * The colours of the Gambian flag: red = sun white = freedom blue = the River Gambia green = nature and...