Tervminták a valósidejű gyakorlatban
Forrás Ezeknek a diáknak a forrása a Game Programming Patterns című könyv Online elérhető a szerző oldaláról: http://gameprogrammingpatterns.com/contents.htm
Game Loop http://gameprogrammingpatterns.com/game-loop.htm
Célja Az alkalmazás előrehaladásának leválasztása a felhasználói inputról és a processzorok sebességéről
A minta A game loop a program működése alatt folyamatosan fut. Minden iteráció során blokkolás nélkül feldolgozza a felhasználói inputot, frissíti az alkalmazás állapotát és kirajzolja az aktuális állapotot. Az eltelt idő számontartásával a program futásának sebességét is vezérli.
A minta while (true) processinput(); update(); render();
Megvalósítás processinput update render wait
A minta cél FPS while (true) double start = getcurrenttime(); processinput(); update(); render(); sleep(start + MS_PER_FRAME - getcurrenttime());
A minta változó idő double lasttime = getcurrenttime(); while (true) double current = getcurrenttime(); double elapsed = current - lasttime; processinput(); update(elapsed); render(); lasttime = current;
A minta változó update double previous = getcurrenttime(); double lag = 0.0; while (true) double current = getcurrenttime(); double elapsed = current - previous; previous = current; lag += elapsed; processinput(); while (lag >= MS_PER_UPDATE) update(); lag -= MS_PER_UPDATE; render();
A minta változó update Figyeljünk arra, hogy a render két update közé érkezik Azaz magának a rendernek is képesnek kell válnia extrapolálni az aktuális állapotból (optimális esetben a következő irányában) Gyors tárgyaknál ez különösen fontos
Update http://gameprogrammingpatterns.com/update-method
Célja Független objektumok szimulálása azáltal, hogy a viselkedésük egy kisebb egységét dolgozzák fel egy adott lépésben
A minta A világ entitások gyűjteményét tartalmazza. Minden entitás megvalósít egy update eljárást, amivel saját viselkedésének egy lépését írja le. A világ minden frame-ben update-eli az összes entitást.
A probléma 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);
A probléma egyszerű megoldása Entity skeleton; bool patrollingleft = false; double x = 0; // Main game loop: while (true) if (patrollingleft) x--; if (--x == 0) patrollingleft = false; else if (++x == 100) patrollingleft = true; skeleton.setx(x); // Handle user input and render game...
A probléma egyszerű megoldása Entity skeleton; bool patrollingleft = false; double x = 0; // Main game loop: while (true) if (patrollingleft) x--; if (--x == 0) patrollingleft = false; else if (++x == 100) patrollingleft = true; skeleton.setx(x); El kellett tárolnunk az állapotot, hogy be tudjuk szüntetni és folytatni tudjuk a legutolsó állapotból a folyamatot! // Handle user input and render game...
A megoldás 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_; ;
A megoldás class World public: World() : numentities_(0) void gameloop(); private: Entity* entities_[max_entities]; int numentities_; ;
A megoldás void World::gameLoop() while (true) // Handle user input... // Update each entity. for (int i = 0; i < numentities_; i++) entities_[i]->update(); // Physics and rendering...
Komponens
A cél Egy entitás több rendszerrel is kapcsolatban lehessen anélkül, hogy ezeket a rendszereket magukat összekapcsolnánk az entitásban
A probléma Egy játékban egy karakter animálódik, hangokat ad ki, hálózaton küld adatok, inputot fogad stb. Ezeket a programban külön alrendszerek kezelik Ha a karakter osztályában ezek az alrendszerek mind include-olva lennének, akkor azok egymást is láthatnák Öröklődés most nem tud segíteni, mert nagyon gyakran gyémántok állnak elő
A minta Egyetlen entitás több rendszerrel is kapcsolatban áll. Minden egyes rendszerrel szembeni viselkedését egy komponens osztályban implementáljuk. Az entitás ezután lényegében csak a komponensek gyűjteménye lesz, feladata ezek menedzselése.
A probléma class Bjorn public: Bjorn() : velocity_(0), x_(0), y_(0) void update(world& world, Graphics& graphics); private: static const int WALK_ACCELERATION = 1; int velocity_; int x_, y_; Volume volume_; Sprite spritestand_; Sprite spritewalkleft_; Sprite spritewalkright_; ;
A probléma void Bjorn::update(World& world, Graphics& graphics) switch (Controller::getJoystickDirection()) case DIR_LEFT: velocity_ -= WALK_ACCELERATION; break; case DIR_RIGHT: velocity_ += WALK_ACCELERATION; break; x_ += velocity_; world.resolvecollision(volume_, x_, y_, velocity_); Sprite* sprite = &spritestand_; if (velocity_ < 0) sprite = &spritewalkleft_; else if (velocity_ > 0) sprite = &spritewalkright_; graphics.draw(*sprite, x_, y_);
A megoldás class GraphicsComponent public: void update(bjorn& bjorn, Graphics& graphics) Sprite* sprite = &spritestand_; if (bjorn.velocity < 0) sprite = &spritewalkleft_; else if (bjorn.velocity > 0) sprite = &spritewalkright_; graphics.draw(*sprite, bjorn.x, bjorn.y); private: Sprite spritestand_; Sprite spritewalkleft_; Sprite spritewalkright_; ;
Vigyázzunk while (!gameover) // Process AI. for (int i = 0; i < numentities; i++) entities[i]->ai()->update(); // Update physics. for (int i = 0; i < numentities; i++) entities[i]->physics()->update(); // Draw to screen. for (int i = 0; i < numentities; i++) entities[i]->render()->render(); // Other game loop machinery for timing...
Vigyázzunk while (!gameover) // Process AI. for (int i = 0; i < numentities; i++) aicomponents[i].update(); // Update physics. for (int i = 0; i < numentities; i++) physicscomponents[i].update(); // Draw to screen. for (int i = 0; i < numentities; i++) rendercomponents[i].render(); // Other game loop machinery for timing...
Vigyázzunk