我對於C#XNA遊戲的架構決策有困難。C#:繼承,重寫和隱藏
世界中的基本實體,例如樹,殭屍或玩家被表示爲遊戲對象。每個遊戲對象至少由一個GameObjectController
,GameObjectModel
和GameObjectView
組成。
這三個足夠簡單的實體,如無生命的樹木或岩石。然而,當我試圖儘可能地保持功能性時,繼承開始變得笨拙。在句法上,我甚至不確定如何最好地實現我的目標。
這裏是GameObjectController
:
public class GameObjectController
{
protected GameObjectModel model;
protected GameObjectView view;
public GameObjectController(GameObjectManager gameObjectManager)
{
this.gameObjectManager = gameObjectManager;
model = new GameObjectModel(this);
view = new GameObjectView(this);
}
public GameObjectManager GameObjectManager
{
get
{
return gameObjectManager;
}
}
public virtual GameObjectView View
{
get
{
return view;
}
}
public virtual GameObjectModel Model
{
get
{
return model;
}
}
public virtual void Update(long tick)
{
}
}
我想指定的GameObjectController
每個子類都將有至少訪問的GameObjectView
和GameObjectModel
。如果子類使用這些類很好,但也許重寫更復雜的Update()
方法,我不希望他們必須複製代碼來生成這些依賴關係。因此,GameObjectController
構造函數將設置這些對象。
但是,有些對象確實想覆蓋模型和視圖。這就是麻煩進來
一些對象需要打,所以他們CombatantGameObjects
:
public class CombatantGameObject : GameObjectController
{
protected new readonly CombatantGameModel model;
public new virtual CombatantGameModel Model
{
get { return model; }
}
protected readonly CombatEngine combatEngine;
public CombatantGameObject(GameObjectManager gameObjectManager, CombatEngine combatEngine)
: base(gameObjectManager)
{
model = new CombatantGameModel(this);
this.combatEngine = combatEngine;
}
public override void Update(long tick)
{
if (model.Health <= 0)
{
gameObjectManager.RemoveFromWorld(this);
}
base.Update(tick);
}
}
還是蠻簡單的。我使用new
來隱藏實例變量是否正確?請注意,我在這裏分配CombatantObjectController.model
,即使已經設置了GameObjectController.Model
。而且,戰鬥員不需要任何特殊的查看功能,所以他們只需要離開GameObjectController.View
。
然後我回到PlayerController
,發現一個錯誤。
public class PlayerController : CombatantGameObject
{
private readonly IInputReader inputReader;
private new readonly PlayerModel model;
public new PlayerModel Model
{
get { return model; }
}
private float lastInventoryIndexAt;
private float lastThrowAt;
public PlayerController(GameObjectManager gameObjectManager, IInputReader inputReader, CombatEngine combatEngine)
: base(gameObjectManager, combatEngine)
{
this.inputReader = inputReader;
model = new PlayerModel(this);
Model.Health = Constants.PLAYER_HEALTH;
}
public override void Update(long tick)
{
if (Model.Health <= 0)
{
gameObjectManager.RemoveFromWorld(this);
for (int i = 0; i < 10; i++)
{
Debug.WriteLine("YOU DEAD SON!!!");
}
return;
}
UpdateFromInput(tick);
// ....
}
}
此行是執行的第一次,我得到一個空引用異常:
model.Body.ApplyImpulse(movementImpulse, model.Position);
model.Position
看model.Body
,這是空的。
這是他們被部署到世界前初始化GameObjects功能:
public void Initialize(GameObjectController controller, IDictionary<string, string> data, WorldState worldState)
{
controller.View.read(data);
controller.View.createSpriteAnimations(data, _assets);
controller.Model.read(data);
SetUpPhysics(controller,
worldState,
controller.Model.BoundingCircleRadius,
Single.Parse(data["x"]),
Single.Parse(data["y"]), bool.Parse(data["isBullet"]));
}
每個對象都爲GameObjectController
通過。這是否意味着如果對象真的是PlayerController
,controller.Model
將引用基地的GameObjectModel
而不是PlayerController
的覆蓋PlayerObjectModel
?
響應於RH:
這意味着現在要PlayerModel P,p.Model不等同於 ((CombatantGameObject)P)。型號,和 也不等同於 ((GameObjectController)p).Model。
這正是我不想要的。我想要:
PlayerController p;
p.Model == ((CombatantGameObject)p).Model
p.Model == ((GameObjectController)p).Model
我該怎麼做? override
?
答案是:更多的殭屍。一場比賽永遠不會有太多的殭屍。 – slugster 2010-04-08 03:32:33
謝謝 - 我已經用幾種方法更新了我的回覆,您可以繼續。在這種情況下,覆蓋不會是您的最佳選擇,因爲您實際上希望返回不同的_type_,從而賦予該屬性不同的簽名。 – 2010-04-08 18:26:43