尝试摆脱嵌套 switch 子句,但对于 C# 来说是新的(可能使用字典和委托)

问题描述 投票:0回答:1

Unity Game Engine 有这个很好的方法来检测碰撞:

它们都采用一个 Collision 对象来实现所有这些情况的逻辑。为了实现这些方法,我采用了一个可碰撞对象(AKA Player)和“listen”它的碰撞来实现一些逻辑。 示例:

public class PlayerController : MonoBehaviour
{
 ...
    private void OnCollisionEnter(Collision collision)
    {            
        Debug.Log("Colission detected with object");
    }
 ...
}

但是,有一些问题可能需要使用嵌套 switch case(丑陋)或者可能需要一些 多态性 字典 - 委托 或其他东西。

  1. 第一个问题:玩家可以与任何对象存在待创建发生碰撞。

  2. 碰撞的“state”可以是“enter”或“stay”或“exit”;因此,我需要能够管理 3 个“states”次 x 数量的“objects”进行碰撞。

  3. 为了“引用”“碰撞”GameObjectUnity提出了一些建议AWFUL:通过“TAG”或“NAME”来引用对象:

    private void OnCollisionEnter(Collision collision){
        if (collision.gameObject.tag == "Ball"){
            Debug.Log("Player collided with an object with TAG 'Ball'");
        }
    }
    

请想象一下,当我考虑为 30 个对象实现 3 种状态(进入、停留、退出)时。 Switch/cases 或嵌套 ifs 将成为一场噩梦,并打破所有良好的代码约定。

我这样做的原因是因为我想要某种“事件监听器”,但我不知道如何在 C# 中实现,其中:

  1. 玩家与某物发生碰撞。
  2. “侦听器”(OnCollisionEnter、...Stay、...Exit)检测此类冲突并调度适当的方法来处理事件。
  3. 尽量不要依赖“标签”或“名称”,因为我认为对字符串进行硬编码是一种不好的做法,但也尝试使代码适用于任何“object碰撞”,而无需对任何内容进行硬编码。

第一次尝试

public class PlayerController : MonoBehaviour { ... private enum CollisionState { ENTER, STAY, EXIT } private enum CollisionableGameObject { COUNTER, SINK } private Dictionary<CollisionableGameObject, Func<CollisionState, Collision, bool>> collisionEvent; private void Start() { this.collisionEvent = new Dictionary<CollisionableGameObject, Func<CollisionState, Collision, bool>> { [CollisionableGameObject.COUNTER] = new Func<CollisionState, Collision, bool>(CollideCounter), [CollisionableGameObject.SINK] = new Func<CollisionState, Collision, bool>(CollideSink) }; } private void OnCollisionEnter(Collision collision) { this.CollisionManager(collision, CollisionState.ENTER); if (collision.gameObject.TryGetComponent(out ClearCounterController clearCounter)) { Debug.Log("Colission detected with clear counter"); } } private void CollisionManager(Collision collision, CollisionState state) { if (this.collisionEvent.TryGetValue("")) { //BY THIS POINT NO IDEA WHAT AM I DOING } } private bool CollideCounter(CollisionState state, Collision collision) { return true; }
第一次使用字典和委托,现在我什至不理解我自己的代码。也许我在尝试归档良好的编程实践时增加了复杂性。但由于我是 Unity 和 C# 的新手,我知道我需要什么,但不知道如何去做,入门级 Unity 教程让我热血沸腾。

如果有任何具有 C# 经验的高级工程师,我希望得到你们的意见。

提前非常感谢。

c# dictionary unity-game-engine delegates polymorphism
1个回答
0
投票
您不必保存对象的碰撞状态。所有三个碰撞检测函数都可以同时或多次调用。您只需要像在代码中那样尝试获取组件即可。

但这会带来一个像你所说的问题;很多 if 控制。你不应该用这种方式控制 30 个物体。但你可以控制一个界面。

例如创建一个名为“ICollideable”的接口

public interface ICollideable{ public void OnCollide(); }
并尝试在 PlayerController 类中获取 ICollideable 接口。然后调用OnCollide函数。

private void OnCollisionEnter(Collision collision) { if (collision.gameObject.TryGetComponent(out ICollideable collideable)) { collideable.OnCollide(); } }
不要忘记在您的类中实现我们的接口。

public class ClearCounterController : ICollideable{ public void OnCollide(){ // Do whatever you want here. } }
您也可以通过这种方式创建停留和退出功能。

© www.soinside.com 2019 - 2024. All rights reserved.