我正在在Unity 6中构建一个2D异步游戏,基于砖块的探索,想像一下Mega Man Battle Network的过场地图。玩家走在一个伪网格的异步砖块上,并且应该保持在可行走区域内。 我想这应该很简单。 我花了一整场会试图让Rigidbody工作。 下面是发生了什么,尝试过什么,以及为什么解决方案如此简单。
设置
可行走区域是一个异步砖块序列。每个砖块在启动时注册其世界位置和边界。 玩家使用WASD移动。 玩家应该能够自由行走于砖块上,但不能离开可行走区域。 我的第一反应是Rigidbody + Colliders。 物理处理包含,Unity做了所有工作,大家都很高兴。
发生了什么
我使用rb.MovePosition()与连续碰撞检测。 物理求解者立即开始与我斗争。 玩家会粘在砖块边缘上,吸入角落,偶尔被两个碰撞器之间困住无法脱出。 求解者在对地板砖碰撞器进行碰撞时,会以一种让运动感觉像是在浸泡在胶水中的方式进行解决。 我尝试了各种方法:
- 射线在玩家前方检测边界之前移动——在直线边缘上有效,但在角落处两根射线不一致时失败
- SphereCast用于平滑的边界检测——同样的角落问题,现有球体
- CheckSphere在移动之前测试目的地——更好,但边缘案例(字面上)仍然出现
- 阻塞碰撞器在可行走区域周围——求解者会随机推玩家远离边缘
- 壁滑沿着碰撞器表面——引入了新的粘在邻近碰撞器之间的粘性问题
每个解决方案解决了一个问题并引入了另一个问题。 基本问题是,我要求物理求解者强制实施数据驱动约束,而求解者有自己的意见关于对象应该如何移动。
解决方案
我删除了Rigidbody。
csharp
transform.position = FloorRegistry.Clamp(desired);
就这样。 我们可以回家了,大家都很高兴。 FloorRegistry 是一个静态类,知道每个可行走砖块的位置。 Clamp() 方法将玩家的期望位置返回到可行走区域内的最近有效位置。 纯数学。 零物理。 玩家总是移动。.Clamp() 只是保持玩家在边界内。
对于异步砖块具体来说,Clamp() 使用一个钻石检查——|dx|/halfW + |dy|/halfH <= 1——因为异步砖块是钻石,不是矩形。 矩形Clamp()允许玩家滑入钻石的视觉角落处没有砖块。 这让我困扰了更长时间——我无法理解为什么玩家应该向右/东移动而不是向上/北移动。
我学到的
物理求解者在你想要物理时是很棒的。 碰撞,滑动,堆叠,重力——这就是它的用途。 但是,如果你的运动是数据驱动的(基于砖块,网格或受限于已知的可行走区域),求解者并不是在帮助你。 它是一个复杂的系统,试图近似你可以用基本数学表达的东西。
你可能会遇到同样的陷阱:
- 你正在添加工作绕过物理求解者不想要的东西
- 你的碰撞层变得复杂以防止不应存在的交互
- 运动“感觉不正确”尽管速度值是正确的
- 边缘和角落案例持续增加
如果可行走区域是已知的数据, Clamp() 到它。 跳过求解者。
评论 (0)