游戏开发模式一:组件模式(Component)
軟件設計模式告訴我們,程序中不同的領域要保持隔離,也就是解耦。所以,我們不希望AI,物理引擎,渲染引擎,聲音引擎,還有其他的事情影響到彼此,不能把他們放到同一個類里。
下面是一個反例:
if (collidingWithFloor() && (getRenderState() != INVISIBLE)) {playSound(HIT_FLOOR); }如果有人要修改這段代碼,那么他就需要查看物理,繪圖,和聲音的代碼以保證不會出錯。更糟糕的情況是,你可能需要修改其他部分的代碼!
?
解決的辦法:
我們可以吧不同的領域分割城不同的組件,談后需要的時候持有這些組件的實例,例如?InputComponent。
?
再看一個難一點的例子:
Bjorn?有一個?update()方法每一幀被調用一次。它獲取determine來決定方向,談后他用物理引擎來處理位置,最后,它把Bj?rn繪制到屏幕上。可以看到這里其實只做了很少的事情,但是卻顯得很復雜。
?
分割不同的領域:
首先讓我們把input分離:
class InputComponent { public:void update(Bjorn& bjorn){switch (Controller::getJoystickDirection()){case DIR_LEFT: bjorn.velocity -= WALK_ACCELERATION; break;case DIR_RIGHT: bjorn.velocity += WALK_ACCELERATION; break;}}private:static const int WALK_ACCELERATION = 1; };Bjorn的變化:
然后我們把其他的組件都分離:
class PhysicsComponent { public:void update(Bjorn& bjorn, World& world){bjorn.x += bjorn.velocity;world.resolveCollision(volume_, bjorn.x, bjorn.y, bjorn.velocity);}private:Volume volume_; };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_; };
現在Bjorn變得很簡潔:
class Bjorn { public:int velocity;int x, y;virtual void update(World& world, Graphics& graphics){input_.update(*this);physics_.update(*this, world);graphics_.update(*this, graphics);}private:InputComponent input_;PhysicsComponent physics_;GraphicsComponent graphics_; };
現在我們已經把不同的組件都分開了,但是Bjorn依然知道這些行為的具體實現。我們將把我們的組件隱藏在借口背后,這樣就需要把InputComponent變成一個抽象類:
class InputComponent { public:virtual void update(Bjorn& bjorn) = 0; };然后實現它:
class PlayerInputComponent : public InputComponent { public:virtual void update(Bjorn& bjorn){switch (Controller::getJoystickDirection()){case DIR_LEFT: bjorn.velocity -= WALK_ACCELERATION; break;case DIR_RIGHT: bjorn.velocity += WALK_ACCELERATION; break;}}private:static const int WALK_ACCELERATION = 1; };我們將持有一個InputComponent的指針,
class Bjorn { public:int velocity;int x, y;Bjorn(InputComponent* input): input_(input){}virtual void update(World& world, Graphics& graphics){input_->update(*this);physics_.update(*this, world);graphics_.update(*this, graphics);}private:InputComponent* input_;PhysicsComponent physics_;GraphicsComponent graphics_; };現在我們可以傳入一個InputComponent來實例化Bjorn:
Bjorn* bjorn = new Bjorn(new PlayerInputComponent());來看看InputComponent的另一個實現:
class DemoInputComponent : public InputComponent { public:virtual void update(Bjorn& bjorn){// AI to automatically control Bjorn...} };
?
好了,最后讓我們看看最簡介的一般實現:
我們有兩個component:
class PhysicsComponent { public:virtual void update(GameObject& obj, World& world) = 0; };class GraphicsComponent { public:virtual void update(GameObject& obj, Graphics& graphics) = 0; };一個GameObject:
class GameObject { public:int velocity;int x, y;GameObject(InputComponent* input,PhysicsComponent* physics,GraphicsComponent* graphics): input_(input),physics_(physics),graphics_(graphics){}virtual void update(World& world, Graphics& graphics){input_->update(*this);physics_->update(*this, world);graphics_->update(*this, graphics);}private:InputComponent* input_;PhysicsComponent* physics_;GraphicsComponent* graphics_; };
?
?
?
?
?
?
轉載于:https://www.cnblogs.com/shangdahao/archive/2013/04/02/2995051.html
總結
以上是生活随笔為你收集整理的游戏开发模式一:组件模式(Component)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: XLSReadWriteII 4.00.
- 下一篇: 六、九大隐式对象(JSP的9大内置对象)