【问题标题】:'Self-aware' classes?“自我意识”课程?
【发布时间】:2011-12-19 04:01:48
【问题描述】:

长期读者第一次海报。请温柔一点。

我热衷于在 VB.net 中创建游戏。作为一个爱好程序员,我免费赠送我的游戏。由于我是一个没有受过正规培训的业余爱好者,因此我会尝试对自己进行正确的编程原则教育,并在编程(例如 OOP)时遵循它们。然而,我显然错过了一些自学成才的事情,如果我接受过正规教育,也许我会知道。

曾经真正困扰我的问题是不同的类(从现在开始称为对象)如何在没有编程特定交互的情况下相互“了解”(请留在我这里......请......)

好吧,想象一下,你有一个太空游戏和以下对象

  • clsShip
  • clsMissile
  • clsAsteroid
  • clsSpaceJunk

现在,这些对象中的每一个都有一个 Health、X、Y 和 Z 私有成员和属性,这些成员和属性都从 clsSpaceEntity 继承来作为参数。现在编程它们之间的冲突的一种方法是在主游戏循环中编写以下逻辑

对于舰船列表中的每艘舰船
检查列表中的每个 clsMissile 以查看它是否与它发生碰撞,如果是,则降低生命值
检查列表中的每个 clsAsteroid 以查看它是否与它发生冲突,如果是,则减少健康
检查每个 clsSpaceJunka 列表,看看它是否与它发生冲突,如果是,则降低健康
... 依此类推,每个对象都依此类推 下一个

等等等等……

现在,如果您谈论的是上面的简单示例,这可能没问题,但我的一些游戏有数十甚至数百个以这种基本方式交互的对象。

现在我向经验丰富的程序员提出问题。

OOP 中有没有办法执行以下操作...

对于从 clsSpaceEntity 继承的每个事物
检查继承此类型的所有其他对象(除了自身),如果它们发生碰撞,则减少健康
下一个

?

这种类型的对象/类或任何“了解”另一个对象以及它们如何相同/不同和交互的能力将为我节省大量的编码。

对此的任何帮助/帮助或反馈将不胜感激。感谢您的宝贵时间,抱歉阅读时间长。

【问题讨论】:

  • 不要使用匈牙利表示法 (clsWhatever)。
  • 看起来您正在尝试实现适当的关注点分离。使用更多的 OOP 概念,您可以制作精美分离的逻辑,而无需处理每种类型的对象的庞大方法。祝你好运!
  • 稍微偏离主题,但您似乎对类和对象有点困惑。虽然它们是相关的,但它们并不是一回事。这个评论框有点小,无法提供完整的解释,但阅读其中的差异会让您的生活更轻松。

标签: vb.net oop class object


【解决方案1】:

您应该为每个派生对象创建一个单独的List(Of SpaceEntity),而不是为每个派生对象创建一个单独的List(Of SpaceEntity)

然后您可以创建一个嵌套的For Each 循环,该循环遍历每对实体并进行碰撞检查。 (经过If x <> y 检查)

您可以通过为SpaceEntity 提供MustOverride 函数来处理与其他对象的碰撞,从而进一步增强您的设计,而不会因每个实体的单独逻辑而污染您的碰撞循环。
您可能应该使用visitor pattern 来允许实体对与其他不同类型实体的碰撞做出不同的反应。

请注意,每次碰撞都会发送到分别碰撞的两个对象;你需要在你的逻辑中处理它。

【讨论】:

    【解决方案2】:

    如果我正在编写处理单艘船、单枚导弹、小行星等的逻辑,那么该逻辑显然应该属于各自的类别。

    如果我正在编写处理多个对象或更糟糕的是,处理不同类型的多个对象的逻辑,我倾向于将该逻辑放在代表更高级别概念的类中。

    例如,您可能有一个包含 SpaceEntity 集合的 Universe 类。还有一个 Universe.FindCollisions() 返回 Collision 对象的集合。

    public class Universe {
        private IEnumerable<SpaceEntity> _entities;
    
        public IEnumerable<Collision> FindCollisions() {
            foreach(var e1 in _entities) {
                foreach(var e2 in _entities) {
                    if (e1.CollidesWith(e2)) {
                        yield return new Collision(e1, e2);
                    }
                }
            }
        }
    }
    

    解决它的另一种方法可能是有一个 CollisionCalculator 类,该类在其构造函数中接受 SpaceEntity 的集合,并且是该特定逻辑所在的位置。

    public class CollisionCalculator {
        public IEnumerable<Collision> Collisions {get; set;}
    
        public CollisionCalculator(IEnumerable<SpaceEntity> entities) {
            // logic to build the Collisions collection goes here
        }
    }
    

    【讨论】:

    • 嵌套的 foreach 循环将为每对重叠的实体返回两次冲突。一种是导弹与岩石相撞,另一种是岩石与导弹相撞。您可能需要过滤掉这些,具体取决于您的冲突解决方式。
    • 可能值得注意的是,随着对象数量变大(超过几百个),双重嵌套 for 循环将变得不切实际。如果物体之间有一定距离可以保证它们不可能发生碰撞,则将宇宙细分为大于该距离的块可能会有所帮助,并保留至少部分位于每个块中的对象的列表。使用 3d 空间中的简单分区,一些对象可能必须出现在最多 8 个列表中,但测试 100 组(每组 10 个对象)的碰撞将比测试一组 1000 个对象更快。
    • 顺便说一句,将 3 维空间细分为多个区域是可能的,并且不会太难,这样任何对象都不会落入超过四个区域(而不是八个)。如果将 Y 舍入到最接近的整数会产生奇数,则将 0.5 添加到 X。如果将 Z 舍入到最接近的整数会产生奇数,则将 X 和 Y 都添加 0.5。然后将所有三个坐标四舍五入为整数。空间坐标和 XY 值之间的映射将显示空间被划分为单位立方体,因此在任何点的四分之一单位内不超过四个。
    猜你喜欢
    • 1970-01-01
    • 2013-02-25
    • 1970-01-01
    • 2020-01-29
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 2013-11-30
    • 1970-01-01
    相关资源
    最近更新 更多