我最近开始使用Microsoft XNA和C#开发一款适合自己娱乐的小游戏.我的问题是关于设计游戏对象和继承游戏对象的对象.我将把游戏对象定义为可以在屏幕上呈现的东西.所以为此,我决定创建一个基类,其中所有其他需要渲染的对象都将继承,称为GameObject.下面的代码是我制作的课程:
class GameObject
{
private Model model = null;
private float scale = 1f;
private Vector3 position = Vector3.Zero;
private Vector3 rotation = Vector3.Zero;
private Vector3 velocity = Vector3.Zero;
private bool alive = false;
protected ContentManager content;
#region Constructors
public GameObject(ContentManager content, string modelResource)
{
this.content = content;
model = content.Load<Model>(modelResource);
}
public GameObject(ContentManager content, string modelResource, bool alive)
: this(content, modelResource)
{
this.alive = alive;
}
public GameObject(ContentManager content, string modelResource, bool alive, float scale)
: this(content, modelResource, alive)
{
this.scale = scale;
}
public GameObject(ContentManager content, string modelResource, bool alive, float scale, Vector3 position)
: this(content, modelResource, alive, scale)
{
this.position = position;
}
public GameObject(ContentManager content, string modelResource, bool alive, float scale, Vector3 position, Vector3 rotation)
: this(content, modelResource, alive, scale, position)
{
this.rotation = rotation;
}
public GameObject(ContentManager content, string modelResource, bool alive, float scale, Vector3 position, Vector3 rotation, Vector3 velocity)
: this(content, modelResource, alive, scale, position, rotation)
{
this.velocity = velocity;
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
我遗漏了额外的方法,例如旋转,移动和绘制对象.现在,如果我想创建另一个对象,比如船,我会创建一个Ship类,它将继承GameObject.示例代码如下:
class Ship : GameObject
{
private int num_missiles = 20; // the number of missiles this ship can have alive at any given time
private Missile[] missiles;
private float max_missile_distance = 3000f; // max distance a missile can be from the ship before it dies
#region Constructors
public Ship(ContentManager content, string modelResource)
: base(content, modelResource)
{
InitShip();
}
public Ship(ContentManager content, string modelResource , bool alive)
: base(content, modelResource, alive)
{
InitShip();
}
public Ship(ContentManager content, string modelResource, bool alive, float scale)
: base(content, modelResource, alive, scale)
{
InitShip();
}
public Ship(ContentManager content, string modelResource, bool alive, float scale, Vector3 position)
: base(content, modelResource, alive, scale, position)
{
InitShip();
}
public Ship(ContentManager content, string modelResource, bool alive, float scale, Vector3 position, Vector3 rotation)
: base(content, modelResource, alive, scale, position, rotation)
{
InitShip();
}
public Ship(ContentManager content, string modelResource, bool alive, float scale, Vector3 position, Vector3 rotation, Vector3 velocity)
: base(content, modelResource, alive, scale, position, rotation, velocity)
{
InitShip();
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
同样,我遗漏了任何额外的船舶特定方法,比如发射导弹.你认为这种设计是好还是应该以某种方式改进或完全改变?看起来子类的构造函数很乱,但也许这是唯一的方法.我从来没有做过这样的事情,我想知道我是否偏离轨道.
感谢大家留下了答案.他们都非常有帮助.似乎普遍认为改变它以使用MVC模式是最好的.我将进一步研究如何做到这一点.我还将删除大多数构造函数,并且只有一个构造函数,因为modelResource之后的所有参数都不是创建对象所必需的,并且稍后可以通过方法调用来更改它们.
就个人而言,我发现大量的构造函数你有一点点输出,但这是你的选择,没有任何根本错误:)
关于从共同基础派生游戏对象的一般策略,这是一种非常常见的做事方式.标准,均匀.我倾向于开始使用更类似于MVC的东西,其中包含仅包含数据的非常轻量级的"模型"游戏对象.
我在XNA中看到的其他常见方法包括/您可能需要考虑的事项:
再说一点,小点.你的设计很好.
构造函数的数量不仅是一个潜在的问题(特别是必须为每个派生类重新定义它们) - 但构造函数的参数数量可能会成为一个问题.即使您将可选参数设置为可空,也很难在以后读取和维护代码.
如果我写:
new Ship(content, "resource", true, null, null, null, null);
Run Code Online (Sandbox Code Playgroud)
第二个NULL做什么?
如果参数列表超出四个或五个参数,它会使代码更具可读性(但更详细)以保存参数:
GameObjectParams params(content, "resource");
params.IsAlive = true;
new Ship(params);
Run Code Online (Sandbox Code Playgroud)
有很多方法可以做到这一点.
既然你在问一个与设计相关的问题,我会尝试给出一些提示,而不是你发布的大量代码,因为其他人已经开始了.
游戏非常适合模型 - 视图 - 控制器模式.你明确地谈论了显示部分,但想一想:你在那里有矢量等,这通常是你建模的一部分.把游戏世界和那里的物体想象成模型.他们有一个位置,他们可能有速度和方向.这是MVC的模型部分.
我注意到你想让船开火.例如,您可能希望机械师在控制器类中进行发射,这需要键盘输入.此控制器类将消息发送到模型部分.一个声音很容易想到你可能想要的是在模型上有一些fireAction()方法.在您的基础模型上,这可能是一个可覆盖(虚拟,抽象)的方法.在船上它可能会给游戏世界添加一个"子弹".
看看我如何写了很多关于模型行为的文章,这里有另一件事给我带来了很多帮助:使用策略模式使类的行为可以交换.该策略模式,如果你认为AI和希望也很大行为在未来somewhen改变.你现在可能不知道,但是在一个月内你可能会想要弹道导弹作为默认导弹,如果你使用了策略模板,你可以在以后轻松改变它.
所以最终你可能想要真正做出类似于显示类的东西.它会有像你这样命名的原语:rotate,translate等.并且您希望从中派生它以添加更多功能或更改功能.但想想看,一旦你拥有的不仅仅是一艘船,一种特殊的船,另一种特殊的船,你将会遇到衍生地狱,你会复制很多代码.再次,使用策略模式.并记得保持简单.Displayble类需要具备什么?
这种设计没有分离对象的 UI 部分和对象的行为部分,可以说是“模型”和“视图”。这不一定是坏事,但如果继续这种设计,您可能会发现以下重构很困难:
但如果你可以接受这些权衡,并且这个设计对你来说有意义,那么我认为它没有什么严重的错误。
| 归档时间: |
|
| 查看次数: |
5849 次 |
| 最近记录: |