You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用两个枚举生成无序唯一值,实现碰撞检测的Switch分支逻辑?

碰撞检测类型匹配的高效可读实现方案

针对你遇到的碰撞检测中(A,B)与(B,A)需要复用同一逻辑的问题,以下是几种C#中实用的实现方案:

方案1:排序枚举值生成唯一键

通过将两个枚举值按大小排序,生成统一的键,确保顺序不影响结果。这种方式简单直接,适合小型碰撞系统。

数值键实现

ColliderType typeA = colliderA.ColliderType;
ColliderType typeB = colliderB.ColliderType;

int valA = (int)typeA;
int valB = (int)typeB;
// 确保小值在前,大值在后,生成唯一键
int key = valA <= valB ? (valA * 100 + valB) : (valB * 100 + valA);

switch (key)
{
    case (int)ColliderType.Circle * 100 + (int)ColliderType.Circle:
        return CheckCircleCircle((CircleCollider)colliderA, (CircleCollider)colliderB);
    case (int)ColliderType.Circle * 100 + (int)ColliderType.Box:
        // 无需再写Box+Circle的case,因为键是统一的
        return CheckCircleBox(
            colliderA is CircleCollider ? (CircleCollider)colliderA : (CircleCollider)colliderB,
            colliderA is BoxCollider ? (BoxCollider)colliderA : (BoxCollider)colliderB
        );
    case (int)ColliderType.Box * 100 + (int)ColliderType.Box:
        return CheckBoxBox((BoxCollider)colliderA, (BoxCollider)colliderB);
    default:
        throw new NotSupportedException($"未支持的碰撞类型组合:{typeA} 和 {typeB}");
}

字符串键实现(可读性更强)

var key = typeA <= typeB ? $"{typeA}_{typeB}" : $"{typeB}_{typeA}";

switch (key)
{
    case $"{ColliderType.Circle}_{ColliderType.Circle}":
        // 执行检测逻辑
        break;
    case $"{ColliderType.Circle}_{ColliderType.Box}":
        // 执行检测逻辑
        break;
}

方案2:字典映射类型对到检测方法

用字典存储无序类型对与对应检测方法的映射,扩展性更好,新增碰撞类型只需添加字典条目,无需修改分支判断。

首先定义碰撞检测委托:

public delegate bool CollisionCheck(Collider a, Collider b);

初始化字典(建议在静态构造函数或启动时初始化):

private static readonly Dictionary<(ColliderType, ColliderType), CollisionCheck> _collisionHandlers = new()
{
    { (ColliderType.Circle, ColliderType.Circle), CheckCircleCircle },
    { (ColliderType.Circle, ColliderType.Box), CheckCircleBox },
    { (ColliderType.Box, ColliderType.Box), CheckBoxBox }
};

调用时标准化类型对:

ColliderType typeA = colliderA.ColliderType;
ColliderType typeB = colliderB.ColliderType;
// 生成有序的类型对,确保(A,B)和(B,A)对应同一个键
var typePair = typeA <= typeB ? (typeA, typeB) : (typeB, typeA);

if (_collisionHandlers.TryGetValue(typePair, out var handler))
{
    return handler(colliderA, colliderB);
}

throw new NotSupportedException($"未支持的碰撞类型组合:{typeA} 和 {typeB}");

注意:CheckCircleBox方法需要兼容两种输入顺序,内部自动转换为固定顺序处理:

private static bool CheckCircleBox(Collider a, Collider b)
{
    CircleCollider circle = a as CircleCollider ?? (CircleCollider)b;
    BoxCollider box = a as BoxCollider ?? (BoxCollider)b;
    // 执行圆-盒碰撞检测逻辑
    return Vector2.Distance(circle.Center, box.ClosestPointTo(circle.Center)) <= circle.Radius;
}

方案3:双分派模式(面向对象最优解)

利用多态特性实现双分派,让碰撞体自身处理碰撞检测逻辑,完全消除类型判断,符合开闭原则,适合需要频繁扩展的大型系统。

首先定义抽象基类:

public abstract class Collider
{
    public abstract ColliderType ColliderType { get; }
    public abstract bool CheckCollision(Collider other);
    
    // 定义针对每种碰撞体的检测方法
    protected abstract bool CheckCircleCollision(CircleCollider circle);
    protected abstract bool CheckBoxCollision(BoxCollider box);
}

实现CircleCollider:

public class CircleCollider : Collider
{
    public Vector2 Center { get; set; }
    public float Radius { get; set; }
    public override ColliderType ColliderType => ColliderType.Circle;

    public override bool CheckCollision(Collider other)
    {
        // 调用对方的对应检测方法,实现双分派
        return other.CheckCircleCollision(this);
    }

    protected override bool CheckCircleCollision(CircleCollider circle)
    {
        // 圆-圆碰撞逻辑
        return Vector2.Distance(Center, circle.Center) <= Radius + circle.Radius;
    }

    protected override bool CheckBoxCollision(BoxCollider box)
    {
        // 圆-盒碰撞逻辑
        return Vector2.Distance(Center, box.ClosestPointTo(Center)) <= Radius;
    }
}

实现BoxCollider:

public class BoxCollider : Collider
{
    public Vector2 Min { get; set; }
    public Vector2 Max { get; set; }
    public override ColliderType ColliderType => ColliderType.Box;

    public override bool CheckCollision(Collider other)
    {
        return other.CheckBoxCollision(this);
    }

    protected override bool CheckCircleCollision(CircleCollider circle)
    {
        // 复用圆-盒的检测逻辑,因为顺序不影响结果
        return circle.CheckBoxCollision(this);
    }

    protected override bool CheckBoxCollision(BoxCollider box)
    {
        // 盒-盒(AABB)碰撞逻辑
        return Min.X <= box.Max.X && Max.X >= box.Min.X &&
               Min.Y <= box.Max.Y && Max.Y >= box.Min.Y;
    }

    public Vector2 ClosestPointTo(Vector2 point)
    {
        return new Vector2(
            Math.Clamp(point.X, Min.X, Max.X),
            Math.Clamp(point.Y, Min.Y, Max.Y)
        );
    }
}

调用时只需一行代码:

bool isColliding = colliderA.CheckCollision(colliderB);

关于枚举标记(Flags)的说明

枚举标记([Flags])主要用于表示可组合的状态集合(如权限、选项),并不适合解决无序类型对的匹配问题,因此不推荐用这种方式实现你的需求。

内容的提问来源于stack exchange,提问作者Wolf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:25:54