C# 设计游戏对象
最近,我开始使用微软XNA和C#开发一款小游戏,以供自己娱乐。我的问题是关于设计一个游戏对象和继承它的对象。我将把游戏对象定义为可以在屏幕上渲染的东西。为此,我决定创建一个基类,所有其他需要渲染的对象都将继承该基类,称为GameObject。以下代码为I级代码:C# 设计游戏对象,c#,oop,xna,C#,Oop,Xna,最近,我开始使用微软XNA和C#开发一款小游戏,以供自己娱乐。我的问题是关于设计一个游戏对象和继承它的对象。我将把游戏对象定义为可以在屏幕上渲染的东西。为此,我决定创建一个基类,所有其他需要渲染的对象都将继承该基类,称为GameObject。以下代码为I级代码: class GameObject { private Model model = null; private float scale = 1f; private Vector3 position = Vector
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
}
再一次,我省略了任何额外的特定于飞船的方法,比如发射导弹。你认为这种设计是好的,还是应该改进或彻底改变?看起来子类的构造函数很混乱,但这可能是唯一的方法。我从来没有做过这样的事情,我想知道我是否偏离了正轨
感谢所有留下答案的人。他们都很有帮助。似乎有一个普遍的共识,即改变它来使用MVC模式将是最好的。我将进一步研究如何做到这一点。我还将删除大多数构造函数,并且只有一个构造函数,因为modelResource之后的所有参数都不是创建对象所必需的,它们都可以在以后通过方法调用进行更改。此设计不会将对象的UI部分与对象的行为部分“模型”和“视图”分开可以这么说。这不一定是件坏事,但如果继续使用此设计,您可能会发现以下重构很困难:
- 通过更改所有艺术资产来重新剥皮游戏
- 更改许多不同游戏中对象的行为,例如确定对象是否处于活动状态的规则
- 更改为其他精灵引擎李>
但是,如果您对这些折衷方案感到满意,并且这种设计对您来说是合理的,那么我认为它没有什么异常的错误 就我个人而言,我发现你有一点不喜欢的构造器的数量,但这是你的选择,根本没有什么问题:) 关于从一个公共基础派生游戏对象的一般策略,这是一种非常常见的方法。甚至是标准的。我倾向于开始使用更类似于MVC的东西,使用只包含数据的轻量级“模型”游戏对象 我在XNA中看到的其他常见方法包括/您可能需要考虑的事项:
- 实现IRenderable接口,而不是在基类或派生类中执行任何渲染代码。例如,您可能需要从未渲染过的游戏对象-航路点或类似的东西
- 你可以使你的基类抽象,你不可能想要实例化一个游戏对象
不过,还是有一些小问题。你的设计很好 >根据调用构造函数的频率,可以考虑使所有额外的参数都是空的,当它们没有值时,只将它们传递给NULL。梅西耶创建对象时,构造器减少了我第一次在XNA中创建游戏时就是这样做的,但下一次我会更多地采用模型/视图类型的方法。模型对象将是您在更新循环中处理的对象,视图将用于绘制循环
当我想使用我的精灵对象处理3D和2D对象时,我遇到了无法将模型与视图分离的问题。它很快就变得一团糟。我对你们在向量中旋转的存储方法很感兴趣。这是怎么回事? 如果您存储X、Y、Z轴的角度(所谓的欧拉角度),如果您想要创建3D游戏,您应该重新考虑这个想法,因为您将在第一次渲染邪恶后不久遇到
就我个人而言,我不喜欢有这么多构造函数,因为您可以提供1个构造函数,并将所有不需要的参数设置为null。这样,您的界面就更干净了。这里谈论从视图中分离模型的人是正确的。用面向游戏开发者的术语来说,GameObject和RenderObject应该有单独的类。回想一下你的主要游戏循环:
// main loop
while (true) {
ProcessInput(); // handle input events
UpdateGameWorld(); // update game objects
RenderFrame(); // each render object draws itself
}
您希望更新游戏世界和渲染当前帧的过程尽可能独立。我还强烈建议使用合成而不是继承的方法来研究基于组件的设计。该思想的要点是基于对象的底层属性对对象建模,并允许这些属性为您完成所有工作 在您的情况下,游戏对象可能具有诸如能够移动、可渲染或具有某种状态等属性。这些独立的功能(或行为)可以建模为对象,并在GameObject中组合,以构建所需的功能
老实说,对于您正在进行的一个小项目,我会专注于使游戏功能化,而不是担心耦合和抽象之类的细节。或者,您可以创建一个结构或帮助类来保存所有数据,并在结构中包含许多构造函数,这样一来,你只需要在一个对象中,而不是在从GameObject继承的每个类中,有大量的构造函数,这不仅是一个潜在的问题(特别是必须为每个派生类重新定义构造函数),而且构造函数的参数数量也可能成为一个问题。即使将可选参数设置为null,以后也很难读取和维护代码 如果我写:
new Ship(content, "resource", true, null, null, null, null);
第二个空值做什么
如果参数列表超过四个或五个参数,则使用结构保存参数会使代码更可读(但更详细):
GameObjectParams params(content, "resource");
params.IsAlive = true;
new Ship(params);
有很多方法可以做到这一点。第一场比赛?开始简单。您的基本GameObject(在您的情况下,更恰当地称为DrawableGameObject[注意XNA中的DrawableGameComponent类])应该只包含属于所有GameObj的信息
GameObjectParams params(content, "resource");
params.IsAlive = true;
new Ship(params);