跳转至

DETERMINISTIC COLLISION

Int Collider

可脱离渲染运行的 2D / 3D 定点物理碰撞库

以 FixInt 为计算基础,为状态同步、帧同步、战斗回放和服务端权威验证提供稳定一致的逻辑碰撞判定。

架构概览 核心能力 返回首页

框架介绍

Unity ZM Physic Int Collider 是一套面向状态同步、帧同步、战斗回放与服务端战斗验证的定点碰撞检测库。碰撞体、坐标、尺寸及碰撞算法建立在 FixInt 定点数学之上,逻辑碰撞体不继承 MonoBehaviour,可以脱离渲染对象独立运行。

模块 命名空间 说明
定点数学 ZM.FixMath 标量、数学函数、2D/3D 定点向量
2D 碰撞 ZM.Physics2D Box、Sphere、碰撞事件、扫掠体 CCD
3D 碰撞 ZM.Physics3D Box、Sphere、Cylinder 组合检测

核心设计

逻辑层持有定点碰撞数据并完成权威判定;Unity GameObjectTransformRenderer 只承担可选的输入适配与画面表现。相同逻辑可复用于客户端和无渲染服务端。

职责边界

本库提供确定性基础碰撞检测、碰撞生命周期和部分位置修正能力,并不是完整刚体动力学引擎,不包含 PhysX 的重力、摩擦、质量、关节和复杂旋转碰撞体模拟。

1. 功能概览

能力 说明
PhysicsWorld2D 管理 2D 逻辑碰撞体并执行 Box / Sphere 检测
PhysicsWorld3D 管理 3D 逻辑碰撞体并执行 Box / Sphere / Cylinder 检测
碰撞生命周期 提供 Enter、Stay、Exit 回调
位置修正 计算部分碰撞组合的穿插修正向量
Unity Collider 适配 从 Unity Collider 快速创建定点逻辑碰撞体
2D Swept Volume 为高速物体提供扫掠体连续检测示例
逻辑渲染分离 逻辑碰撞体可不绑定任何 GameObject

1.1 碰撞支持矩阵

A B Box Sphere
Box 支持 支持
Sphere 支持 支持
A B Box Sphere Cylinder
Box 支持 支持 支持
Sphere 支持 支持 支持
Cylinder 支持 支持 支持

形状说明

Box 检测以轴对齐包围盒思路实现。当前版本不提供任意旋转 OBB 或复杂网格碰撞,请根据项目需求扩展。

2. 获取与接入

2.1 获取源码

git clone https://github.com/ZMteacher/Unity-ZM-PhysicIntCollider.git

使用 Unity Hub 打开完整工程,或将下列目录完整复制到已有项目:

Assets/ZMPackages/FixIntMath
Assets/ZMPackages/FixIntPhysics

依赖关系

FixIntPhysics 依赖 FixIntMath。复制时应保留两个目录的 .asmdef.meta 文件;使用自定义程序集的业务代码还需要添加相应 Assembly Definition Reference。

2.2 引用命名空间

using ZM.FixMath;
using ZM.Physics2D;
using ZM.FixMath;
using ZM.Physics3D;

3. 运行流程

一次标准逻辑帧通常包含以下步骤:

  1. 读取当前帧已确认输入。
  2. 计算角色等逻辑对象的新定点位置。
  3. 使用 SyncLogicPosSyncLogicSizeSyncLogicRadius 等接口同步碰撞数据。
  4. 调用 PhysicsWorld2D.Instance.OnLogicFrameUpdate() 或 3D 对应接口。
  5. 处理 Enter / Stay / Exit 回调和 AdjustPos
  6. 将最终逻辑状态同步到表现对象。
帧输入 -> 定点逻辑移动 -> 同步碰撞体 -> 世界检测
       -> 碰撞事件/位置修正 -> 权威逻辑结果 -> 渲染插值

不要使用 Update 作为权威逻辑帧

仓库 Demo 在 Update() 中调用碰撞世界是为了直观演示。正式帧同步项目应由固定频率的逻辑帧调度器调用,不能依赖各客户端不同的渲染帧率。

4. 2D 快速上手

4.1 纯逻辑方式创建

using ZM.FixMath;
using ZM.Physics2D;

FixIntBoxCollider2D player = new FixIntBoxCollider2D(
    new FixIntVector2(0, 0),   // 逻辑位置
    FixIntVector2.zero,        // 中心偏移
    new FixIntVector2(2, 2)    // 完整尺寸
);

FixIntSphereCollider2D enemy = new FixIntSphereCollider2D(
    new FixIntVector2(3, 0),
    FixIntVector2.zero,
    1                         // 半径
);

PhysicsWorld2D.Instance.AddCollider2D(player);
PhysicsWorld2D.Instance.AddCollider2D(enemy);

4.2 监听碰撞事件

player.OnCollisionEnter2DAction += OnCollisionEnter;
player.OnCollisionStay2DAction += OnCollisionStay;
player.OnCollisionExit2DAction += OnCollisionExit;

void OnCollisionEnter(FixIntCollider2D other)
{
    Debug.Log($"进入碰撞:{other.ColliderType}");
}

void OnCollisionStay(FixIntCollider2D other)
{
    // 持续伤害、触发区计时等
}

void OnCollisionExit(FixIntCollider2D other)
{
    Debug.Log($"离开碰撞:{other.ColliderType}");
}

4.3 驱动逻辑帧

void OnLogicFrameUpdate(FixIntVector2 nextPosition)
{
    player.SyncLogicPos(nextPosition);
    PhysicsWorld2D.Instance.OnLogicFrameUpdate();
}

4.4 释放碰撞体

player.OnRelease();
enemy.OnRelease();

OnRelease() 会停用碰撞体、清理碰撞状态,并将其从对应物理世界移除。

5. 从 Unity Collider 创建

5.1 2D Box

BoxCollider2D unityBox = GetComponent<BoxCollider2D>();
FixIntBoxCollider2D logicBox =
    PhysicsWorld2D.Instance.GenerateFixIntBoxFormUnityCollider(unityBox);

5.2 3D Box / Sphere / Cylinder

BoxCollider unityBox = boxObject.GetComponent<BoxCollider>();
SphereCollider unitySphere = sphereObject.GetComponent<SphereCollider>();
CapsuleCollider unityCapsule = cylinderObject.GetComponent<CapsuleCollider>();

FixIntBoxCollider3D box =
    PhysicsWorld3D.Instance.GenerateFixIntBoxFormUnityCollider(unityBox);

FixIntSphereCollider3D sphere =
    PhysicsWorld3D.Instance.GenerateFixIntSphereFormUnityCollider(unitySphere);

FixintCylinderCollider3D cylinder =
    PhysicsWorld3D.Instance.GenerateFixIntCylinderFormUnityCollider(unityCapsule);

生成接口的 managerCollider 参数默认为 true,表示创建后自动加入碰撞世界。传入 false 时需要自行管理。

RenderObj

适配接口会调用 SetRenderObj 保存对应 Unity 对象。纯逻辑方式创建的碰撞体可以不设置 RenderObj,业务代码不得假设它一定存在。

6. 碰撞体公共 API

6.1 公共属性

属性 说明
Active 是否参与碰撞检测
RenderObj 可选的 Unity 表现对象
LogicPos 定点逻辑位置,包含中心偏移后的结果
Center 碰撞体中心偏移
ColliderType 碰撞体形状枚举
X / Y / Z 逻辑位置分量;2D 无 Z
CanAdjust 当前是否存在待消费的位置修正
AdjustPos 位置修正向量

6.2 公共方法

API 说明
SetRenderObj(GameObject) 绑定可选表现对象
SetUseAdjustPos(bool) 开启或关闭位置修正
SyncLogicPos(...) 更新逻辑位置
SyncLogicSize(...) 更新 Box 尺寸
SyncLogicRadius(...) 更新 Sphere / Cylinder 半径
SyncLogicHeight(...) 更新 3D Cylinder 高度
DetectCollider(target) 与目标碰撞体执行检测并更新事件状态
OnRelease() 释放并从物理世界移除

AdjustPos 是消费式读取

读取 AdjustPos 时会将 CanAdjust 重置为 false。请在碰撞世界完成检测后统一读取一次,不要在多个系统中重复读取。

7. 形状 API

7.1 FixIntBoxCollider2D

成员 说明
Size 完整宽高
BoxWidth 半宽
BoxHeight 半高

构造函数:

new FixIntBoxCollider2D(logicPos, center, size);

7.2 FixIntSphereCollider2D

成员 说明
Radius 圆形碰撞体半径
new FixIntSphereCollider2D(logicPos, center, radius);

7.3 FixIntBoxCollider3D

成员 说明
Size 完整三维尺寸
HalfSize 三轴半尺寸
BoxWidth X 轴半宽
BoxHeight Y 轴半高

7.4 FixIntSphereCollider3D

Radius 表示球体半径。

7.5 FixintCylinderCollider3D

成员 说明
Radius 圆柱半径
Height 圆柱高度
MaxHeightPoint 顶部 Y 坐标
MinHeightPoint 底部 Y 坐标
ContainTargetHeight(y) 判断 Y 坐标是否处于圆柱高度范围

类名大小写

当前源码类型名为 FixintCylinderCollider3D,其中 inti 为小写。调用时需要与源码保持一致。

8. PhysicsWorld2D API

API 说明
Instance 2D 世界单例
OnLogicFrameUpdate() 遍历已注册碰撞体并更新碰撞状态
DetectCollider(Box, Box, useAdjust) Box 与 Box 检测
DetectCollider(Box, Sphere, useAdjust) Box 与 Sphere 检测
DetectCollider(Sphere, Sphere) Sphere 与 Sphere 检测
AddCollider2D(collider) 注册碰撞体
RemoveCollider2D(collider) 移除碰撞体
GenerateFixIntBoxFormUnityCollider(...) 从 Unity Box 创建逻辑 Box
GenerateFixIntSphereFormUnityCollider(...) 从 Unity Collider 创建逻辑 Sphere

直接调用 DetectCollider 适合一次性查询;调用碰撞体的 DetectCollider(target) 或世界逻辑帧更新,则会一并维护 Enter / Stay / Exit 状态。

9. PhysicsWorld3D API

检测组合 对应重载
Box / Box DetectCollider(FixIntBoxCollider3D, FixIntBoxCollider3D)
Box / Sphere DetectCollider(FixIntBoxCollider3D, FixIntSphereCollider3D)
Sphere / Sphere DetectCollider(FixIntSphereCollider3D, FixIntSphereCollider3D)
Cylinder / Sphere DetectCollider(FixintCylinderCollider3D, FixIntSphereCollider3D)
Cylinder / Box DetectCollider(FixintCylinderCollider3D, FixIntBoxCollider3D, bool)
Cylinder / Cylinder DetectCollider(FixintCylinderCollider3D, FixintCylinderCollider3D)

PhysicsWorld3D 同样提供碰撞体注册、移除、逻辑帧更新和 Unity Collider 适配接口。

10. 位置修正

位置修正用于处理部分形状碰撞后的穿插:

player.SetUseAdjustPos(true);

void OnLogicFrame(FixIntVector2 intendedPosition)
{
    player.SyncLogicPos(intendedPosition);
    PhysicsWorld2D.Instance.OnLogicFrameUpdate();

    if (player.CanAdjust)
    {
        intendedPosition += player.AdjustPos;
        player.SyncLogicPos(intendedPosition);
    }
}

修正不是完整动力学响应

AdjustPos 只提供穿插位置修正,不会自动计算质量、冲量、摩擦或反弹。多个碰撞同时发生时,业务层还需确定稳定的处理顺序和迭代策略。

11. 2D 连续碰撞检测

离散碰撞只检查每个逻辑帧的最终位置,高速子弹可能在相邻两帧之间越过薄墙。CCDSweptVolume2D 根据上一帧与当前帧位置生成扫掠包围盒,用于补充检测运动路径覆盖区域。

CCDSweptVolume2D swept = new CCDSweptVolume2D(
    bulletCollider,
    currentFramePosition,
    lastFramePosition
);

bool hit = swept.DetectCollider(wallCollider);

当前实现

仓库中的 CCDSweptVolume2D 同时包含教学可视化代码,会创建临时 GameObjectImage。服务端或正式逻辑版本应移除表现层代码,仅保留定点扫掠体计算与检测。

12. 性能与确定性

12.1 当前复杂度

OnLogicFrameUpdate() 当前使用两层循环遍历碰撞体,检测复杂度约为 O(n²)。少量战斗单位便于使用;碰撞体较多时建议增加 Broad Phase:

  • 均匀网格 / Spatial Hash
  • 四叉树(2D)
  • 八叉树(3D)
  • Sweep and Prune
  • 碰撞层与掩码过滤

12.2 确定性清单

  1. 所有端使用相同库版本、配置和查找表。
  2. 使用固定逻辑帧和一致输入顺序。
  3. 碰撞体注册、移除与遍历顺序保持一致。
  4. 不以 Transform 或 Unity Physics 结果作为权威逻辑状态。
  5. 随机数使用相同种子和调用顺序。
  6. 多碰撞修正采用明确、稳定、可复现的顺序。

13. 示例场景

场景 演示内容
PhysicsWorld2DDemo.unity 2D Box / Sphere 碰撞与事件
BoxPlayerMove/PlayerMove.unity Box 角色移动及阻挡
SpherePlayerMove/PlayerMove.unity Sphere 角色移动及阻挡
SweptVolume/SweptVolume.unity 高速子弹连续碰撞检测
PhysicsWorld3DDemo.unity 3D Box / Sphere / Cylinder 检测
PlayerMoveDemo.unity 3D 定点移动与碰撞

示例根目录:

Assets/ZMPackages/FixIntPhysics

14. 常见问题

为什么两个对象看起来接触了,却没有触发碰撞?

检查逻辑位置、中心偏移、尺寸或半径是否已通过 SyncLogic... 接口更新;同时确认碰撞体仍处于 Active 状态并已注册到正确的 PhysicsWorld。

为什么回调重复触发?

OnCollisionStay...Action 本来就会在持续碰撞期间每个逻辑帧触发。只需要首次事件时应监听 OnCollisionEnter...Action

为什么读取不到位置修正?

先调用 SetUseAdjustPos(true),并确认当前形状组合支持修正。AdjustPos 为消费式读取,读取后 CanAdjust 会重置。

可以放到纯 C# 服务端运行吗?

核心设计支持逻辑与渲染分离,但现有程序集仍引用 UnityEngine,部分适配与 Demo 也使用 Unity 类型。部署纯 .NET 服务端时,应拆分核心逻辑程序集并移除 Unity 表现与适配代码。

为什么高速子弹仍可能漏检?

普通离散检测只检查帧末位置。可使用扫掠体思路,并根据子弹形状、墙体厚度和业务精度扩展专用 CCD。

相关链接