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

Unity 2D俯视角游戏中无法推动物体的问题求助

解决Unity 2D玩家推动箱子无效的问题

你的问题核心在于使用了Rigidbody2D.MovePosition直接设置位置,这种方式属于运动学式移动,不会触发物理引擎的碰撞推力,因此无法推动带有刚体的箱子。同时OnCollisionExit2D里强制清零箱子速度的代码,也会阻止箱子被推动后的运动。

以下是修复步骤和修改后的代码:


关键调整点

  • 替换MovePosition为物理驱动的移动方式(比如设置velocity),让玩家的运动参与物理交互
  • 移除OnCollisionExit2D中清零箱子速度的逻辑
  • 确保玩家和箱子的Rigidbody2D设置正确:
    • 玩家刚体:Body Type设为Dynamic,开启Freeze Rotation Z防止旋转
    • 箱子刚体:Body Type设为Dynamic,可根据需求调整Mass(建议玩家质量略大于箱子,比如玩家质量2、箱子质量1)

修改后的PlayerController代码

using UnityEngine;
using UnityEngine.InputSystem;
using Unity.Netcode;

public class PlayerController : NetworkBehaviour
{
    public float moveSpeed = 5f;
    public float collisionOffset = 0.05f;
    public ContactFilter2D movementFilter;
    Vector2 movementInput;
    Rigidbody2D rb;
    List<RaycastHit2D> castCollisions = new List<RaycastHit2D>();

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        // 锁定Z轴旋转,避免玩家碰撞后旋转
        rb.freezeRotation = true;
    }

    private void FixedUpdate()
    {
        if (!IsOwner) return;

        if (movementInput != Vector2.zero)
        {
            // 检测全方向移动是否可行
            bool canMoveFull = TryCheckMove(movementInput);
            
            if (canMoveFull)
            {
                // 用速度驱动移动,触发物理碰撞
                rb.velocity = movementInput * moveSpeed;
            }
            else
            {
                // 尝试单独X方向移动
                bool canMoveX = TryCheckMove(new Vector2(movementInput.x, 0));
                if (canMoveX)
                {
                    rb.velocity = new Vector2(movementInput.x * moveSpeed, 0);
                }
                else
                {
                    // 尝试单独Y方向移动
                    bool canMoveY = TryCheckMove(new Vector2(0, movementInput.y));
                    if (canMoveY)
                    {
                        rb.velocity = new Vector2(0, movementInput.y * moveSpeed);
                    }
                    else
                    {
                        // 所有方向受阻,停止移动
                        rb.velocity = Vector2.zero;
                    }
                }
            }
        }
        else
        {
            // 无输入时停止
            rb.velocity = Vector2.zero;
        }
    }

    // 仅检测移动方向是否有障碍物,不执行移动
    private bool TryCheckMove(Vector2 direction)
    {
        int count = rb.Cast(
            direction,
            movementFilter,
            castCollisions,
            moveSpeed * Time.fixedDeltaTime + collisionOffset);
        
        // 清空碰撞列表,避免残留数据干扰下一次检测
        castCollisions.Clear();
        return count == 0;
    }

    void OnMove(InputValue movementValue)
    {
        // 归一化输入,避免斜向移动速度过快
        movementInput = movementValue.Get<Vector2>().normalized;
    }
}

额外说明

  • 对movementInput做了归一化处理,保证斜向和单向移动速度一致
  • 使用rb.velocity让物理引擎处理玩家运动,碰撞时会自然对箱子施加推力
  • 保留方向检测逻辑,避免玩家穿模到障碍物中

内容的提问来源于stack exchange,提问作者Pixelcaft

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:30:52