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

如何控制相机移动时长?需求:5秒内从(0,0,0)移动至(100,0,100)

控制相机指定时长移动的实现方法

核心思路是通过时间进度驱动的线性插值(Lerp),让相机在设定时长内从起点平滑移动到终点。以下是具体实现方案:

通用原理

  1. 提前定义起点位置、终点位置和总移动时长
  2. 记录移动起始时间,每帧计算已流逝时间占总时长的比例(范围0~1)
  3. 用该比例对起点和终点位置做插值,得到相机当前帧的目标位置
  4. 当比例达到1时,将相机直接定位到终点,停止插值

伪代码示例

// 初始化参数
Vector3 startPos = (0, 0, 0)
Vector3 targetPos = (100, 0, 100)
float totalDuration = 5.0f
float startTime = 当前时间戳

// 帧更新逻辑
void Update() {
    float elapsedTime = 当前时间戳 - startTime
    float progress = Math.Clamp(elapsedTime / totalDuration, 0, 1)
    Vector3 currentPos = Lerp(startPos, targetPos, progress)
    设置相机位置为currentPos
    
    if (progress >= 1) {
        停止移动更新
        设置相机位置为targetPos // 确保精准到达
    }
}

Unity C# 实现示例

using UnityEngine;

public class TimedCameraMove : MonoBehaviour
{
    [SerializeField] private Vector3 startPosition = new(0, 0, 0);
    [SerializeField] private Vector3 targetPosition = new(100, 0, 100);
    [SerializeField] private float moveDuration = 5f;
    
    private float _startTime;
    private bool _isMoving;

    void Start()
    {
        StartMove();
    }

    public void StartMove()
    {
        _startTime = Time.time;
        _isMoving = true;
    }

    void Update()
    {
        if (!_isMoving) return;
        
        float elapsedTime = Time.time - _startTime;
        float progress = Mathf.Clamp01(elapsedTime / moveDuration);
        transform.position = Vector3.Lerp(startPosition, targetPosition, progress);
        
        if (progress >= 1f)
        {
            _isMoving = false;
            transform.position = targetPosition;
        }
    }
}

Unreal Engine C++ 实现示例

#include "Camera/CameraActor.h"
#include "TimerManager.h"

class ATimedCameraMove : public ACameraActor
{
    GENERATED_BODY()

public:
    ATimedCameraMove();

protected:
    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override;

public:
    void StartCameraMove(FVector StartPos, FVector TargetPos, float Duration);

private:
    FVector StartPosition;
    FVector TargetPosition;
    float MoveDuration;
    float StartTime;
    bool bIsMoving = false;
};

// .cpp 文件实现
ATimedCameraMove::ATimedCameraMove()
{
    PrimaryActorTick.bCanEverTick = true;
}

void ATimedCameraMove::BeginPlay()
{
    Super::BeginPlay();
    StartCameraMove(FVector(0,0,0), FVector(100,0,100), 5.0f);
}

void ATimedCameraMove::StartCameraMove(FVector StartPos, FVector TargetPos, float Duration)
{
    StartPosition = StartPos;
    TargetPosition = TargetPos;
    MoveDuration = Duration;
    StartTime = GetWorld()->GetTimeSeconds();
    bIsMoving = true;
}

void ATimedCameraMove::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    
    if (!bIsMoving) return;
    
    float ElapsedTime = GetWorld()->GetTimeSeconds() - StartTime;
    float Progress = FMath::Clamp(ElapsedTime / MoveDuration, 0.0f, 1.0f);
    FVector CurrentPos = FMath::Lerp(StartPosition, TargetPosition, Progress);
    SetActorLocation(CurrentPos);
    
    if (Progress >= 1.0f)
    {
        bIsMoving = false;
        SetActorLocation(TargetPosition);
    }
}

额外优化建议

  • 若需要平滑的启停效果,可使用缓动函数替换线性插值,比如Unity的Mathf.SmoothStep或Unreal的FMath::SmoothStep,也可自定义缓动曲线
  • 始终基于时间戳计算进度,避免帧率波动导致移动时长不准确
  • 可增加打断逻辑,通过设置_isMoving/bIsMoving为false随时终止移动

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 20:21:42