Unity 角色“防卡墙”实战:不用动态物理材质,也能稳定解决 Wedging 问题

在很多基于 Rigidbody 的角色项目里,大家遇到"卡墙"时第一反应是改摩擦系数、切换物理材质,甚至运行时动态改材质。

我们这次走了另一条路:不依赖动态物理材质,而是用"预测胶囊 + ComputePenetration 挤出向量"做防卡墙,最终稳定解决了问题。

这篇文章记录完整思路和落地方式。


1. 问题背景

项目中的角色移动使用 AddForce 驱动,场景有大量复杂几何(边角、凹凸 Mesh、环形结构)。

常见异常:

  1. 明明有移动输入,但角色贴墙后"推不动"。
  2. 某些边角处速度突然被吃掉。
  3. 偶发楔入(wedging),表现为抖动、短距离抽搐或原地卡住。

2. 为什么不再依赖"动态物理材质"方案

很多项目会尝试在代码里动态切换 friction/bounce 来缓解卡墙,但这种方式有几个硬伤:

  1. 治标不治本

    卡墙核心是接触几何与解算方向问题,不是单纯摩擦问题。

  2. 全局副作用大

    改材质会影响整套接触行为(滑移、落地、平台交互、推挤手感)。

  3. 调参成本高、稳定性差

    一处场景调好了,另一处复杂结构可能又失效。

  4. 行为不一致

    不同 FPS、不同接触体组合时,动态材质策略往往表现漂移。

我们最后选择:玩家和子物体都使用默认材质,不在运行时改材质参数

把防卡墙交给"几何预测 + 挤出向量"来处理,结果更稳。


3. 核心方案:Predictive Capsule + Penetration Push

最终方案分 5 步:

  1. 预测下一物理步角色胶囊位置(仅水平分量)。
  2. 在预测位姿做 OverlapCapsuleNonAlloc。
  3. 对每个重叠体调用 Physics.ComputePenetration。
  4. 聚合所有 separationDir * separationDistance 得到总挤出向量。
  5. 只处理水平向内分量:
    • 去掉"继续往里顶"的加速度
    • 可选抵消当前"向里"的水平速度(不加反弹)

重点:不改 Y 轴,不覆盖跳跃系统,不依赖动态材质。


4. 为什么它比单次 SweepTest 稳

单 SweepTest 适合"前方是否有障碍"的预警,但对 wedging 场景信息不够。

而 ComputePenetration 给的是"最小分离向量",可以直接回答:

  • 现在应该往哪边解开重叠?
  • 多个接触体同时挤压时,合力方向是什么?

这正是防卡墙真正需要的信息。


5. 精简代码思路

cs 复制代码
// 预测水平位移
Vector3 predictedDelta = horizontalV * dt + accPlanar * (dt * dt);
predictedDelta += desiredDir.normalized * movementSweepPadding;

// 预测位姿胶囊重叠检测
int hitCount = Physics.OverlapCapsuleNonAlloc(
    pointA, pointB, radius, overlapBuffer, movementSweepBlockMask, QueryTriggerInteraction.Ignore);

// 聚合挤出向量
Vector3 planarPush = Vector3.zero;
for (int i = 0; i < hitCount; i++)
{
    Collider other = overlapBuffer[i];
    if (other == null || other.isTrigger) continue;

    if (Physics.ComputePenetration(
        capsule, predictedPos, predictedRot,
        other, other.transform.position, other.transform.rotation,
        out Vector3 sepDir, out float sepDist))
    {
        Vector3 planarDir = Vector3.ProjectOnPlane(sepDir, Vector3.up);
        if (planarDir.sqrMagnitude > 1e-6f && sepDist > 0f)
            planarPush += planarDir.normalized * sepDist;
    }
}

// 只移除向内推进,不改Y
if (planarPush.sqrMagnitude > 1e-6f)
{
    Vector3 outward = planarPush.normalized;
    Vector3 intoObstacle = -outward;

    float intoAcc = Vector3.Dot(accelerationStep, intoObstacle);
    if (intoAcc > 0f) accelerationStep -= intoObstacle * intoAcc;
}

6. 参数建议

  1. movementSweepPadding: 0.05 ~ 0.12
  2. movementSweepMaxCancelAcceleration: 25 ~ 60
  3. movementSweepBlockMask: 只包含会阻挡移动的层

7. 这套"防卡墙"方案的价值

  1. 不依赖动态物理材质,避免全局副作用。
  2. 对复杂场景更稳,特别是边角/环形/凹凸结构。
  3. 不破坏原有跳跃与竖直力模型。
  4. 参数可控、行为一致性更高。

结论

卡墙问题的核心是"接触解算方向"而不是"摩擦值本身"。

把策略从"动态改材质"切换到"预测胶囊 + 挤出向量",防卡墙会从"偶发有效"变成"稳定可控"。

如果你也在做 Unity 物理角色控制,这个方案非常值得直接落地。

相关推荐
winlife_5 分钟前
Unity 域重载会清空一切:Editor 工具如何让状态在重载后续命
unity·游戏引擎
深度森林2 小时前
无人机“路径规划”高价值专利案例:基于抗干扰粒子群优化的无人机路径规划方法
游戏引擎·cocos2d
小贺儿开发2 小时前
Unity3D 串口通信上位机联调系统
unity·串口·协议·数据·通信·传输·互动
tedcloud1234 小时前
ppt-master部署教程:快速搭建智能演示文稿系统
服务器·人工智能·系统架构·游戏引擎·powerpoint
SCLchuck8 小时前
UE5 地形材质UV
ue5·材质·uv
垂葛酒肝汤1 天前
Unity的UI扫光效果Shader
ui·unity·游戏引擎
mxwin1 天前
Unity Shader Alpha测试 · 模板测试 · 深度测试
unity·游戏引擎
UTwelve1 天前
【UE】材质与半透明 - 01. 基于Masked遮罩的抖动半透明 DitherMask
ue5·材质·虚幻引擎·着色器
2601_956002811 天前
冬日狂想曲(赠去马赛克补丁)2026.5.13最新版免费下载 转存后自动更新 (看到请立即转存 资源随时失效)pc手机版通用
智能手机·游戏引擎·电脑·游戏程序·动画·游戏美术
草木深雨纷纷1 天前
我的世界基岩版手机版(光影材质包大全)下载国际服集合下载分享
游戏·智能手机·游戏程序·材质