【问题标题】:Two Classes Dependent On Each Other两个相互依赖的类
【发布时间】:2011-04-26 23:17:32
【问题描述】:

我有 Camera 类,它处理相机行为。其中的字段是对目标的 Cube 类的引用(Cube 只是对象之一,但为了简单起见,我不会提及其他对象)。为了计算 View 矩阵,我需要相机的位置和目标的位置,所以我可以向我的程序解释:“相机放在这里,从这里看这个立方体”。如果立方体碰巧四处移动,相机的视角也会自动改变。

到目前为止,一切都很好:有一个 Camera 类依赖于 Cube 类,还有一个 Cube 类不依赖任何东西(在这个例子中)。

当我需要绘制一个立方体或任何东西时遇到了问题——为了绘制一些东西,在所需的值中,它是相机的视图矩阵;这就是我刚刚在第一段中计算的那个。本质上,这意味着当我开始在屏幕上绘制东西时,Cube 类也变得依赖于 Camera 类,它们现在相互依赖。这意味着我要么:

  1. 需要将Camera类的View矩阵字段设为静态,这样我就可以直接从Cube类中访问了。
  2. 需要在 Cube 类中创建一个方法(例如 SetView),然后我可以从 Camera 类中调用该方法(因为我已经有它的引用)。
  3. 需要在外部范围内保留视图矩阵。
  4. 需要建立双向依赖关系。

但是,我不喜欢其中任何一个:

  1. 处理多个视图的摄像头更多(目前屏幕上有 3 个),并且可能更多(或更少)。
  2. 这会使代码略微(有时,也许,非常)不可读——例如,当我绘制立方体时,不太清楚 View 矩阵的来源,您只需使用它,不要回头.
  3. 我会从相机类访问外部作用域,或者外部作用域会访问相机,我不喜欢这样,因为外部作用域仅用于处理执行机制。
  4. 我喜欢将我的引用字段保持为“只读”,因为它目前在这个系统中无处不在 - 引用在构造函数中设置,并且仅用于从被引用的类中获取数据。

而且,如果我没有说清楚,让我重复一下,有多个 Camera 对象,以及多个 Cube 对象;而任何相机可能会或可能不依赖于任何立方体,但通常至少有一个相机依赖于一个立方体。

任何建议将不胜感激:)

【问题讨论】:

    标签: c# class xna dependencies bidirectional


    【解决方案1】:

    如果您的 Cube 必须知道如何相对于相机渲染自己(因此必须了解相机),那么相机知道如何将自己与 Cube 对齐可能没有意义。当前在 Camera 中的对齐行为可能属于更高级别的类,例如知道 Cubes 和 Cameras 的 CameraDirector。这提高了类的凝聚力,因为它将 Camera 的一些职责拆分为一个不同的、紧密关注的 CameraDirector 类。这让 Camera 可以专注于其核心工作,并使其更易于理解和维护。

    【讨论】:

    • 感谢您的注意...在接受此回复之前,我必须进行一些测试,但您现在给了我应该做什么的想法——在Camera 类,我可以在其中命令相机跟随该对象......在这种情况下,我将反转当前的依赖关系。
    • 是的,我重新编码了这部分,在我看来这是迄今为止最好的解决方案。
    【解决方案2】:

    我让每个对象类负责它自己的渲染。

    在您的情况下,您必须将图形实例和相对于对象的视点传递给每个渲染方法。

    绘图类可以访问所有对象类的实例,并以任何有意义的顺序调用每个对象的绘图方法。您的对象类可能必须有另一个方法来确定与视点的距离,以便您可以按从远到近的顺序调用绘图方法。

    【讨论】:

    • 我还让每个类负责它自己的渲染 :) 感谢您提醒我距离问题,我想我没有将那部分代码转移到新解决方案中。
    【解决方案3】:

    在做 XNA 时,我遇到了一个类似的问题。

    我通过在我的 Draw 方法接口中添加一个相机接口来解决它。

    它不是很漂亮,到处都是相机,但效果很好。

    真正要得到的是你的更新和绘制循环是分开的。

    绘制时,您有一个要绘制的对象列表,并且您的绘制例程有一些相机类传递给它。

    以一种方式对您的类进行编码以生成需要渲染的所有对象的列表的替代方法。将此传递给包含相机的渲染器。

    关键是要维护一个摄像机列表,以及一个可绘制对象列表,尽管所有这些对象也属于描述游戏状态的逻辑模式。

    了解控制反转。这就是我真正描述的所有内容。

    【讨论】:

      【解决方案4】:

      两个备用选项:

      1. 为彼此不链接但仍包含您要使用的大部分逻辑的 Camera 和 Cube 创建基类。然后,您可以添加对 Cube 的 BaseCamera 引用,您将为其分配一个 Camera 对象,而不是 BaseCamera 对象。 (还有一个带有 BaseCube 字段的相机。)这就是多态性的力量。
      2. 定义 ICamera 和 ICube 接口。然后,Camera 类将使用 ICube 字段链接到立方体,反之亦然。

      不过,这两种解决方案都需要您在创建和释放新的相机和立方体对象时格外小心。我个人的偏好是使用接口。请记住,ICube 和 ICamera 界面应该不相互链接。它们的相关类将链接到另一个接口,而不是接口。

      【讨论】:

      • 谢谢,在对象层次结构上工作有点棘手(假设它不在 my 域中),但如果你认为你是对的解决方案中没有太多的对象层次结构。这是我必须与其他相关人员讨论的问题,尽管我认为我们已经到了可以建立更好层次结构的地步,因为现在我们只有几个接口。
      【解决方案5】:

      假设您的DrawWorld() 例程已经知道Cubes 和Cameras,我会将视图矩阵传递给Cube 的Draw() 方法:

      foreach (Cube cube in cubes) {
          cube.Draw(..., mainCamera.ViewMatrix, ...);
      }
      

      这样Cube 只“依赖”Matrix 而不是Camera。再说一次,也许这违反了上面的规则 3。不过,如果没有看到你的一些代码,我就不能做得更好了。

      【讨论】:

      • 这是我从一开始就一直在使用的——那时我只有一台相机。我在引入多个摄像头时遇到了这个问题(将其视为赛车游戏中的后视镜)。所以用这种方式处理它变得很棘手:)
      猜你喜欢
      • 2021-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-11
      • 1970-01-01
      • 2011-09-18
      • 2017-03-01
      • 1970-01-01
      相关资源
      最近更新 更多