2010-04-22 35 views
3

我想實現某種「只是換了我」的遊戲引擎和問題的情節去的方式如下:C++遊戲設計及多態性問題

假設我有一個可呈現實體的一些抽象接口,例如IRenderable

而且它聲明的方式如下:

interface IRenderable { 
    // (...) 
    // Suppose that Backend is some abstract backend used 
    // for rendering, and it's implementation is not important 
    virtual void Render(Backend& backend) = 0; 
}; 

我在做什麼,現在是像類似聲明

class Ball : public IRenderable { 

    virtual void Render(Backend& backend) { 
    // Rendering implementation, that is specific for 
    // the Ball object 
    // (...) 
    } 
}; 

不同的類,然後一切都看起來不錯。我可以輕鬆地做類似std::vector<IRenderable*> items,推動在這個載體的一些項目,如new Ball(),然後撥打電話類同foreach (IRenderable* in items) { item->Render(backend); }

好吧,我想這是「多態」的方式,但如果我想有不同的類型是什麼對象在我的遊戲中,並有能力操縱他們的狀態,每個對象都可以通過它自己的界面進行操作?

我可以做類似

struct GameState { 
    Ball ball; 
    Bonus bonus; 
    // (...) 
}; 

,然後輕鬆地通過自己的方法改變對象的狀態,像ball.Move(...)bonus.Activate(...),其中Move(...)是具體的只有BallActivate(...) - 只爲Bonus實例。

但在這種情況下,我失去了編寫foreach IRenderable*的機會,僅僅是因爲我將這些球和獎金存儲爲其派生的基類的實例。而在這種情況下,渲染過程變成像

ball.Render(backend); 
bonus.Render(backend); 
// (...) 

很亂,因爲我們實際上失去了多態性這樣(沒有實際需要作出Render功能虛擬等

另一種方法是壞是指通過調用或dynamic_casttypeid東西向下轉型,以確定要處理的對象的類型,這看起來更糟糕,我和這也打破了這種「多態」的想法。

所以,我的問題是 - 是否存在某種(可能)替代方法來實現我想要做的事情,或者我的當前模式可以以某種方式修改,以便我實際存儲IRenderable*用於我的遊戲對象(以便我可以在其中每個對象上調用虛擬Render方法)同時保留輕鬆改變這些對象狀態的能力?

也許我做的事情從一開始絕對錯誤的,如果是的話,請指出來:)

提前感謝!

回答

1

我不是一個C++程序員,但希望人造代碼將有助於...

級渲染所具有的功能渲染

類動產從渲染繼承,也有諸如X,Y性能, z和功能,如移動

類球動產

繼承了現在你的遊戲狀態可以渲染對象的列表,並在時機成熟時,以渲染,它可以通過它們只是循環。

其他操作(如世界時鐘的勾號)可能會循環查找Moveable實例的對象並告訴它們更新。

如果您的獎金是可呈現的(我無法確定您的問題),那麼它可以繼承子類Collectable,其子類Moveable。

+0

有人知道一些有效的C++方法來通過這些Renderable項目來實現第二個循環,這隻會找到Movable對象的子集嗎? 要麼我很愚蠢或這隻能通過調用動態鑄造/ typeid /您自己的RTTI實施... 感謝回答:) – 2010-04-23 00:25:17

+1

@Kotti只是創建他們的另一個列表。例如。你有一個可移植的列表,一個Movables列表,一個收藏列表。然後,任何時候你想操作任何子集,只要遍歷適當的列表。 (再次 - 將Renderables添加到Renderable構造函數中的可渲染列表中。) – 2010-04-23 18:58:16

3

您將不同對象存儲爲類成員的事實不應妨礙您在IRenderable*向量中存儲指向它們的指針。

struct GameState { 
    Ball ball; 
    Bonus bonus; 
    vector<IRenderable*> m_items; 

    GameState() // constructor 
    { 
    m_items.push_back(&ball); 
    m_items.push_back(&bonus); 
    } 

}; 

這種方式,你也不必擔心m_items釋放的指針。當GameState被銷燬時,它們將被自動銷燬。

此外,你的foreach的語法是時髦的。

+0

看起來不錯,謝謝。類似於此的方式可以使用BOOST_FOREACH來完成。 – 2010-04-23 00:20:18

2

你真的應該在你的遊戲引擎中有獨立的子系統。一個用於渲染,另一個用於遊戲邏輯。您的圖形子系統應該有一個指向IRenderable對象的指針列表。你的遊戲邏輯子系統應該有另一個接口的對象列表。

現在,您可以很容易地擁有具有狀態但無法呈現等等的實體。你甚至可能有一個獨立的音頻子系統。這也應該有助於保持代碼清潔和模塊化。

+0

也許,但我認爲這通常會帶來很多頭痛,特別是在添加/刪除遊戲對象之後的IRenderable *指針同步等等。 我可能是錯的,可能應該試一試。 – 2010-04-23 00:27:54

+0

使用RAII(http://en.wikipedia.org/wiki/RAII)。在構造函數中註冊對象並將其移除析構函數。這將確保對象將正確註冊和註銷。 – bitc 2010-04-23 09:54:24

+0

順便說一句,可見的IRenderable對象每次刷新屏幕都會更新。遊戲邏輯應該獨立於每秒幀數並具有自己的刷新率。這是分開這些責任的另一個原因。 – bitc 2010-04-23 10:14:49