Unity滑动控制问题:元素仅移动一次且碰撞不停止如何解决?
问题描述
需要实现:滑动操作时,玩家元素持续移动直到碰撞障碍物。当前存在两个问题:
- 现有代码仅让元素移动一次,无法持续滑动移动
- 碰撞障碍物时不会停止移动
玩家与墙体均已配置2D Box Collider,此前使用while循环导致代码阻塞,改用Coroutine后问题仍未解决。询问是否需要添加Rigidbody及具体解决方法。
问题根源
- 现有Coroutine只执行一次
Translate操作就结束,没有循环逻辑实现持续移动 - 碰撞状态判断仅在协程启动时检查一次,没有持续监听碰撞状态
- 错误调用
StopCoroutine(OnSwipeUp()),比如下滑协程里错误停止上滑协程,逻辑混乱 - 未使用Rigidbody2D,直接用
Transform.Translate移动会绕过物理碰撞检测的交互逻辑,导致碰撞时无法正确停止
解决方案
1. 必须添加Rigidbody2D
给玩家对象添加Rigidbody2D组件,设置以下参数:
Body Type选择Kinematic(不受重力影响,同时支持碰撞检测)- 取消勾选
Use Gravity - 勾选
Freeze Rotation Z(防止玩家旋转)
2. 重构协程与移动逻辑
- 用单个协程统一处理持续移动,循环执行直到碰撞障碍物
- 使用
Rigidbody2D.MovePosition替代Transform.Translate,保证Kinematic刚体的物理交互正确性 - 添加状态标记防止重复触发滑动操作
修改后的完整代码
using System.Collections; using UnityEngine; public class PlayerController : MonoBehaviour { private Rigidbody2D _rb; private bool _isMoving = false; private bool _isColliding = false; [Header("移动设置")] public float moveSpeed = 5f; public float SWIPE_THRESHOLD = 20f; private Vector2 _fingerDown; private Vector2 _fingerUp; void Awake() { _rb = GetComponent<Rigidbody2D>(); if (_rb == null) { Debug.LogError("玩家对象缺少Rigidbody2D组件,请添加!"); } } IEnumerator MoveContinuously(Vector2 direction) { _isMoving = true; _isColliding = false; while (!_isColliding) { // 按物理帧更新位置,保证移动平滑且符合物理规则 _rb.MovePosition(_rb.position + direction * moveSpeed * Time.fixedDeltaTime); yield return new WaitForFixedUpdate(); } _isMoving = false; } void OnCollisionEnter2D(Collision2D col) { _isColliding = true; } void OnCollisionExit2D(Collision2D col) { _isColliding = false; } float GetVerticalMoveDistance() { return Mathf.Abs(_fingerDown.y - _fingerUp.y); } float GetHorizontalMoveDistance() { return Mathf.Abs(_fingerDown.x - _fingerUp.x); } void CheckSwipeInput() { if (_isMoving) return; // 正在移动时忽略新的滑动 // 垂直滑动判断 if (GetVerticalMoveDistance() > SWIPE_THRESHOLD && GetVerticalMoveDistance() > GetHorizontalMoveDistance()) { var direction = _fingerDown.y - _fingerUp.y > 0 ? Vector2.up : Vector2.down; StartCoroutine(MoveContinuously(direction)); _fingerUp = _fingerDown; } // 水平滑动判断 else if (GetHorizontalMoveDistance() > SWIPE_THRESHOLD && GetHorizontalMoveDistance() > GetVerticalMoveDistance()) { var direction = _fingerDown.x - _fingerUp.x > 0 ? Vector2.left : Vector2.right; StartCoroutine(MoveContinuously(direction)); _fingerUp = _fingerDown; } } void Update() { foreach (Touch touch in Input.touches) { switch (touch.phase) { case TouchPhase.Began: _fingerUp = touch.position; _fingerDown = touch.position; break; case TouchPhase.Ended: _fingerDown = touch.position; CheckSwipeInput(); break; } } } }
关键改进点
- 用Kinematic类型的Rigidbody2D处理移动,确保碰撞检测有效
- 协程循环执行移动,直到碰撞触发停止
- 添加
_isMoving标记防止同时处理多个滑动请求 - 使用
WaitForFixedUpdate同步物理帧,避免移动卡顿 - 简化滑动判断逻辑,统一移动处理代码,减少冗余
内容的提问来源于stack exchange,提问作者SpeedyGo55
相关产品推荐
相关产品推荐

