游戏架构

我对我正在制作的XNA游戏有疑问,但它也是未来游戏的一般性问题。 我正在制作Pong游戏而且我不确切知道要在哪里更新,所以我会更好地解释我的意思。 我有一个类Game,Paddle和Ball,例如,我想validation球与屏幕限制或桨之间的碰撞,但我遇到了两种方法来做到这一点:

更高级别的方法 – 将桨和球属性公开,并在Game.Update上检查碰撞?

低级方法 – 我提供我需要的每个信息(屏幕限制和拨片信息)到球类(通过参数,或在公共公共静态类)和Ball.Update我检查碰撞?

我想我的问题以更通用的方式是:

对象是否需要知道如何更新和绘制自己,甚至是从某种程度上提供给它们的更高级别的依赖项?

要么

最好在Game.Update或Game.Draw中使用更高级别处理它,还是使用Managers来简化代码?

我认为这是一个适用于每个游戏的游戏逻辑模型问题。 我不知道我的问题是否清楚,如果没有,请随意提问。

回答你的问题的困难部分是你要问两个:“我现在应该做什么,对于乒乓球”和“我应该做些什么,以后,在一些通用游戏上”。


为了制作Pong你甚至不需要Ball和Paddle课程,因为他们基本上只是位置。 在你的游戏课中坚持这样的东西:

Vector2 ballPosition, ballVelocity; float leftPaddlePosition, rightPaddlePosition; 

然后只需在游戏的UpdateDrawfunction中以适合您的顺序更新并绘制它们。 简单!


但是,假设您想要创建多个球,并且球具有许多属性(位置,速度,旋转,颜色等):您可能想要制作可以实例化的Ball类或结构(同样适用于桨)。 您甚至可以将某些函数移动到它们自包含的类中( Draw函数就是一个很好的例子)。

但保持设计概念相同 – 所有对象 – 对象交互处理(即:游戏玩法)都发生在您的Game类中。

如果您有两个或三个不同的游戏元素(或类),这一切都很好。


但是我们假设一个更复杂的游戏。 让我们采取基本的乒乓球比赛,添加一些像弹球和球员控制的脚蹼的弹球元素。 让我们从Snake中添加一些元素,比如我们有一个AI控制的“蛇”以及一些球或蛇可以击中的拾取物。 并且为了好的衡量,我们可以说桨也可以像太空侵略者一样射击激光,激光螺栓根据它们击中的东西做不同的事情。

Golly这是一个巨大的互动混乱! 我们如何应对呢? 我们不能把它全部放在游戏中!

简单! 我们创建一个接口(或抽象类或虚拟类),我们的游戏世界中的每个“东西”(或“演员”)都将来自。 这是一个例子:

 interface IActor { void LoadContent(ContentManager content); void UnloadContent(); void Think(float seconds); void UpdatePhysics(float seconds); void Draw(SpriteBatch spriteBatch); void Touched(IActor by); Vector2 Position { get; } Rectangle BoundingBox { get; } } 

(这只是一个例子。没有“ 一个真正的演员界面 ”适用于每个游戏,你需要自己设计。这就是我不喜欢DrawableGameComponent 。)

拥有一个通用界面允许Game只谈论Actors – 而不需要知道游戏中的每一种类型。 只剩下每种类型的共同事物 – 碰撞检测,绘图,更新,加载,卸载等。

一旦你进入演员,你就可以开始担心特定类型的演员了。 例如,这可能是Paddle一个方法:

 void Touched(IActor by) { if(by is Ball) ((Ball)by).BounceOff(this.BoundingBox); if(by is Snake) ((Snake)by).Kill(); } 

现在,我喜欢让球被桨反弹,但这真的是一个品味问题。 你可以反过来做。

最后,您应该能够将所有演员都放在一个大型列表中,您可以在游戏中轻松迭代。

实际上,出于性能或代码简单性的原因,最终可能会有多个不同类型的actor列表。 这没关系 – 但总的来说,一般都要坚持游戏的原则只知道通用演员。

演员也可能想要查询出于各种原因存在的其他演员。 因此,给每个演员一个参考游戏,并在游戏中公开演员列表(当你编写游戏代码并且它是你自己的内部代码时,不需要对公共/私人超级严格。)


现在,您甚至可以更进一步,拥有多个接口。 例如:一个用于渲染,一个用于脚本和AI,一个用于物理等。然后有多个实现可以组成对象。

本文将对此进行详细介绍 。 我在这个答案中有一个简单的例子。 如果您开始发现您的单个actor接口开始变成更多抽象类的“树”,那么这是合适的下一步。

您也可以选择开始考虑游戏的不同组件如何相互通信。

Ball和Paddle都是游戏中的对象,在这种情况下,是可渲染的可移动物体。 桨具有以下标准

它只能上下移动

  1. 桨叶固定在屏幕的一侧或底部
  2. Paddle可能由用户控制(1对计算机或1 vs 1)
  3. 可以渲染球拍
  4. 桨只能移动到屏幕的底部或顶部,它不能通过它的边界

球具有以下标准

它不能离开屏幕的边界

  1. 它可以呈现
  2. 根据它在桨上的位置,您可以间接控制它(一些简单的物理)
  3. 如果它落在桨的后面那么圆就完成了
  4. 当比赛开始时,球通常会附着在丢失的人的桨上。

确定可以提取界面的通用标准

 public interface IRenderableGameObject { Vector3 Position { get; set; } Color Color { get; set; } float Speed { get; set; } float Angle { get; set; } } 

你也有一些GamePhysics

 public interface IPhysics { bool HasHitBoundaries(Window window, Ball ball); bool HasHit(Paddle paddle, Ball ball); float CalculateNewAngle(Paddle paddleThatWasHit, Ball ball); } 

然后有一些游戏逻辑

 public interface IGameLogic { bool HasLostRound(...); bool HasLostGame(...); } 

这不是所有逻辑,但它应该让您了解要查找的内容,因为您正在构建一组库和函数,您可以使用它们来确定将要发生的事情以及可能发生的事情以及您需要当事情发生时采取行动。

另外,看看这个,你可以改进和重构它,这样它就是一个更好的设计。

了解您的域名并写下您的想法。 没有计划就是计划失败

您可以将球和球拍视为游戏的一个组成部分,XNA为您提供基类GameComponent ,它具有您可以覆盖的Update(GameTime gameTime)方法来执行逻辑。 此外,还有DrawableGameComponent类,它带有自己的Draw方法来覆盖。 每个GameComponent类都有一个Game属性,用于保存创建它们的游戏对象。 在那里,您可以添加一些服务,您的组件可以使用它来自己获取信息。

您想要制作哪种方法,要么具有处理每次交互的“主”对象,要么向组件提供信息并让它们自己做出反应,这完全取决于您。 后一种方法在大型项目中是首选。 此外,这将是面向对象的处理事物的方式,为每个实体提供自己的Update和Draw方法。

我同意安德鲁所说的话。 我也在学习XNA和我的课程,例如你的球类。 我至少有一个更新(游戏时间)方法和一个Draw()方法。 通常是Initialize(),Load()。 然后从主游戏课我将从他们各自的表兄弟那里调用这些方法。 这是在我了解GameComponent之前。 这是一篇关于你是否应该使用它的好文章。 http://www.nuclex.org/blog/gamedev/100-to-gamecomponent-or-not-to-gamecomponent