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

Unity3D爬墙功能欧拉角限制异常:进入触发器时视角骤跳

爬墙视角骤跳问题修复方案

问题根源很明确:你进入爬墙状态时,直接把玩家Y轴角度硬卡到全局固定的[-20,20]区间,不管玩家当时朝向哪里,自然会出现视角跳变。下面给两种可行的修复思路:

思路1:基于爬墙初始朝向限制旋转

进入爬墙状态时,先记录玩家当前的Y轴角度作为基准,后续只允许在这个基准的±20度范围内旋转,避免硬拉视角。

修改代码如下:

private float minYRot = -20f;
private float maxYRot = 20f;
// 新增:记录爬墙开始时的基准Y轴角度
private float climbStartYRot;

// 替换原来的触发调用逻辑,进入触发器时调用这个方法初始化基准角度
public void StartWallClimb()
{
    wallClimb.climbing = true;
    // 把当前玩家Y轴角度转成-180到180的范围
    float currentY = player.rotation.eulerAngles.y;
    climbStartYRot = currentY > 180 ? currentY - 360 : currentY;
}

public void LateUpdate()
{
    float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
    float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

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

    transform.eulerAngles = new Vector3(xRotation, player.rotation.eulerAngles.y, 0f);
    
    // 分状态处理旋转:非爬墙正常转,爬墙时按限制规则转
    if (!wallClimb.climbing)
    {
        player.transform.Rotate(Vector3.up * mouseX);
    }
    else
    {
        LimitRotation(mouseX);
    }
}

// 修改限制逻辑,基于基准角度做范围约束
public void LimitRotation(float mouseX)
{
    float currentY = player.rotation.eulerAngles.y;
    currentY = currentY > 180 ? currentY - 360 : currentY;
    // 计算加上鼠标输入后的临时角度
    float tempY = currentY + mouseX;
    
    // 基于爬墙初始角度做clamp
    tempY = Mathf.Clamp(tempY, climbStartYRot + minYRot, climbStartYRot + maxYRot);
    
    // 应用最终旋转
    player.rotation = Quaternion.Euler(player.rotation.eulerAngles.x, tempY, player.rotation.eulerAngles.z);
}

思路2:基于墙体朝向限制旋转(更符合爬墙逻辑)

爬墙时玩家的旋转应该相对于墙体朝向,比如面朝墙体时只能左右转20度。这种情况需要在进入触发器时记录墙体的朝向:

private float minYRot = -20f;
private float maxYRot = 20f;
// 新增:记录墙体前方向的Y轴角度(转成-180到180范围)
private float wallForwardYRot;

// 进入触发器时调用,传入墙体的Transform
public void StartWallClimb(Transform wallTransform)
{
    wallClimb.climbing = true;
    float wallY = wallTransform.forward.eulerAngles.y;
    wallForwardYRot = wallY > 180 ? wallY - 360 : wallY;
}

public void LateUpdate()
{
    float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
    float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

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

    transform.eulerAngles = new Vector3(xRotation, player.rotation.eulerAngles.y, 0f);
    
    if (!wallClimb.climbing)
    {
        player.transform.Rotate(Vector3.up * mouseX);
    }
    else
    {
        LimitRotation(mouseX);
    }
}

public void LimitRotation(float mouseX)
{
    // 计算玩家当前相对于墙体的角度
    float currentPlayerY = player.rotation.eulerAngles.y;
    currentPlayerY = currentPlayerY > 180 ? currentPlayerY - 360 : currentPlayerY;
    float relativeY = currentPlayerY - wallForwardYRot;
    
    // 加上鼠标输入的旋转量后限制范围
    relativeY += mouseX;
    relativeY = Mathf.Clamp(relativeY, minYRot, maxYRot);
    
    // 转成全局角度应用
    float targetY = wallForwardYRot + relativeY;
    player.rotation = Quaternion.Euler(player.rotation.eulerAngles.x, targetY, player.rotation.eulerAngles.z);
}

补充触发器调用逻辑

需要在墙体触发器的OnTriggerEnter方法里调用初始化方法,而不是直接在LateUpdate里触发限制:

private void OnTriggerEnter(Collider other)
{
    if (other.CompareTag("Wall"))
    {
        // 用思路1就调用StartWallClimb(),思路2则传墙体Transform
        StartWallClimb(other.transform);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 19:05:05