You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity滑动控制问题:元素仅移动一次且碰撞不停止如何解决?

问题描述

需要实现:滑动操作时,玩家元素持续移动直到碰撞障碍物。当前存在两个问题:

  1. 现有代码仅让元素移动一次,无法持续滑动移动
  2. 碰撞障碍物时不会停止移动

玩家与墙体均已配置2D Box Collider,此前使用while循环导致代码阻塞,改用Coroutine后问题仍未解决。询问是否需要添加Rigidbody及具体解决方法。

问题根源
  1. 现有Coroutine只执行一次Translate操作就结束,没有循环逻辑实现持续移动
  2. 碰撞状态判断仅在协程启动时检查一次,没有持续监听碰撞状态
  3. 错误调用StopCoroutine(OnSwipeUp()),比如下滑协程里错误停止上滑协程,逻辑混乱
  4. 未使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:59:17