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

Unity玩家移动碰撞添加求助:水下场景Y轴移动受限问题

Unity水下游戏:碰撞检测与全轴移动兼容问题

问题描述

开发水下游戏时,现有移动脚本实现了玩家沿相机方向移动,但存在两个核心问题:

  • 玩家会直接穿过墙体,添加Box Collider无效果;
  • 添加Rigidbody后碰撞生效,但Y轴(上下)移动被限制,无法满足水下游动需求。
    新编写的移动脚本解决了碰撞问题,但仍无法实现Y轴移动,需要同时兼顾碰撞检测与全轴自由移动。

原有移动脚本(Movement1)

using UnityEngine;
using System.Collections;

public class Movement1 : MonoBehaviour {
    /* 
    wasd : basic movement
    shift : Makes camera accelerate */
 
    public float sensX;
    public float sensY;
    public Transform orientation;

    float xRotation;
    float yRotation;
    float mainSpeed = 5.0f; //regular speed
    float shiftAdd = 8.0f; //multiplied by how long shift is held.  Running
    float maxShift = 12.0f; //Maximum speed when holding shift
    float camSens = 0.25f; //How sensitive the mouse is
    private Vector3 lastMouse = new Vector3(255, 255, 255); //sets mouse near the middle
    private float totalRun= 1.0f;

    private void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }

    void Update () {
        float mouseX = Input.GetAxisRaw("Mouse X") * Time.deltaTime * sensX;
        float mouseY = Input.GetAxisRaw("Mouse Y") * Time.deltaTime * sensY;

        yRotation += mouseX;
        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);

        transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
        orientation.rotation = Quaternion.Euler(0, yRotation, 0);
       
        //Keyboard commands
        float f = 0.0f;
        Vector3 p = GetBaseInput();
        if (p.sqrMagnitude > 0){ // only move while a direction key is pressed
            if (Input.GetKey (KeyCode.LeftShift)){
                totalRun += Time.deltaTime;
                p  = p * totalRun * shiftAdd;
                p.x = Mathf.Clamp(p.x, -maxShift, maxShift);
                p.y = Mathf.Clamp(p.y, -maxShift, maxShift);
                p.z = Mathf.Clamp(p.z, -maxShift, maxShift);
            } else {
                totalRun = Mathf.Clamp(totalRun * 0.5f, 1f, 1000f);
                p = p * mainSpeed;
            }
                
            p = p * Time.deltaTime;
            Vector3 newPosition = transform.position;
            if (Input.GetKey(KeyCode.Space)){ //If player wants to move on X and Z axis only
                transform.Translate(p);
                newPosition.x = transform.position.x;
                newPosition.z = transform.position.z;
                transform.position = newPosition;
            } else {
                transform.Translate(p);
            }
        }
    }

    private Vector3 GetBaseInput() { //returns the basic values, if it's 0 than it's not active.
        Vector3 p_Velocity = new Vector3();
        if (Input.GetKey (KeyCode.W)){
            p_Velocity += new Vector3(0, 0 , 1);
        }
        if (Input.GetKey (KeyCode.S)){
            p_Velocity += new Vector3(0, 0, -1);
        }
        if (Input.GetKey (KeyCode.A)){
            p_Velocity += new Vector3(-1, 0, 0);
        }
        if (Input.GetKey (KeyCode.D)){
            p_Velocity += new Vector3(1, 0, 0);
        }
        return p_Velocity;
    }
}

新移动脚本(NewMovement)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewMovement : MonoBehaviour
{
    [Header("Movement")]
    public float moveSpeed;

    public Transform orientation;

    float horizontalInput;
    float verticalInput;

    Vector3 moveDirection;

    Rigidbody rb;

    // Start is called before the first frame update
    private void Start()
    {
        rb = GetComponent<Rigidbody>();
        rb.freezeRotation = true;
    }
    private void MyInput()
    {
        horizontalInput = Input.GetAxisRaw("Horizontal");
        verticalInput = Input.GetAxisRaw("Vertical");
    }

    private void MovePlayer()
    {
        moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;

        rb.AddForce(moveDirection.normalized * moveSpeed * 8f, ForceMode.Force);
    }
    // Update is called once per frame
    private void Update()
    {
        MyInput();
        SpeedControl();
    }

    private void FixedUpdate()
    {
        MovePlayer();
    }

    private void SpeedControl()
    {
        Vector3 flatVel = new Vector3(rb.velocity.x, rb.velocity.y, rb.velocity.z);

        if(flatVel.magnitude > moveSpeed)
        {
            Vector3 limitedVel = flatVel.normalized * moveSpeed;
            rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z);
        }
    }
}

相机控制脚本(NewCamMovement)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewCamMovement : MonoBehaviour
{
    public float sensX;
    public float sensY;
    public Transform orientation;
    float xRotation;
    float yRotation;

    private void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }

    // Update is called once per frame
    void Update()
    {
        float mouseX = Input.GetAxisRaw("Mouse X") * Time.deltaTime * sensX;
        float mouseY = Input.GetAxisRaw("Mouse Y") * Time.deltaTime * sensY;

        yRotation += mouseX;
        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);

        transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
        orientation.rotation = Quaternion.Euler(0, yRotation, 0);
    }
}

解决方案

核心问题分析

  1. 原有脚本穿墙原因:Movement1使用transform.Translate直接修改位置,完全绕过Unity物理引擎,因此Box Collider无法触发碰撞检测。
  2. 新脚本Y轴移动失效原因:NewMovement未处理Y轴输入,且未将Y轴方向加入移动向量;同时需确保Rigidbody设置正确。

修改后的完整移动脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewMovement : MonoBehaviour
{
    [Header("Movement")]
    public float moveSpeed;
    public float verticalMoveSpeed; // 可单独设置上下移动速度,适配水下体验

    public Transform orientation;

    float horizontalInput;
    float verticalInput;
    float verticalYInput; // 上下移动输入

    Vector3 moveDirection;

    Rigidbody rb;

    private void Start()
    {
        rb = GetComponent<Rigidbody>();
        rb.freezeRotation = true;
        rb.useGravity = false; // 水下关闭默认重力,可自定义浮力逻辑
    }

    private void MyInput()
    {
        horizontalInput = Input.GetAxisRaw("Horizontal");
        verticalInput = Input.GetAxisRaw("Vertical");
        // 检测上下移动输入:Space上浮,Left Ctrl下潜
        verticalYInput = 0;
        if (Input.GetKey(KeyCode.Space)) verticalYInput += 1;
        if (Input.GetKey(KeyCode.LeftControl)) verticalYInput -= 1;
    }

    private void MovePlayer()
    {
        // 构建XZ平面移动方向
        Vector3 horizontalMove = orientation.forward * verticalInput + orientation.right * horizontalInput;
        // 加入Y轴移动方向
        moveDirection = horizontalMove.normalized + Vector3.up * verticalYInput;
        
        // 应用移动力:XZ用moveSpeed,Y轴用verticalMoveSpeed(可选分开设置)
        rb.AddForce(horizontalMove.normalized * moveSpeed * 8f + Vector3.up * verticalYInput * verticalMoveSpeed * 8f, ForceMode.Force);
    }

    private void Update()
    {
        MyInput();
        SpeedControl();
    }

    private void FixedUpdate()
    {
        MovePlayer();
    }

    private void SpeedControl()
    {
        // 分离XZ和Y轴速度限制,避免上下移动影响平面速度
        Vector3 flatVel = new Vector3(rb.velocity.x, 0, rb.velocity.z);
        float yVel = rb.velocity.y;

        // 限制XZ平面速度
        if(flatVel.magnitude > moveSpeed)
        {
            Vector3 limitedFlatVel = flatVel.normalized * moveSpeed;
            rb.velocity = new Vector3(limitedFlatVel.x, yVel, limitedFlatVel.z);
        }

        // 限制Y轴速度
        if(Mathf.Abs(yVel) > verticalMoveSpeed)
        {
            rb.velocity = new Vector3(rb.velocity.x, Mathf.Sign(yVel) * verticalMoveSpeed, rb.velocity.z);
        }
    }
}

额外设置说明

  1. Rigidbody配置:确保Rigidbody的Use Gravity关闭,Freeze Rotation勾选(避免玩家旋转),不冻结任何轴;
  2. Collider配置:给Player添加Box Collider或Capsule Collider,并确保墙体等障碍物也有Collider(且标记为Static);
  3. 浮力扩展:若需要模拟水下浮力,可在脚本中添加额外逻辑,比如当玩家未主动上下移动时,缓慢上浮或下沉。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 16:12:06