{Programação de Jogos}
Bruno Cicanci @ TDC SP 2015
{Design Patterns}
● Command
● Flyweight
● Observer
● Prototype
● States
● Singleton
{Command: Problema}
void InputHandler::handleInput()
{
if (isPressed(BUTTON_X)) jump();
else if (isPressed(BUTTON_Y)) fireGun();
else if (isPressed(BUTTON_A)) swapWeapon();
else if (isPressed(BUTTON_B)) reloadWeapon();
}
http://gameprogrammingpatterns.com/command.html
{Command: Solução}
class Command
{
public:
virtual ~Command() {}
virtual void execute() = 0;
};
class JumpCommand : public Command
{
public:
virtual void execute() { jump(); }
};
void InputHandler::handleInput()
{
if (isPressed(BUTTON_X))
buttonX_->execute();
else if (isPressed(BUTTON_Y))
buttonY_->execute();
else if (isPressed(BUTTON_A))
buttonA_->execute();
else if (isPressed(BUTTON_B))
buttonB_->execute();
}
http://gameprogrammingpatterns.com/command.html
{Command: Uso}
● Input
● Undo
● Redo
{Flyweight: Problema}
class Tree
{
private:
Mesh mesh_;
Texture bark_;
Texture leaves_;
Vector position_;
double height_;
double thickness_;
Color barkTint_;
Color leafTint_;
};
http://gameprogrammingpatterns.com/flyweight.html
{Flyweight: Solução}
class TreeModel
{
private:
Mesh mesh_;
Texture bark_;
Texture leaves_;
};
class Tree
{
private:
TreeModel* model_;
Vector position_;
double height_;
double thickness_;
Color barkTint_;
Color leafTint_;
};
http://gameprogrammingpatterns.com/flyweight.html
{Flyweight: Uso}
● Milhares de instâncias
● Tile maps
{Observer: Problema}
void Physics::updateEntity(Entity& entity)
{
bool wasOnSurface = entity.isOnSurface();
entity.accelerate(GRAVITY);
entity.update();
if (wasOnSurface && !entity.isOnSurface())
{
notify(entity, EVENT_START_FALL);
}
}
http://gameprogrammingpatterns.com/observer.html
{Observer: Solução parte 1}
class Observer
{
public:
virtual ~Observer() {}
virtual void onNotify(const Entity& entity, Event event) = 0;
};
class Achievements : public Observer
{
public:
virtual void onNotify(const Entity& entity, Event event)
{
switch (event)
{
case EVENT_ENTITY_FELL:
if (entity.isHero() && heroIsOnBridge_)
{
unlock(ACHIEVEMENT_FELL_OFF_BRIDGE);
}
break;
}
}
}; http://gameprogrammingpatterns.com/observer.html
{Observer: Solução parte 2}
class Subject
{
private:
Observer* observers_[MAX_OBSERVERS];
int numObservers_;
protected:
void notify(const Entity& entity, Event event)
{
for (int i = 0; i < numObservers_; i++)
{
observers_[i]->onNotify(entity, event);
}
}
};
class Physics : public Subject
{
public:
void updateEntity(Entity& entity);
};
http://gameprogrammingpatterns.com/observer.html
{Observer: Uso}
● Achievements
● Efeitos sonoros / visuais
● Eventos
● Mensagens
● Expirar demo
● Callback async
{Prototype: Problema}
class Monster
{
// Stuff...
};
class Ghost : public Monster {};
class Demon : public Monster {};
class Sorcerer : public Monster {};
http://gameprogrammingpatterns.com/prototype.html
class Spawner
{
public:
virtual ~Spawner() {}
virtual Monster* spawnMonster() = 0;
};
class GhostSpawner : public Spawner
{
public:
virtual Monster* spawnMonster()
{
return new Ghost();
}
};
{Prototype: Solução parte 1}
class Monster
{
public:
virtual ~Monster() {}
virtual Monster* clone() = 0;
// Other stuff...
};
http://gameprogrammingpatterns.com/prototype.html
class Ghost : public Monster {
public:
Ghost(int health, int speed)
: health_(health),
speed_(speed)
{}
virtual Monster* clone()
{
return new Ghost(health_, speed_);
}
private:
int health_;
int speed_;
};
{Prototype: Solução parte 2}
class Spawner
{
public:
Spawner(Monster* prototype)
: prototype_(prototype)
{}
Monster* spawnMonster()
{
return prototype_->clone();
}
private:
Monster* prototype_;
}; http://gameprogrammingpatterns.com/prototype.html
{Prototype: Uso}
● Spawner
● Tiros
● Loot
{States: Problema}
void Heroine::handleInput(Input input)
{
if (input == PRESS_B)
{
if (!isJumping_ && !isDucking_)
{
// Jump...
}
}
else if (input == PRESS_DOWN)
{
if (!isJumping_)
{
isDucking_ = true;
}
} http://gameprogrammingpatterns.com/state.html
else if (input == RELEASE_DOWN)
{
if (isDucking_)
{
isDucking_ = false;
}
}
}
{States: Solução}
void Heroine::handleInput(Input input)
{
switch (state_)
{
case STATE_STANDING:
if (input == PRESS_B)
{
state_ = STATE_JUMPING;
}
else if (input == PRESS_DOWN)
{
state_ = STATE_DUCKING;
}
break;
http://gameprogrammingpatterns.com/state.html
case STATE_JUMPING:
if (input == PRESS_DOWN)
{
state_ = STATE_DIVING;
}
break;
case STATE_DUCKING:
if (input == RELEASE_DOWN)
{
state_ = STATE_STANDING;
}
break;
}
}
{States: Uso}
● Controle de animação
● Fluxo de telas
● Movimento do personagem
{Singleton: Problema}
“Garante que uma classe tenha somente uma instância
E fornecer um ponto global de acesso para ela”
Gang of Four, Design Patterns
{Singleton: Solução}
class FileSystem
{
public:
static FileSystem& instance()
{
if (instance_ == NULL) instance_ = new FileSystem();
return *instance_;
}
private:
FileSystem() {}
static FileSystem* instance_;
};
http://gameprogrammingpatterns.com/singleton.html
{Singleton: Uso}
“Friends don’t let friends create singletons”
Robert Nystrom, Game Programming Patterns
{Outros Design Patterns}
Double Buffer
Game Loop
Update Method
Bytecode
Subclass Sandbox
Type Object
Component
Event Queue
Service Locator
Data Locality
Dirty Flag
Object Pool
Spatial Partition
{Livro: Game Programming Patterns}
http://gameprogrammingpatterns.com
{Outros livros}
Física
Physics for Game Developers
Computação Gráfica
3D Math Primer for Graphics and Game
Game Design
Game Design Workshop
Level Up! The Guide to Great Game Design
Produção
The Game Production Handbook
Agile Game Development with Scrum
Programação
Code Complete
Clean Code
Programação de Jogos
Game Programming Patterns
Game Programming Algorithms and Techniques
Game Coding Complete
Inteligência Artificial
Programming Game AI by Example
{Blog: gamedeveloper.com.br}
{Obrigado}
E-mail: bruno@gamedeveloper.com.br
Twitter: @cicanci
PSN: cicanci42

Programação de Jogos - Design Patterns

  • 1.
    {Programação de Jogos} BrunoCicanci @ TDC SP 2015
  • 2.
    {Design Patterns} ● Command ●Flyweight ● Observer ● Prototype ● States ● Singleton
  • 3.
    {Command: Problema} void InputHandler::handleInput() { if(isPressed(BUTTON_X)) jump(); else if (isPressed(BUTTON_Y)) fireGun(); else if (isPressed(BUTTON_A)) swapWeapon(); else if (isPressed(BUTTON_B)) reloadWeapon(); } http://gameprogrammingpatterns.com/command.html
  • 4.
    {Command: Solução} class Command { public: virtual~Command() {} virtual void execute() = 0; }; class JumpCommand : public Command { public: virtual void execute() { jump(); } }; void InputHandler::handleInput() { if (isPressed(BUTTON_X)) buttonX_->execute(); else if (isPressed(BUTTON_Y)) buttonY_->execute(); else if (isPressed(BUTTON_A)) buttonA_->execute(); else if (isPressed(BUTTON_B)) buttonB_->execute(); } http://gameprogrammingpatterns.com/command.html
  • 5.
  • 6.
    {Flyweight: Problema} class Tree { private: Meshmesh_; Texture bark_; Texture leaves_; Vector position_; double height_; double thickness_; Color barkTint_; Color leafTint_; }; http://gameprogrammingpatterns.com/flyweight.html
  • 7.
    {Flyweight: Solução} class TreeModel { private: Meshmesh_; Texture bark_; Texture leaves_; }; class Tree { private: TreeModel* model_; Vector position_; double height_; double thickness_; Color barkTint_; Color leafTint_; }; http://gameprogrammingpatterns.com/flyweight.html
  • 8.
    {Flyweight: Uso} ● Milharesde instâncias ● Tile maps
  • 9.
    {Observer: Problema} void Physics::updateEntity(Entity&entity) { bool wasOnSurface = entity.isOnSurface(); entity.accelerate(GRAVITY); entity.update(); if (wasOnSurface && !entity.isOnSurface()) { notify(entity, EVENT_START_FALL); } } http://gameprogrammingpatterns.com/observer.html
  • 10.
    {Observer: Solução parte1} class Observer { public: virtual ~Observer() {} virtual void onNotify(const Entity& entity, Event event) = 0; }; class Achievements : public Observer { public: virtual void onNotify(const Entity& entity, Event event) { switch (event) { case EVENT_ENTITY_FELL: if (entity.isHero() && heroIsOnBridge_) { unlock(ACHIEVEMENT_FELL_OFF_BRIDGE); } break; } } }; http://gameprogrammingpatterns.com/observer.html
  • 11.
    {Observer: Solução parte2} class Subject { private: Observer* observers_[MAX_OBSERVERS]; int numObservers_; protected: void notify(const Entity& entity, Event event) { for (int i = 0; i < numObservers_; i++) { observers_[i]->onNotify(entity, event); } } }; class Physics : public Subject { public: void updateEntity(Entity& entity); }; http://gameprogrammingpatterns.com/observer.html
  • 12.
    {Observer: Uso} ● Achievements ●Efeitos sonoros / visuais ● Eventos ● Mensagens ● Expirar demo ● Callback async
  • 13.
    {Prototype: Problema} class Monster { //Stuff... }; class Ghost : public Monster {}; class Demon : public Monster {}; class Sorcerer : public Monster {}; http://gameprogrammingpatterns.com/prototype.html class Spawner { public: virtual ~Spawner() {} virtual Monster* spawnMonster() = 0; }; class GhostSpawner : public Spawner { public: virtual Monster* spawnMonster() { return new Ghost(); } };
  • 14.
    {Prototype: Solução parte1} class Monster { public: virtual ~Monster() {} virtual Monster* clone() = 0; // Other stuff... }; http://gameprogrammingpatterns.com/prototype.html class Ghost : public Monster { public: Ghost(int health, int speed) : health_(health), speed_(speed) {} virtual Monster* clone() { return new Ghost(health_, speed_); } private: int health_; int speed_; };
  • 15.
    {Prototype: Solução parte2} class Spawner { public: Spawner(Monster* prototype) : prototype_(prototype) {} Monster* spawnMonster() { return prototype_->clone(); } private: Monster* prototype_; }; http://gameprogrammingpatterns.com/prototype.html
  • 16.
  • 17.
    {States: Problema} void Heroine::handleInput(Inputinput) { if (input == PRESS_B) { if (!isJumping_ && !isDucking_) { // Jump... } } else if (input == PRESS_DOWN) { if (!isJumping_) { isDucking_ = true; } } http://gameprogrammingpatterns.com/state.html else if (input == RELEASE_DOWN) { if (isDucking_) { isDucking_ = false; } } }
  • 18.
    {States: Solução} void Heroine::handleInput(Inputinput) { switch (state_) { case STATE_STANDING: if (input == PRESS_B) { state_ = STATE_JUMPING; } else if (input == PRESS_DOWN) { state_ = STATE_DUCKING; } break; http://gameprogrammingpatterns.com/state.html case STATE_JUMPING: if (input == PRESS_DOWN) { state_ = STATE_DIVING; } break; case STATE_DUCKING: if (input == RELEASE_DOWN) { state_ = STATE_STANDING; } break; } }
  • 19.
    {States: Uso} ● Controlede animação ● Fluxo de telas ● Movimento do personagem
  • 20.
    {Singleton: Problema} “Garante queuma classe tenha somente uma instância E fornecer um ponto global de acesso para ela” Gang of Four, Design Patterns
  • 21.
    {Singleton: Solução} class FileSystem { public: staticFileSystem& instance() { if (instance_ == NULL) instance_ = new FileSystem(); return *instance_; } private: FileSystem() {} static FileSystem* instance_; }; http://gameprogrammingpatterns.com/singleton.html
  • 22.
    {Singleton: Uso} “Friends don’tlet friends create singletons” Robert Nystrom, Game Programming Patterns
  • 23.
    {Outros Design Patterns} DoubleBuffer Game Loop Update Method Bytecode Subclass Sandbox Type Object Component Event Queue Service Locator Data Locality Dirty Flag Object Pool Spatial Partition
  • 24.
    {Livro: Game ProgrammingPatterns} http://gameprogrammingpatterns.com
  • 25.
    {Outros livros} Física Physics forGame Developers Computação Gráfica 3D Math Primer for Graphics and Game Game Design Game Design Workshop Level Up! The Guide to Great Game Design Produção The Game Production Handbook Agile Game Development with Scrum Programação Code Complete Clean Code Programação de Jogos Game Programming Patterns Game Programming Algorithms and Techniques Game Coding Complete Inteligência Artificial Programming Game AI by Example
  • 26.
  • 27.