我正在尝试为游戏设计一些类,但我不确定我做得对。
我有两个类:Actor
和Building
。它们有几个子类:Policeman
、Fireman
和PoliceStation
、FireStation
。
我希望能够将所有这些项放在一个列表中,以便稍后进行迭代,所以我添加了一个基类:GameEntity
所以我有这个:
public abstract class GameEntity:
{
public GameEntity()
{
}
}
public class Actor: GameEntity
{
public int _speed;
public TileSprite _UI;
public Actor()
{
}
public bool CollidesWith(Vector2 pos)
{
//Do stuff here
}
public virtual void OnClick()
{
//Do stuff here
}
public void DoActing()
{
}
}
public class Policeman: Actor
{
public Policeman()
{
_speed = 10;
}
public override void OnClick()
{
//Do stuff
}
}
public class Building: GameEntity
{
public TileSprite _UI;
public Building()
{
}
public bool CollidesWith(Vector2 pos)
{
//Do stuff here
}
public virtual void OnClick()
{
//Do stuff here
}
public void DoBuilding()
{
}
}
public class PoliceStation: Building
{
public PoliceStation()
{
}
public override void OnClick()
{
//Do stuff
}
}
现在,我想能够做到这一点:
List<GameEntity> Entities = new List<GameEntity>();
Actor a1 = new PoliceMan();
Building b1 = new PoliceStation
Entities.Add(a1);
Entities.Add(b1);
foreach(GameEntity ent in Entities)
{
if (ent.CollidesWith(something))
{
ent.OnClick();
//If Actor then do
ent.DoActing();
//If Building then do
ent.DoBuilding();
}
}
现在,为了完成最后一点,我最好实现一个包含OnClick
和CollidesWith
的接口,还是可以通过继承来实现?如果是,我该怎么做?
干杯。
这只是给你一个想法,我想这正是你所需要的。
public interface IGameEntity
{
bool CollidesWith();
void OnClick();
void DoActing();
}
public class Actor : IGameEntity { //Interface implemented }
public class Building: IGameEntity { //Interface implemented }
public class Policeman: IGameEntity { //Interface implemented }
public class Fireman: IGameEntity { //Interface implemented }
public class FireStation: IGameEntity { //Interface implemented }
在您的客户端对象中,只需执行以下操作:
List<IGameEntity> entities = new List<IGameEntity>()
{
new Actor(),
new Building(),
new Policeman(),
new Fireman(),
new Fireman()
};
foreach (IGameEntity entity in entities)
{
entity.CollidesWith();
entity.OnClick();
entity.DoActing();
}
这里有很多方法。如果所有GameEntities都可以点击,那么你可以在基类中添加一个OnClick事件属性。
如果不是,那么我会有一个Interface IClick,然后在可点击的实体上实现它。
碰撞,取决于。建筑物不会移动,所以它们不会与任何东西碰撞,但它们可能会被碰撞,因此,例如,你可能想做一个损坏的rountine,这意味着一个被破坏的、例行的——也许是维修例行的。
没有正确的答案,但是三种代码气味将是一个没有任何内容的基类。
一个非常深刻的继承层次(在我的书中,两个以上的层次令人怀疑)因此,如果你开始看到GameEntity->BuildingEntity->ActiveBuildingEntity->RepairableBuildingEntity,你就会陷入更混乱的境地。
最重要的是,一个基类中有无所事事的方法,这些方法之所以存在,是因为您需要在某些子体中添加行为(覆盖)。
不要害怕有几个接口。IClick、ICollsion、IDamage、IRepair等。这比暗示建筑物会撞到汽车要好得多。
您可以这样做:
public interface IGameEntity
{
void OnClick();
bool CollidesWith(Vector2 pos);
void Do();
}
public abstract class Actor: IGameEntity
{
public int _speed;
public TileSprite _UI;
public virtual bool CollidesWith(Vector2 pos)
{
//Do stuff here
}
// can be marked virtual with implementation if you want a default
// this way base classes will be forced to implement their own implementation
public abstract void OnClick();
// can be marked virtual with implementation if you want a default
// this way base classes will be forced to implement their own implementation
public abstract void Do();
}
public class Policeman: Actor
{
public Policeman()
{
_speed = 10;
}
public override void OnClick()
{
//Do stuff
}
public override void Do()
{
//Do Acting for Police
}
}
public abstract class Building: IGameEntity
{
public TileSprite _UI;
public bool CollidesWith(Vector2 pos)
{
//Do stuff here
}
public abstract void OnClick();
public abstract void Do();
}
public class PoliceStation: Building
{
public PoliceStation()
{
}
public override void OnClick()
{
//Do stuff
}
public override void Do()
{
// Do Building
}
}
如果游戏实体只是一个接口,那么就没有必要把它变成一个抽象类。如果演员和建筑永远不能作为一个独立的物体存在,那么它们应该是抽象的。如果基类必须重写DoActing、DoBuilding和OnClick,则可以在actor和Building中将它们标记为抽象。
我遵循了norlesh的建议,只使用一个方法Do。你也可以让Actor和Building有自己的抽象方法,而IGameEntity没有Do。然后你会放一个if语句,检查每个对象是否都是builder类型,然后他们会运行build,如果是Actor类型,然后运行act。
我认为有一种方法的方式更好,因为你只需要消除一个步骤。从设计的角度来看,我不确定,但无论哪种方式对我来说都是一样的。
List<IGameEntity> Entities = new List<IGameEntity>();
Actor a1 = new PoliceMan();
Building b1 = new PoliceStation();
Entities.Add(a1);
Entities.Add(b1);
foreach(IGameEntity ent in Entities)
{
if (ent.CollidesWith(something))
{
ent.OnClick();
ent.Do();
}
}
将虚拟doStuff()
添加到GameEntity
并在子类中重写它,而不是使用像DoActing
和DoBuilding
这样的唯一方法名,然后从循环中调用它应该可以满足您的需要。