处理对象之间的交互

我目前正在团结一致做几场比赛。 我正在使用C#。 我通常对游戏中的代码感到满意,我知道如何让它“优雅”,可以这么说。 我非常擅长编码单个元素(Say,Asteroids中的宇宙飞船)。 但我对我的代码感到满意,直到我达到一个对象需要与另一个对象交互的程度。 在那之后它变成了代码意大利面,我总是放弃这个项目。我还没有找到一种处理事物的优雅方式。 我相信我已经在互联网的各个地方提出过要求,但我似乎不断回到这一点。

有没有处理对象之间交互的常用方法? 什么都不觉得hacky? 我的最新项目再次出现了这个问题。 这是一个Unity项目,一个2d sidescroller。 检测我是否用我的角色命中“尖峰”包括检查碰撞对象标签并查看它是否是“尖峰”。 但是我的所有“死亡”代码都包含在播放器中,而不是尖峰。 除了带有标签的网格对撞机之外,尖峰不是其他任何东西。 这感觉不对。

所以stackoverflow,你们怎么处理这个?

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

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

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

  • BeforeMove(协调oldCoordinate,Coordinate newCoordinate,out bool canMove)
  • 移动(协调oldCoordinate,Coordinate newCoordinate)
  • HealthChanged(int newHealth)

场景中的其他对象可能包含以下事件:

  • DamagePlayer(int damage)
  • HealPlayer(整形)

当您要移动玩家时,您将触发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事件,当它达到零或更低时,会杀死玩家。

使用此模式,添加新function(如检测下降)相对简单。 只需创建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)); } } 

这通常是大项目发生的事情,他们开始非常好,最终成为大怪物。 在编写面向对象的应用程序时,我发现了以下几个有用的原则:

  1. 从您的域问题开始深入到类图开始,以自上而下的方式进行OOAD分析
  2. 始终将您的应用程序分成多个层(实用程序,数据访问,业务对象,UI ……)
  3. 最重要的是,实施GRASP模式以确保您的对象具有正确的职责,以自然的方式进行交互而不是高度耦合。

除了设计模式,总是很好考虑:
而不是使用标签,我建议为这样的事情创建组件。 它们是Unity3d的核心概念之一,并且更具可重用性。

例如,您可以创建一个类型为DamageVolume的新组件。 这将使它更通用,你可以将其重用于其他损害你的播放器的东西。 您还可以使用InstantKillDamageType (允许玩家决定他的死亡方式或播放效果)或DamageAmount 。 在玩家的碰撞事件中,您可以执行以下操作:

 var damager = collision.gameobject.GetComponent(); if (damager != null) { if (damager.InstantKill) { this.Kill(damager.DamageType); } else { this.Damage(damager.DamageAmount, damager.DamageType); } }