2013-01-10 24 views
5

我需要您的幫助。 我正在安排一個腳本,可以在RPG遊戲中執行一個能力之前檢查各種情況。C#,Unity - 具有多個不同對象的單一功能

所有這些能力都屬於單獨的類(火球,治療,毒藥),都是從另一個抽象類(遠程能力,治療能力,DOT能力)派生而來的,這些都是抽象類(Ability)的父代。

爲了避免產生多種功能,來處理每一個能力:

void condition(Fireball f){//test}; 
void condition(Heal f){//test}; 
void condition(Poison f){//test}; 

我想創建一個函數調用,可以採取各種能力。

void condition(Ability f){//test} 

到目前爲止,我已經成功地創建了一個Fireball對象並將它傳遞給該函數。

Fireball _fire = new FireBall(); 
condition(_fire); 

void condition(Ability f){//test} 

在這裏,我可以訪問所有的能力類初始化的公共變量,但我不能訪問在派生類初始化公共變量(遠程能力,自愈能力,DOT能力)。

難道是我忘了什麼,或者我是否以錯誤的視角看待這個問題? (我不擅長利用繼承和抽象類。)

+0

經典的OOP多態/繼承問題:)想想一個解決方案既困難又有趣,它可以保持封裝並且具有舒適性。 +1。 – dreamzor

+0

這與Objective C有什麼關係? –

+0

對不起,我想我標記錯了。 –

回答

8

不知道條件函數的更多細節,您有兩個選項。

一,你可以這樣做

if (f.GetType() == typeof(FireBall)) 
{ 
    fireBall = (FireBall)f; 
    fireBall.FireTheFireBall(); 
} 
else if (f.GetType() == typeof(Heal)) 
... 

或者,你的能力能有一個抽象的激活方法,它要求所有派生類重載:

class Fireball 
{ 
    public override void Activate() 
    { 
     //do fireball specific things 
     this.FireTheFireBall(); 
    } 

    public void FireTheFireBall() {...}  
} 

class Heal 
{ 
    public override void Activate() 
    { 
     //do healing specific things 
     this.ApplyTheBandage(); 
    } 
    ... 
} 

abstract class Ability 
{ 
    public abstract void Activate(); 
} 

void condition(Ability f){ 
    f.Activate(); //runs the version of Activate of the derived class 
} 

那麼這適用於任何事情用Ability可以調用someAbility.Activate()並且派生類提供的實現將被執行。

你也應該研究一下接口,它們就像抽象類一樣。接口的好處是你可以實現多個接口,而你僅限於從一個基本的抽象類繼承。想想一個具有轉向和拉動功能的IKnob接口。你可能有一個Drawer類,它實現了IKnob,一個Door類,一個TrappedDoor類,它實現了Turn並激活了一個陷阱。一個球員走過來一個門,擊中它使用按鈕,你傳遞給open函數的對象,打開(IKnob旋鈕)

void Open(IKnob knob) 
{ 
    knob.Turn(); 
    knob.Pull(); 
} 

class TrappedDoor:IKnob,IMaterial,ISomethingElse,IHaveTheseOtherCapabilitiesAsWell 
{ 
    private bool TrapAlreadySprung{get;set;} 
    //more complex properties would allow traps to be attached either to the knob, or the door, such that in one case turning the knob activates the trap, and in the other, Pull activates the trap 
    public Turn() { 
    if(! TrapAlreadySprung) 
    { 
     MessageBox("You hit your head, now you're dead"); 
    } 
    } 
} 

有方法來檢查,如果事情有一個接口,因此,如果有些玩家走到一個物品上,試圖與之交談,你可以檢查物體是否具有ICanTalk接口,如果它確實接着調用object.GetReply(「Hello」)並且物體可以響應。所以,如果你願意的話,你可以談論門和石頭。您可以使用ICanTalk接口方法處理所有處理對話/顯示響應等問題的代碼,然後其他類可以實現ICanTalk,並且每個類都可以決定如何響應。這個概念被稱爲「分離問題」,並幫助您創建更多可重用的代碼。

重要的是你可以編寫一段代碼,一個算法,函數等,只能用於該接口,這樣一旦你得到代碼與接口一起工作,你就可以使用該接口任何類,並且該類可以利用預先存在的代碼。

I.e.你的condition函數,如果它接受了IAbility接口,那麼一旦你的代碼有效,那麼你創建的實現了IAbility的任何類都可以傳遞給條件函數。條件函數負責做任何它應該做的事情,而實現IAbility的類負責處理它實現的方法中的任何特定的內容。

當然,實現抽象類或接口的類必須實現所需的方法,所以有時候你可能會覺得你正在複製代碼。例如,如果您有類似TrappedDoor和Door的類,則TrappedDoor的行爲可能與普通Door類似,如果陷阱未設置/已經彈出。所以你可以在這種情況下繼承門,或者有一個私人的門屬性(稱爲「組合」)。如果陷阱已經彈出,那麼您可以調用基本Door類或私人Door屬性並調用.Turn,以便在陷阱未激活的情況下重新使用常規門的默認行爲。

Test if object implements interface

我個人主要使用的接口和組成,而不是繼承。不是那種可怕的繼承,但是繼承層次很快會變得非常複雜。

+0

謝謝你的回答。我不確定第二個建議是如何工作的,但我確實認爲第一個建議可能會起作用。 我會盡快研究它,我會回報:) –

+0

@Marc更新後展開第二個例子。 – AaronLS

+1

第二個例子看起來像我懷疑的更合理的想法:) :) –

相關問題