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

Play模式下Unity相机初始位置异常偏移问题求助

问题:Unity相机初始位置在Play模式下莫名跳变

我有一个预制体相机,场景编辑模式下的transform.position为:

Scene:Vector3(-2.86999989,1.01999998,-0.810000002)

我在脚本中设置了对应的初始相机位置:

[SerializeField] private Vector3 initialCameraPosition = new Vector3(-2.86999989, 1.01999998, -0.810000002);

原本期望相机从该初始位置开始旋转,但进入Play模式后,相机的transform.position立即被覆盖为:

play:Vector3(-2.72023177,0.810079217,-1.23373544)

场景与Play模式下的位置差值:

X axis: 0.1498
Y axis: -0.2099
Z axis: -0.4237

挂载脚本的Target物体transform.position为Vector3(0,0,0),且已确认:

  • 场景中仅使用1台相机
  • 无其他脚本调用该相机
  • 无其他设置影响相机

附上相关脚本:

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

public class CameraController : MonoBehaviour
{
    [SerializeField] private Transform target; 
    [SerializeField] private Vector3 initialCameraPosition = new Vector3(3f, 1f, 2.5f);
    [SerializeField] private Vector3 initialCameraRotation = new Vector3(30f, 45f, 0f);

    public float sensitivity = 100f; // 旋转灵敏度
    private float _yaw = 0f;         // 当前水平旋转角度
    private float _pitch = 0f;       // 当前垂直旋转角度

    private float minPitch = 5f;     // 最小垂直角度
    private float maxPitch = 90f;    // 最大垂直角度

    private Transform cameraObject;  // 动态查找的相机对象
    private float distanceFromTarget; // 原脚本遗漏的变量定义

    void Start()
    {
        // 查找相机对象(未预先赋值时)
        cameraObject = Camera.main.transform;

        if (target == null)
        {
            Debug.LogError("未指定目标物体(Target)!");
        }

        if (cameraObject == null)
        {
            Debug.LogError("场景中无相机!");
            return;
        }

        // 设置初始位置与旋转角度
        cameraObject.position = initialCameraPosition;
        cameraObject.rotation = Quaternion.Euler(initialCameraRotation);

        // 根据初始位置计算与目标的距离和旋转角度
        Vector3 targetDirection = cameraObject.position - target.position;
        distanceFromTarget = targetDirection.magnitude;

        _yaw = initialCameraRotation.y; // 从初始旋转获取yaw值
        _pitch = initialCameraRotation.x; // 从初始旋转获取pitch值
    }

    void Update()
    {
        HandleInput();

        // 限制pitch值范围
        _pitch = Mathf.Clamp(_pitch, minPitch, maxPitch);

        // 围绕目标旋转相机
        RotateCamera();
    }

    private void HandleInput()
    {
        Vector2 inputDelta = Vector2.zero;

        // 移动端触摸输入
        if (Input.touchCount > 0)
        {
            Touch touch = Input.GetTouch(0);
            inputDelta = touch.deltaPosition;
        }
        // 鼠标输入
        else if (Input.GetMouseButton(0))
        {
            inputDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
        }

        // 更新旋转角度
        _yaw += inputDelta.x * sensitivity * Time.deltaTime;
        _pitch -= inputDelta.y * sensitivity * Time.deltaTime;
    }

    private void RotateCamera()
    {
        // 计算围绕目标的旋转角度
        Quaternion rotation = Quaternion.Euler(_pitch, _yaw, 0f);
        Vector3 positionOffset = rotation * new Vector3(0, 0, -distanceFromTarget);

        // 设置相机位置与旋转角度
        cameraObject.position = target.position + positionOffset;
        cameraObject.LookAt(target);
    }
}

问题原因

核心问题是**Start()设置初始位置后,第一帧Update()执行的RotateCamera()直接覆盖了相机位置**:

  1. Start()中你手动设置了相机初始位置,但同时用initialCameraRotation直接赋值给_yaw和_pitch
  2. 你设置的初始位置initialCameraPosition,和初始旋转initialCameraRotation对应的围绕目标点的位置并不匹配
  3. 进入Play模式后第一帧,RotateCamera()会用_pitch和_yaw重新计算相机位置,这个新位置和你手动设置的初始位置不一致,导致跳变

解决方案

需要让_yaw和_pitch从初始相机位置反向计算,而非直接使用预设的旋转值,保证初始位置和旋转逻辑匹配。修改Start()方法中的旋转值计算部分:

void Start()
{
    // ... 其他代码不变

    // 设置初始位置
    cameraObject.position = initialCameraPosition;

    // 根据初始位置计算与目标的距离
    Vector3 targetDirection = cameraObject.position - target.position;
    distanceFromTarget = targetDirection.magnitude;

    // 从初始位置反向计算yaw和pitch,保证和初始位置匹配
    _yaw = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg;
    _pitch = Mathf.Asin(targetDirection.y / distanceFromTarget) * Mathf.Rad2Deg;
    _pitch = Mathf.Clamp(_pitch, minPitch, maxPitch);

    // 让相机朝向目标
    cameraObject.LookAt(target);
}

同时确保脚本中补充distanceFromTarget的变量声明:

private float distanceFromTarget;

修改后,初始位置会保持你设置的值,_yaw和_pitch由初始位置推导而来,第一帧RotateCamera()计算的位置和初始位置完全一致,不会出现跳变。


内容的提问来源于stack exchange,提问作者Cirill Parnò

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 00:17:15