将具有2个参数的事件映射到特定方法的优雅方式



我正在Unity中开发一款游戏,我有多个对象(苹果、橙子、香蕉等)可以与多个碰撞器对象(网、盒子、环等)碰撞。每一场比赛都有特定的功能。假设有10个物体和10个对撞机物体,那就是100种方法。如果可能的话,我希望避免使用switch/if-else语句。

目前,碰撞是在对撞机对象上触发的,然后我将其发送给调度:

public class NetCollision : BaseCollider {
CollisionDispatch dispatch;
void OnCollisionEnter (Collision coll)
{
Fruit obj = coll.gameObject.GetComponent<Fruit> ();
dispatch.RegisterCollision (obj, this, coll);
}}

在CollisionDispatch中,我有这样的switch语句:

public void RegisterCollision(Fruit obj, BaseCollider collider, Collision collision) {
if (obj is Banana) {
BananaDispatch (obj as Banana, collider, collision)
} else if (obj is Apple) {
AppleDispatch (obj as Banana, collider, collision)
} ...
}
public void BananaDispatch (Banana obj, BaseCollider coll, Collision collision) {
if (coll is NetCollider) {
// Banana-NetCollider method
} else if (coll is BoxCollider) {
// Banana-BoxCollider method
} ...
}

这是使用泛型的情况吗?我尝试过对泛型进行重构,但它似乎并不能清理代码。

您可以使用多态性和策略或状态模式。例如:

public class CollisionDispatch : MonoBehaviour
{
public void RegisterCollision(Fruit obj, BaseCollider collider, Collision collision)
{
obj.Dispatch(collider, collision);
}
}
public interface ICollisionableFruit
{
//add method for each collision type
void HandleNetCollision(Collision collision);
void HandleElseCollision(Collision collision);
}
public abstract class Fruit : ICollisionableFruit
{
public virtual void Dispatch(BaseCollider collider, Collision collision)
{
collider.HandleCollision(this, collision);
}
//declare all of interface's methods as abstract
public abstract void HandleNetCollision(Collision collision);
public abstract void HandleElseCollision(Collision collision);
}

public class Banana : Fruit
{
//override all methods
public override void HandleNetCollision(Collision collision)
{
Debug.LogFormat("HandleNetCollision for {0}", this.GetType());
}
public override void HandleElseCollision(Collision collision)
{
Debug.LogFormat("HandleElseCollision for {0}", this.GetType());
}
}
public abstract class BaseCollider
{
CollisionDispatch dispatch;
void OnCollisionEnter(Collision coll)
{
var obj = coll.gameObject.GetComponent<Fruit>();
dispatch.RegisterCollision(obj, this, coll);
}
public abstract void HandleCollision(ICollisionableFruit fruit, Collision collision);
}
public class NetCollision : BaseCollider
{
public override void HandleCollision(ICollisionableFruit fruit, Collision collision)
{
Debug.LogFormat("NetCollision HandleCollision");
fruit.HandleNetCollision(collision);
}
}
public class ElseCollision : BaseCollider
{
public override void HandleCollision(ICollisionableFruit fruit, Collision collision)
{
Debug.LogFormat("NetCollision HandleCollision");
fruit.HandleElseCollision(collision);
}
}

您只需为Fruit的所有继承重写Dispatch方法,为BaseCollider的所有继承覆盖HandleCollision方法。此外,您还可以为每个BaseCollider继承的Fruit添加特定于抽象的方法,如果它意味着不同的冲突处理依赖的Fruits类型,则可以从HandleCollision调用它。

如果您需要使用更多的碰撞器,只需要向ICollisionableFruitFruit和每个继承器添加新方法。

它不是一个明显灵活的解决方案,但它比if的许多解决方案都要好。

据我所知,有一堆Fruit对象,当类型为FruitObstacle的特定对象与它们碰撞时,它们都必须做出不同的反应。

为此,我将使用继承:

  • 创建一个基类Fruit,该基类将具有OnCollisionEnter方法
  • 创建所有CollideWithNetCollideWithBox。。。如CCD_ 16方法
  • OnCollisionEnter方法中运行switch来检测碰撞对象的类型(有很多方法可以检测,例如,可以在FruitObstacle上使用tags)并调用相应的方法
  • 创建继承Fruit类(Banana : FruitApple : Fruit…)的所有水果子级
  • 为您的CollideWithBoxCollideWithNet。。。每种水果的方法

如果每个水果都有相同的逻辑,那么可以使用virtual方法而不是abstract方法,并在Fruit类中添加逻辑(不要忘记用base.MethodName调用继承类中的基类)。

相关内容

最新更新