【问题标题】:Game Architecture游戏架构
【发布时间】:2011-07-24 10:41:24
【问题描述】:

我有一个关于我正在制作的 XNA 游戏的问题,但这也是未来游戏的通用问题。我正在制作 Pong 游戏,但我不知道在哪里更新什么,所以我会更好地解释我的意思。我有一个 Game、Paddle 和 Ball 类,例如,我想验证球与屏幕限制或桨之间的碰撞,但我遇到了两种方法来做到这一点:

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

低级方法- 我将我需要的所有信息(屏幕限制和桨信息)提供给球类(通过参数,或在公共公共静态类中)和 Ball.Update我检查碰撞?

我想我的问题更笼统地说是:

一个对象是否需要知道如何更新和绘制自己,甚至需要以某种方式提供给它们的更高级别的依赖项?

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

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

【问题讨论】:

  • 我认为你所说的“逻辑”实际上是指“架构”。
  • (我一直在引用这个问题,所以我要自己修复标题...)
  • 这个更适合gamedev.stackexchange.com

标签: c# architecture xna xna-4.0


【解决方案1】:

回答您的问题的难点在于您要同时问:“我现在应该做什么,对于 Pong”和“我以后应该做什么,在一些通用游戏中”。


要制作 Pong,您甚至不需要 Ball 和 Paddle 课程,因为它们基本上只是位置。只需在您的 Game 类中添加这样的内容即可:

Vector2 ballPosition, ballVelocity;
float leftPaddlePosition, rightPaddlePosition;

然后在游戏的UpdateDraw 函数中按照适合您的顺序更新和绘制它们。简单!


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

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

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


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

天哪 真是一团糟!我们将如何应对?我们不能把它全部放在游戏中!

简单!我们创建了一个接口(或抽象类或虚拟类),我们游戏世界中的每个“事物”(或“演员”)都将从中派生。这是一个例子:

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; }
}

(这只是一个例子。没有“一个真正的演员界面”适用于每场比赛,你需要自己设计。这就是我不喜欢@的原因987654330@.)

拥有一个通用界面可以让 Game 只讨论 Actor,而不需要了解游戏中的每一种类型。只需要做每种类型的通用操作 - 碰撞检测、绘制、更新、加载、卸载等。

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

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

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

最后,您应该能够将所有演员放入一个大列表中,您可以在游戏中简单地迭代。

实际上,出于性能或代码简单性的原因,您最终可能会拥有多个不同类型的参与者列表。这没关系 - 但总的来说,请尽量坚持 Game 只知道通用演员的原则。

Actor 也可能出于各种原因想要查询存在哪些其他 Actor。所以给每个actor一个Game的引用,并在Game上公开actor列表(当你编写游戏代码时,不需要对public/private非常严格,这是你自己的内部代码。)


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

这在this article中有详细描述。我在this answer 中有一个简单的例子。如果您开始发现您的单个参与者接口开始变成更多的抽象类“树”,那么这是一个合适的下一步。

【讨论】:

  • 很棒的回应 - “但是让我们假设一个更复杂的游戏。”这听起来很酷的游戏...正在开发类似的东西:)
【解决方案2】:

您也可以选择开始考虑游戏的不同组件需要如何相互交流。

Ball 和 Paddle 都是游戏中的对象,在本例中是可渲染、可移动的对象。 桨有以下标准

只能上下移动

  1. 桨叶固定在屏幕的一侧或底部
  2. Paddle 可能由用户控制(1 对计算机或 1 对 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(...);
}

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

此外,查看此内容,您可以对其进行改进和重构,使其成为更好的设计。

了解您的领域并写下您的想法。 不计划就是计划失败

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 2017-08-22
        • 2012-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-01
        • 2013-02-01
        • 2011-08-31
        • 2011-10-02
        相关资源
        最近更新 更多