← ClaudeAtlas

game-mathlisted

写移动/碰撞/相机等游戏逻辑时使用。向量、插值、帧率无关。
Wade-DevCode/awesome-coding-skills-cn · ★ 3 · AI & Automation · score 78
Install: claude install-skill Wade-DevCode/awesome-coding-skills-cn
# 游戏数学与手感 ## 何时用 - 写角色移动、跳跃、相机跟随、射弹轨迹等任何和空间运动相关的逻辑之前。 - 发现帧率一高角色移动变快、帧率一低角色移动变慢的 bug 时。 - 实现平滑跟随相机、技能预测线、瞄准辅助、敌人转向等涉及插值或旋转的功能时。 - 出现角色卡墙、穿墙、碰撞检测时有时不准等物理/几何问题时。 ## 核心规则 ### 1. 所有移动与计时必须乘 deltaTime,物理用固定步长 **规则:** 角色位移、速度积分、冷却计时等所有随时间变化的量,必须乘以当前帧的 `deltaTime`;物理模拟(刚体、碰撞)必须在固定步长的 `FixedUpdate`(或等效接口)中执行,不能放在可变帧率的 `Update` 里。 **为什么:** 最经典的错误:`transform.position += speed * Vector3.forward`——忘了乘 `deltaTime`。60fps 时移动速度正常,玩家开了高刷屏(144fps)变成 2.4 倍速,开了垂直同步卡到 30fps 就像踩了泥。更隐蔽的版本:冷却计数器 `cooldown -= 1`(每帧减 1),在 60fps 下 1 秒冷却感觉正确,在 120fps 下只有 0.5 秒——平衡性被帧率破坏。物理放在 `Update` 里的后果:帧率波动导致碰撞检测不稳定,高速物体(子弹)会穿过薄墙(Tunneling)。 **怎么做:** ```csharp // Unity 示例 void Update() { // ✅ 位移乘 deltaTime,帧率无关 transform.position += velocity * Time.deltaTime; // ✅ 冷却计时乘 deltaTime if (cooldown > 0) cooldown -= Time.deltaTime; // ❌ 不乘 deltaTime,帧率越高移动越快 // transform.position += velocity; } void FixedUpdate() { // ✅ 物理/碰撞在固定步长中处理 rb.AddForce(jumpForce * Vector3.up); } ``` - 自研引擎同理:物理循环用固定 `dt`(如 1/60s),渲染循环用实际帧间隔;物理步长和渲染步长解耦。 --- ### 2. 用引擎向量 API,分清世界坐标与本地坐标 **规则:** 向量运算(归一化、点积、叉积、投影)全部使用引擎提供的 Vector API,禁止自己手写 `sqrt` 计算距离再归一化;坐标空间转换(世界 ↔ 本地 ↔ 屏幕)必须明确,不能混用。 **为什么:** 手写归一化的经典 bug:`float len = sqrt(x*x + y*y); dir = (x/len, y/len)`——当向量长度接近零时除以近零值,结果爆成 NaN 或 Infinity,角色瞬间飞到无穷远处。坐标空间混用更隐蔽:把角色的 `transform.forward`(世界坐标方向)直接当本地坐标方向使用,角色一旋转就方向全乱。 **怎么做:** ```csharp // 反例 — 手写归一化,零向量时 NaN float len = Mathf.Sqrt(dir.x * dir.x + dir.y * dir.y); Vector2 normalized = new Vector2(dir.