Gdc09 Minimissile

11

Transcript of Gdc09 Minimissile

Page 1: Gdc09 Minimissile
Page 2: Gdc09 Minimissile

MiniGamesRebuilding Three Classic

Joe LinhoffEugene JarvisDarren Torpey

Page 3: Gdc09 Minimissile

Missile Command, 1980Atari

Page 4: Gdc09 Minimissile

Learning Objectives

dynamic object management with lists

C-style polymorphism screen to world, world

to screen coordinate

Page 5: Gdc09 Minimissile

Dynamic Objects

Don't know how many enemy missiles there will be at any time

Missiles can split (MIRVs)

Don't know how many player missiles there will be at any time

The static ways will not work

Lists are the backbone of game development

Doubly linked lists make it easy and quick to unlink nodes

Page 6: Gdc09 Minimissile

Dynamic Infrastructureinit body final

Good code construction requires guaranteed init and final

Init sets up all list heads

Final runs through & frees all lists

The lists 'own' the object write code such that only way to object is through

list; do not keep any other copies always test pointers before use generally: one owner for every resource

Page 7: Gdc09 Minimissile

Game Controller Class Owns Game Objects

Simplifies collisions and other multi-type operations

init is in constructor initializes all lists by

making them list heads final is in 'final'

zaps all remaining objects in lists

not destructor b/c we want more control

idea is to clean up after yourself

// JFL 13 Aug 08Game::Game(chr *name) : qeUpdateBase(name,0,GAMEID_GAME){ this->name = qeObjName(this->_oShared); LLMakeHead(&this->listOfGameThings); LLMakeHead(&this->listOfWorlds); LLMakeHead(&this->listOfBuildings); LLMakeHead(&this->listOfPlayers); LLMakeHead(&this->listOfBadGuys); LLMakeHead(&this->listOfPlayerProjs); LLMakeHead(&this->listOfBadGuyProjs);} // Game::Game()

// JFL 18 Aug 08void Game::final(){ // don't call directly, use objRemove() Game *game; if((game=Game::instance)) { gameZapList(&game->listOfBadGuyProjs); gameZapList(&game->listOfPlayerProjs); gameZapList(&game->listOfBadGuys); gameZapList(&game->listOfPlayers); gameZapList(&game->listOfBuildings); gameZapList(&game->listOfWorlds); gameZapList(&game->listOfGameThings); delete game; // free the C++ object Game::instance=0; // reset pointer }} // Game::final()

Page 8: Gdc09 Minimissile

Game Objects

Constructors must setup their own node LLMakeNode() here

part of init Destructor not

explicitly needed

// JFL 14 Aug 07World::World(chr *name){ szcpy(this->name,sizeof(this->name),name,0); LLMakeNode(this,GAMEID_WORLD); SET3(this->xyzMin,-110,0,0); SET3(this->xyzMax,110,200,0);} // World::World()

// JFL 14 Aug 07int World::draw(void){ qefnDrawGrid(50,10); qefnDrawAxes(1); return 0;} // World::draw()

Page 9: Gdc09 Minimissile

Owners Must Always Guarantee Cleanup

Game::final() runs through all the lists of objects it owns and zaps them after all the objects it owns are zapped, it deletes itself

and zeros its Singleton instance pointer not called directy, Game derives from qeUpdateBase

and call to objRemove() causes engine to call final() when it's safe

// JFL 18 Aug 08void Game::final(){ // don't call directly, use objRemove() Game *game; if((game=Game::instance)) { gameZapList(&game->listOfBadGuyProjs); gameZapList(&game->listOfPlayerProjs); gameZapList(&game->listOfBadGuys); gameZapList(&game->listOfPlayers); gameZapList(&game->listOfBuildings); gameZapList(&game->listOfWorlds); gameZapList(&game->listOfGameThings); delete game; // free the C++ object Game::instance=0; // reset pointer }} // Game::final()

Page 10: Gdc09 Minimissile

Zap & Zap List

Use while when unlinking

Zap unlink calls destructor frees memory 'zap' b/c it's

descriptive, short, not generally used, and cool

// JFL 25 Jan 09int gameZapList(LLNode *head){ LLNode *n; while((n=head->next)&&n->t) gameZap(n); return 1; // nonzero return assumed} // gameZapList()

// JFL 25 Jan 09int gameZap(LLNode *n){ // unlink the game object LLUnlink(n);

// call destructor for game objects switch(n->t) { case GAMEID_INPUT:((Input*)n)->~Input();break; case GAMEID_CAMERA:((Camera*)n)->~Camera();break; case GAMEID_HUD:((HUD*)n)->~HUD();break; case GAMEID_WORLD:((World*)n)->~World();break; case GAMEID_BUILDING:((Building*)n)->~Building();break; case GAMEID_PLAYER:((Player*)n)->~Player();break; case GAMEID_PROJ:((Proj*)n)->~Proj();break; case GAMEID_BADGUY:((BadGuy*)n)->~BadGuy();break; default: BRK(); // add handler for type } // switch

// free the memory delete (qe*)n;

return 1; // nonzero return assumed} // gameZap()

Page 11: Gdc09 Minimissile

Simple Doubly Linked C-Style Polymorphic Lists

Build class with list node first Unique type identifiers signal type Use static_cast<TYPE>(node) Scanning is easy

LLNode *n;BadGuy *bad;

for(n=this->listOfBadGuys.next;n->t;n=n->next){ if(n->t!=GAMEID_BADGUY) continue; bad=(BadGuy*)n; // handle bad guy } // for

Scan from any node forward or backward, skip list head

Use of continue to minimize nesting "Should" use static_cast<>()