2

我目前正在团结一致地制作一些游戏。我正在使用 C#。我通常对我的游戏中的代码很满意,我知道如何让它“优雅”,可以这么说。我非常擅长对单个元素进行编码(例如,小行星中的宇宙飞船)。但我只对我的代码感到满意,直到我达到一个对象需要与另一个对象交互的地步。在那之后它变成了代码的意大利面,我总是放弃这个项目。我还没有找到一种优雅的方式来处理事情。我相信我在互联网上的各个地方都问过,但我似乎一直在问这个问题。

有没有处理对象之间交互的通用方法?有什么不让人觉得hacky的吗?这个问题在我最近的项目中再次出现。这是一个 Unity 项目,一个 2d 横向卷轴。检测我是否用我的角色击中“尖峰”涉及检查碰撞对象标签并查看它是否是“尖峰”。但是我所有的“死亡”代码都包含在播放器中,而不是尖峰。尖峰实际上只是带有标签的网格对撞机。这感觉不对。

那么stackoverflow,你们都是怎么处理的呢?

4

3 回答 3

3

大型项目通常会发生这种情况,它们开始时非常好,但最终变成了巨大的怪物。以下是我在编写面向对象应用程序时发现的一些有趣的有用原则:

  1. 以自上而下的方式进行 OOAD 分析,从挖掘到类图的领域问题开始
  2. 始终将您的应用程序分层(实用程序、数据访问、业务对象、UI...)
  3. 最重要的是,实施GRASP 模式以确保您的对象具有正确的职责,以自然的方式交互而不是高度耦合。
于 2012-07-04T06:28:07.700 回答
3

除了设计模式,这总是值得考虑的:
我建议不要使用标签,而是为类似的东西创建组件。它们是 Unity3d 的核心概念之一,可重用性更强。

例如,您可以创建一个新的类型DamageVolume或类似的组件。这将使它更通用,您可以将其重新用于其他会损坏您的播放器的事情。你也可以用属性来配置它,例如InstantKillDamageType(这将允许玩家决定他如何死或播放哪些效果)或DamageAmount。在你的玩家的碰撞事件中,你可以这样做:

var damager = collision.gameobject.GetComponent<DamageVolume>();
if (damager != null) {
    if (damager.InstantKill) {
        this.Kill(damager.DamageType);
    }
    else {
        this.Damage(damager.DamageAmount, damager.DamageType);
    }
}
于 2012-07-04T07:28:33.850 回答
2

正如 Johnn Blade 在对该问题的评论中留下的那样,使用观察者模式可能是在应用程序的不同部分之间传达状态更改的好方法。

作为一个具体的例子,您可以将玩家的移动分解为几个离散的步骤(或事件),这些步骤(或事件)可以被应用程序的其他部分观察到。

例如,如果您将以下事件添加到播放器:

  • BeforeMove(坐标 oldCoordinate, 坐标 newCoordinate, out bool canMove)
  • 移动(坐标旧坐标,坐标新坐标)
  • HealthChanged(int newHealth)

场景中的其他对象可能会发生以下事件:

  • DamagePlayer(int 伤害)
  • HealPlayer(int 治疗)

当您要移动玩家时,您将触发 BeforeMoved 事件 - 如果没有响应canMove = false(例如锁着的门),则允许移动。然后更新玩家的位置,并调用 Moved。

所以,你的 Spike 可能会监听玩家 Moved 事件:

void Moved(Coordinate oldCoordinate, Coordinate newCoordinate) 
{ 
  if (newCoordinate.Intersects(this.Location))
  {
    DamagePlayer(50); 
  }
} 

相应地,您的播放器将监听 DamagePlayer 事件。

void DamagePlayer(int damage)
 {
    this.Health -= damage;
    HealthChanged(this.Health);  
 }

有些东西(可能在玩家本身)会监听 HealthChanged 事件,当它达到零或更少时,会杀死玩家。

使用这种模式,添加新功能(例如检测跌倒)相对简单。只需创建 Moved 事件的新观察者:

void Moved(Coordinate oldCoordinate, Coordinate newCoordinate) 
{ 
  decimal deltaY = oldCoordinate.Y - newCoordinate.Y; 
  if (deltaY  < -100) // If fell 100 units or more, take 10 damage per unit. 
  {
    DamagePlayer(10 * Math.Abs(deltaY)); 
  }
} 
于 2012-07-04T06:55:27.300 回答