场景里面只有一个主相机MainCamera,写一函数,传入目标点的位置和旋转角度,点击按钮,使当前相机跳转到目标点镜头,相机跳转过程中部僵硬,过渡平滑。为了封装复用,写成单例的形式,方便其他页面调用。

效果如下所示:

点击前

点击后

项目结构如下:

完整代码:

CameraSwitcher.cs

using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 相机切换控制器 - 提供平滑的相机位置和旋转过渡功能
/// 使用单例模式设计,确保全局唯一实例并可静态访问
/// </summary>
public class CameraSwitcher : MonoBehaviour
{
    // 单例实例引用,外部可通过CameraSwitcher.Instance访问
    public static CameraSwitcher Instance { get; private set; }

    [Header("配置")]
    // 要控制的主相机
    public Camera mainCamera;
    // 相机过渡动画持续时间(秒)
    public float transitionDuration = 1.0f;
    // 控制过渡速度的动画曲线,默认使用缓入缓出效果
    public AnimationCurve transitionCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);

    // 相机是否正在过渡中
    private bool isTransitioning = false;

    void Awake()
    {
        // 单例模式初始化:确保场景中只有一个CameraSwitcher实例
        if (Instance == null)
            Instance = this;
        else
            Destroy(gameObject); // 销毁重复的实例

        // 自动获取相机引用(如果未手动指定)
        if (mainCamera == null)
            mainCamera = GetComponent<Camera>();
    }

    /// <summary>
    /// 平滑切换相机到指定位置和旋转
    /// </summary>
    /// <param name="targetPosition">目标位置</param>
    /// <param name="targetRotation">目标旋转(四元数)</param>
    public static void SwitchTo(Vector3 targetPosition, Quaternion targetRotation)
    {
        // 安全检查:确保实例存在且未在过渡中
        if (Instance == null || Instance.isTransitioning)
            return;

        // 启动相机过渡协程
        Instance.StartCoroutine(Instance.MoveCameraSmoothly(targetPosition, targetRotation));
    }

    /// <summary>
    /// 相机平滑过渡的协程实现
    /// </summary>
    /// <param name="targetPosition">目标位置</param>
    /// <param name="targetRotation">目标旋转</param>
    private System.Collections.IEnumerator MoveCameraSmoothly(Vector3 targetPosition, Quaternion targetRotation)
    {
        // 标记为过渡中,防止重复触发
        isTransitioning = true;

        // 记录起始位置和旋转
        Vector3 startPosition = mainCamera.transform.position;
        Quaternion startRotation = mainCamera.transform.rotation;
        float elapsedTime = 0;

        // 随时间进行插值过渡
        while (elapsedTime < transitionDuration)
        {
            // 基于动画曲线计算插值因子(0-1范围)
            float t = transitionCurve.Evaluate(elapsedTime / transitionDuration);

            // 线性插值计算当前位置和旋转
            mainCamera.transform.position = Vector3.Lerp(startPosition, targetPosition, t);
            mainCamera.transform.rotation = Quaternion.Slerp(startRotation, targetRotation, t);

            // 更新已过时间
            elapsedTime += Time.deltaTime;

            // 暂停协程,等待下一帧
            yield return null;
        }

        // 确保最终位置精确对齐(避免浮点误差)
        mainCamera.transform.position = targetPosition;
        mainCamera.transform.rotation = targetRotation;

        // 标记过渡完成
        isTransitioning = false;
    }
}

UIManger.cs

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

public class UIManger : MonoBehaviour
{
    public Button switchButton;
    void Start()
    {
        if (switchButton != null)
        {
            switchButton.onClick.AddListener(() => {
                CameraSwitcher.SwitchTo(new Vector3(17.84f, 1.64f, -0.38f), Quaternion.Euler(0, -90, 0));

            });
        }
    }

    void Update()
    {
        
    }
}
 

更多推荐