Unity 2D玩家碰撞墙体时抖动及自动移动问题求助
解决2D URP顶视角射击游戏玩家碰撞墙体抖动、无输入漂移及朝向偏移问题
问题描述
我正在Unity中制作一款2D URP顶视角射击游戏。当玩家以特定方式(沿墙体滑动或碰撞墙体角落)与墙体碰撞时,会出现抖动现象,且无输入时会缓慢移动,还会朝向鼠标方向偏移。
玩家脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; public class PlayerMovement : MonoBehaviour { [SerializeField] private float movespeed; [SerializeField] private float rotspeed; [SerializeField] private Camera cam; [SerializeField] private Animator animator; private Rigidbody2D rb; private Vector2 moveInput; private void Awake() { rb = GetComponent<Rigidbody2D>(); } private void Update() { animator.SetFloat("Speed", rb.velocity.sqrMagnitude); } private void FixedUpdate() { SetPlayerVel(); RotateInDirectionofCursor(); } private void SetPlayerVel() { rb.velocity = moveInput * movespeed * Time.deltaTime; } private void RotateInDirectionofCursor() { Vector2 mouseWorldPos = cam.ScreenToWorldPoint(Input.mousePosition); transform.up = (mouseWorldPos - new Vector2(transform.position.x, transform.position.y)) * -1; } private void OnMove(InputValue inputValue) { moveInput = inputValue.Get<Vector2>(); } }
相关组件设置
玩家
- Rigidbody2D:Body Type (Dynamic)、Collision Detection (Continuous)、Interpolate (Interpolate)
- Box Collider 2D
- Player Input
墙体(位于Tilemap网格下)
- Tilemap Collider 2D
- Rigidbody2D:Body Type (Static)
我尝试改用rb.MovePosition实现移动,也尝试编写脚本处理墙体碰撞,但都无效。由于我对Unity不够熟练,可能没找到问题根源。
问题根源分析
- 移动逻辑错误:直接给
rb.velocity赋值时乘以Time.deltaTime是错误的——Rigidbody2D的velocity本身是基于每秒的速度,乘以deltaTime会导致速度被错误缩放,无输入时可能残留微小速度导致漂移。 - 旋转与物理帧冲突:在
FixedUpdate中直接修改transform.up会干扰物理引擎的碰撞处理,导致碰撞时抖动;同时直接赋值旋转会忽略物理约束,和刚体运动脱节。 - 碰撞检测与插值配合问题:Tilemap Collider的网格特性加上刚体插值设置,若移动逻辑不匹配,容易在角落或滑动时出现抖动。
具体修复方案
1. 修正移动逻辑
移除Time.deltaTime,并在无输入时直接归零速度,避免漂移:
private void SetPlayerVel() { // 无输入时直接归零速度,防止漂移 if (moveInput.magnitude < 0.01f) { rb.velocity = Vector2.zero; return; } // 直接设置速度(velocity本身是每秒单位,无需乘deltaTime) rb.velocity = moveInput.normalized * movespeed; }
注意:如果需要平滑加速/减速,可以用
rb.AddForce替代直接赋值velocity,或者用Lerp过渡速度,避免瞬间速度变化导致的碰撞抖动。
2. 分离旋转逻辑到Update,并使用平滑旋转
将旋转移到Update(因为鼠标输入是帧同步的),并使用Quaternion.RotateTowards实现平滑旋转,避免直接修改transform干扰物理:
private void Update() { animator.SetFloat("Speed", rb.velocity.sqrMagnitude); RotateInDirectionofCursor(); // 移到Update处理 } private void FixedUpdate() { SetPlayerVel(); // 物理相关逻辑留在FixedUpdate } private void RotateInDirectionofCursor() { Vector2 mouseWorldPos = cam.ScreenToWorldPoint(Input.mousePosition); Vector2 direction = mouseWorldPos - (Vector2)transform.position; // 计算目标朝向的角度(适配up方向的偏移) float targetAngle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg - 90f; // 平滑旋转到目标角度 transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(0, 0, targetAngle), rotspeed * Time.deltaTime); }
3. 优化碰撞设置
- 给玩家的Box Collider 2D添加小范围的Edge Radius(比如0.05-0.1),减少角落碰撞时的尖锐接触,缓解抖动。
- 若Tilemap Collider是复合碰撞,确保启用Used By Composite,并检查Tilemap的碰撞瓦片是否有重叠或异常。
- 尝试将玩家Rigidbody2D的Interpolate改为
Extrapolate,或者暂时关闭插值测试是否是插值导致的抖动。
4. 额外优化:处理碰撞后的速度修正
如果滑动时仍有抖动,可以在OnCollisionStay2D中修正速度,避免刚体被墙体"弹回"导致的抖动:
private void OnCollisionStay2D(Collision2D collision) { if (collision.gameObject.CompareTag("Wall")) { // 获取碰撞法线,将速度沿法线方向的分量归零 Vector2 normal = collision.contacts[0].normal; rb.velocity = Vector2.Project(rb.velocity, Vector2.Perpendicular(normal)); } }
内容的提问来源于stack exchange,提问作者Clare05
相关产品推荐
相关产品推荐

