2011-08-02 107 views
3

我有一個關於如何處理這種類層次結構的問題。層次結構與遊戲有關,但我認爲它足以通過gamdev。我可以想象這種事偶爾會出現,所以我很好奇可能的解決方案如何處理類層次結構

我有一個名爲BaseCharacter的基類,它定義了我的遊戲中的一個角色。它包含所有基本統計數據,狀態效應持有者,事件等以具有基線字符。我的大部分遊戲邏輯都是在BaseCharacter的實體上進行操作,在必要時進行投射。

從那裏我繼承到一個人形生物類,它增加了必要的結構和方法來爲角色添加裝備(武器,護甲等),最後我有一個PlayableCharacter類,從類人生物吸入並添加了當前EXP,可配置能力結構等

因此類結構很簡單:

BaseCharacter --->人形---> PlayableCharacter

這種結構用於定義玩家身邊人物的偉大工程,但我可能會決定再改進一下結構。我必須能夠將「敵人」類添加到層次結構中。爲了滿足敵人的需求,我需要添加一些與EXP /點有關的數據結構/方法來打敗敵人,物品戰鬥表等。

問題是,我在哪裏添加這些結構?將它們添加到BaseCharacter似乎是一個糟糕的主意,因爲我基本上說每個角色都有一個敵方實體所需的方法/數據結構。我考慮開始一個單獨的類,最終會看起來像這樣:

BaseCharacter--->Humanoid--->PlayableCharacter 
      \---->Enemy--->EnemyHumanoid 

其中Enemy繼承自BaseCharacter。 EnemyHumanoid將添加與BaseCharacter-> Humanoid的繼承相同的一組方法/數據結構。這是有效的,但意味着我不能將敵人人型投入人型生物,儘管敵人人型符合人形生物的要求。這也增加了冗餘,因爲我有這兩個繼承添加完全相同的一組對象/方法。

然後使用名爲EnemyInterface一個單獨的類考慮,並與繼承層次是這樣結束:

BaseCharacter----->Humanoid----->PlayableCharacter 
    |     |     
    V     V     
    Enemy   EnemyHumanoid 

敵人EnemyHumanoid都實現EnemyInterface。但是,我現在失去了敵人< - >敵人人類關係。我應該在這裏使用多重不義行爲嗎? (有敵人和人型生物的敵人人形?)被認爲是壞形式?有沒有更合乎邏輯的方法來做到這一點?這裏的例子非常簡單,但如果我最終分裂我的類層次更多,它只會變得更加複雜。

任何幫助,將不勝感激

回答

1

這聽起來像你正在使用繼承重用,而不是堅持LSP(http://en.wikipedia.org/wiki/Liskov_substitution_principle),這是通向地獄。

我的一般建議是隻爲is-a關係使用繼承。也就是說,你可以將一種類型替換爲另一種類型。對於大多數解決方案,我更喜歡組合來繼承,因爲我發現它更簡單。

在您的具體情況下,爲什麼考慮敵人與PlayableCharacter不同?考慮在類階層以外的地方使用EXP和Loot表,你可以將一個Humanoid傳遞給它並分別計算這些項目。

C++是一種多範式語言。您不必侷限於OO解決方案。

祝你好運!

1

這可能是怎麼回事?

BaseCharacter----->Humanoid----->PlayableCharacter 
        /\     
        / \     
       Enemy  EnemyHumanoid 

EnemyHumanoid可能只需要Humanoid的某些功能。

0

需要考慮的問題是Humanoid實例是否需要轉換爲BaseCharacter實例。你可能會發現它實際上沒有。你真的需要迭代所有人形字符集嗎?

如果是這樣定義:

Humanoid 

BaseCharacter->PlayableCharacter (contains Humanoid) 
      \---->Enemy---->EnemyHumanoid (contains Humanoid) 

[你可能要考慮制定一個定義具體EnemyNonhumanoid敵人摘要]

另一種方法是定義人形作爲接口,並提供getHumanoid( )方法在PlayableCharacter和EnemyHumanoid上實現,作爲每種情況下的句柄。

2

而不是重新安排您的類層次結構來解決這個特定問題(請參閱StackUnderblow的答案以瞭解如何執行此操作)我建議您對基於組件的體系結構進行一些研究。基本上,不是有一個描述使PlayableCharacter獨特的東西的類,而是將一個組件(或一組組件)嫁接到某種基本容器上。

這種方法要靈活得多,而且隨着設計的發展將更容易重構。例如,如果你有一些特定的敵人和人類應該能夠訪問的特性,那麼你必須將系統鉤子添加到你的基類中,向不能使用該特徵的敵人引入開銷。這是描述一個簡單問題的很多詞語,但隨着遊戲的發展,你會一再地遇到問題。

Here是一個很好的SO討論,擴展了我的建議。

Bheeshmar是對的,你是在地獄的路上!

1

你試圖繼承根據多個方面(錯了,我不知道「縱橫」在這裏是正確的話,我不是以英語爲母語,對不起),即你的BaseCharacter類:

  • 表 - 仿人/動物/等
  • 對齊 - 敵人/朋友/等

這總是會導致問題,因爲你已經觀察到:遲早你會想創建類它應該繼承自BaseCharacter的多個子類(通常來自每個aspec的一個子類) t類),例如。人形+敵人。在這種情況下,您要麼使用多重繼承(由於實現問題,不推薦在C++中使用),要麼需要重新設計代碼。

通常最好的解決方案是根據前面指出的方面分割對象。例如。在一個BaseCharacter對象中,你可以有兩個指針,一個CharacterForm *和一個CharacterAlignment *。然後你可以繼承CharacterForm(如HumanoidForm,AnimalForm等)和CharacterAlignment(EnemyAlignment,FriendAlignment等)。),並根據需要進行組合。

請注意,這種方法確實是朝着基於組件的設計邁出的第一步,正如Dan O所建議的那樣。

你需要做的每一次類似東西,你發現自己創建一個子類,這是它的基地在不同的感覺比以前的子類(如一個子類創建人形和動物,你需要敵人後 - >這顯然是對BaseCharacters進行分類的另一種方式)。根據經驗法則,每個類別只應根據一個方面而成爲子類別。

0

這個怎麼樣?

BaseCharacter

IBehaviour是接口

HumanoidBehaviour被執行IBehaviour

BaseCharacter包含IBehaviour

Enemy繼承BaseCharacter,並且包含HumanoidBehaviour

PlayableCharacter繼承BaseCharacter,並且包含HumanoidBehaviour

所以在邏輯上我們會得到:Enemy是,一個BaseCharacter已經-A行爲HumanoidBehaviour

可能Strategy design pattern將有助於在這裏 也有funny book,有一個很好的例子)