mcpField
U
ue-gameplay-cameras

ue-gameplay-cameras

github.com/quodsoler开发419247 次安装4 周前更新
代码仓库

关于 ue-gameplay-cameras

ue-gameplay-cameras 是面向 Unreal Engine 5.8 项目的摄像机开发参考 Skill,供开发者实现和排查游戏摄像机功能。内容覆盖经典摄像机栈与实验性的 Gameplay Camera System,并提供 API 指引和代码示例。

主要功能

  1. 01比较两种摄像机系统
  2. 02第三人称与第一人称摄像机配置
  3. 03视点目标切换与混合
  4. 04自定义 Camera Manager 与 Modifier
  5. 05摄像机抖动、电影摄像机及调试

适用场景

  1. 01为 Unreal Engine 5.8 配置角色摄像机
  2. 02实现摄像机视点切换和过渡
  3. 03排查画面缺失、错误视角或抖动

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/quodsoler/unreal-engine-skills --skill ue-gameplay-cameras

安装后在 Claude Code 中输入/ue-gameplay-cameras确认已加载。

附带文件references/classic-camera-stack.mdreferences/gameplay-camera-system.md

详细介绍

UE Gameplay Cameras

目标引擎:UE 5.8。以下 API 已根据 5.8 头文件验证;旧形式列在“已弃用 — 请勿使用”下。

5.8 中提供两种摄像机堆栈。经典堆栈位于 Engine 模块(Classes/Camera、Classes/GameFramework/SpringArmComponent.h),摄像机震动模式位于 EngineCameras 插件中,电影风格摄像机位于 CinematicCamera 中;数据驱动的 Gameplay Camera System 位于 GameplayCameras 插件中(在 5.8 中为实验性功能,但默认启用)。Build.cs 需要 "Core"、"CoreUObject"、"Engine",以及用于电影摄像机的 "CinematicCamera"、用于震动模式的 "EngineCameras" 和用于插件的 "GameplayCameras"。

上下文

如果 .agents/ue-project-context.md 存在,请阅读它(模块名称、约定、已启用的插件、GAS/网络设置)。如果文件不存在,请继续。

根据请求和代码库确定相关领域。只有在两种合理的理解会导致不同代码时才提问。

请求涉及……前往
在两种堆栈之间选择经典堆栈还是 Gameplay Camera System
谁在每帧计算最终视图经典管线的运行方式
第三人称弹簧臂、摄像机延迟、碰撞探测第三人称弹簧臂摄像机
第一人称摄像机、眼睛高度、视图旋转第一人称摄像机
切换摄像机、在角色之间混合视图目标与混合
俯仰角限制、FOV、淡入淡出、自定义摄像机逻辑自定义 APlayerCameraManager
摄像机上的持久后期效果(倾斜、后坐力、锁定目标)摄像机修饰器
爆炸、命中、世界空间震动摄像机震动
焦距、光圈、对焦、轨道和摇臂电影摄像机
摄像机资源、Rig、导演、混合、控制旋转Gameplay Camera System
用 C++ 编写新的摄像机节点和求值器C++ 中的自定义摄像机节点
没有画面、摄像机错误、抖动摄像机调试

完整的经典 API 范围(摄像机上的后期处理、FMinimalViewInfo 字段、震动模式目录、电影摄像机设置):references/classic-camera-stack.md。节点/导演/服务目录、摄像机变量、求值上下文和 CVar:references/gameplay-camera-system.md。

经典堆栈还是 Gameplay Camera System

需求经典堆栈Gameplay Camera System
即刻投入生产的稳定性是 — 生产级 API插件在 5.8 中为实验性功能(GameplayCameras.uplugin 中的 IsExperimentalVersion),API 仍在变化
开箱即用始终可用(Engine 模块)是 — "EnabledByDefault": true
每个 Pawn 一个摄像机、少量模式最适合功能过剩
多种摄像机模式,包含创作好的混合和过渡在 UpdateViewTarget 中手写状态机内置:摄像机 Rig + 过渡 + 混合堆栈
设计师无需 C++ 即可创作摄像机仅限 Blueprint 子类摄像机资源、Rig 图表、State Tree 导演
每种模式的后期处理、构图、碰撞推移自行编写内置摄像机节点
摄像机震动UCameraShakeBase + 模式UCameraShakeAsset + 震动摄像机节点

支持混合使用:AGameplayCamerasPlayerCameraManager 是 APlayerCameraManager 的子类,因此插件运行求值时,经典视图目标、淡入淡出和修饰器仍可使用。

经典管线的运行方式

  1. APlayerController 持有 PlayerCameraManager(由 virtual void SpawnPlayerCameraManager() 从 TSubclassOf<APlayerCameraManager> PlayerCameraManagerClass 生成)。
  2. APlayerCameraManager::UpdateCamera(float DeltaTime) → DoUpdateCamera(float DeltaTime) → UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime)。
  3. UpdateViewTarget 填充 OutVT.POV(一个 FMinimalViewInfo)。ACameraActor 目标会直接使用其摄像机组件;其他目标则调用 Target->CalcCamera(PlayerCameraManager.cpp:354),其基类 AActor 实现会在 bFindCameraComponentWhenViewTarget 为 true 时使用第一个启用的摄像机组件,否则使用 Actor 的眼睛视点(Actor.cpp:3688-3706)。
  4. ApplyCameraModifiers(float DeltaTime, FMinimalViewInfo& InOutPOV) 会按 Priority(0 = 最高)运行 ModifierList 中的每个 UCameraModifier。
  5. 结果会被缓存;GetCameraLocation()、GetCameraRotation() 和 GetCameraCacheView() 会读取该结果,而 APlayerController::GetPlayerViewPoint(FVector& out_Location, FRotator& out_Rotation) 会返回该结果。

APlayerController 上的 bAutoManageActiveCameraTarget(默认值为 true)会使占有时调用 virtual void AutoManageActiveCameraTarget(AActor* SuggestedTarget),这就是为什么刚被占有的 Pawn 无需编写代码就会成为视图目标。

第三人称弹簧臂摄像机

// MyCharacter.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"

class UCameraComponent;
class USpringArmComponent;

UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    AMyCharacter();

private:
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera", meta = (AllowPrivateAccess = "true"))
    TObjectPtr<USpringArmComponent> CameraBoom;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera", meta = (AllowPrivateAccess = "true"))
    TObjectPtr<UCameraComponent> FollowCamera;
};

// MyCharacter.cpp - also include Camera/CameraComponent.h,
// GameFramework/SpringArmComponent.h and GameFramework/CharacterMovementComponent.h
#include "MyCharacter.h"

AMyCharacter::AMyCharacter()
{
    bUseControllerRotationPitch = false;
    bUseControllerRotationYaw   = false;
    bUseControllerRotationRoll  = false;

    GetCharacterMovement()->bOrientRotationToMovement = true;
    GetCharacterMovement()->RotationRate = FRotator(0.f, 500.f, 0.f);

    CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
    CameraBoom->SetupAttachment(RootComponent);
    CameraBoom->TargetArmLength = 400.f;
    CameraBoom->bUsePawnControlRotation = true;
    CameraBoom->bInheritPitch = true;
    CameraBoom->bInheritYaw = true;
    CameraBoom->bInheritRoll = false;
    CameraBoom->SocketOffset = FVector(0.f, 60.f, 0.f);
    CameraBoom->TargetOffset = FVector(0.f, 0.f, 50.f);
    CameraBoom->bDoCollisionTest = true;
    CameraBoom->ProbeChannel = ECC_Camera;
    CameraBoom->ProbeSize = 12.f;
    CameraBoom->bEnableCameraLag = true;
    CameraBoom->CameraLagSpeed = 10.f;
    CameraBoom->CameraLagMaxDistance = 100.f;

    FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
    FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
    FollowCamera->bUsePawnControlRotation = false;
    FollowCamera->FieldOfView = 90.f;
}

SocketOffset 会应用于弹簧臂的旋转空间(侧向偏移会跟随摄像机);TargetOffset 会应用于世界空间(高度偏移会保持垂直)。bUsePawnControlRotation 只能设置在弹簧臂或摄像机其中之一上——两者都设置会重复应用控制旋转。使用 FRotator GetTargetRotation() const 读取弹簧臂继承的旋转(来自父级或控制旋转),并使用 bool IsCollisionFixApplied() const 检查碰撞探测是否缩短了弹簧臂。

第一人称摄像机

将 UCameraComponent 直接附加到网格体或胶囊体上,在摄像机上设置 bUsePawnControlRotation = true,并在 Pawn 上保持 bUseControllerRotationYaw = true,这样身体就会随视角转动。

// MyFirstPersonCharacter.h - inside the class body
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
TObjectPtr<UCameraComponent> FirstPersonCamera;

// MyFirstPersonCharacter.cpp - also include Camera/CameraComponent.h and Components/CapsuleComponent.h
AMyFirstPersonCharacter::AMyFirstPersonCharacter()
{
    bUseControllerRotationYaw = true;

    FirstPersonCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
    FirstPersonCamera->SetupAttachment(GetCapsuleComponent());
    FirstPersonCamera->SetRelativeLocation(FVector(0.f, 0.f, BaseEyeHeight));
    FirstPersonCamera->bUsePawnControlRotation = true;
    FirstPersonCamera->bEnableFirstPersonFieldOfView = true;
    FirstPersonCamera->bEnableFirstPersonScale = true;
    FirstPersonCamera->FirstPersonFieldOfView = 70.f;
    FirstPersonCamera->FirstPersonScale = 0.6f;
}

FirstPersonFieldOfView 和 FirstPersonScale 只会影响标记为第一人称的图元,并且两者都需要设置各自的 bEnable* 标志。APawn::BaseEyeHeight 会影响 virtual FVector GetPawnViewLocation() const;要处理蹲下时的情况,请重写 virtual void RecalculateBaseEyeHeight()。virtual FRotator GetViewRotation() const 是弹簧臂和 AI 感知使用的瞄准旋转。要自行计算视角,请重写 AActor::CalcCamera,且不要调用 Super——对于非 ACameraActor 视图目标,始终会运行你的重写实现;摄像机组件查找逻辑位于基类实现中(Actor.cpp:3690)。只有在调用 Super 且希望它跳过摄像机组件时,才设置 bFindCameraComponentWhenViewTarget = false。

// MyViewTargetActor.cpp - declare the override in the class body, include Camera/CameraTypes.h
void AMyViewTargetActor::CalcCamera(float DeltaTime, struct FMinimalViewInfo& OutResult)
{
    OutResult.Location = GetActorLocation() + FVector(0.f, 0.f, 150.f);
    OutResult.Rotation = GetActorRotation();
    OutResult.FOV = 75.f;
}

视角目标与混合

// Inside a method of a MyGame class that has a PlayerController - include GameFramework/PlayerController.h
void AMyPlayerController::FocusOnActor(AActor* NewTarget)
{
    SetViewTargetWithBlend(NewTarget, 0.75f, VTBlend_EaseInOut, 2.f, false);
}

要实现此功能,请使用 virtual void SetViewTargetWithBlend(class AActor* NewViewTarget, float BlendTime = 0, enum EViewTargetBlendFunction BlendFunc = VTBlend_Linear, float BlendExp = 0, bool bLockOutgoing = false)。EViewTargetBlendFunction 的取值包括:VTBlend_Linear、VTBlend_Cubic、VTBlend_EaseIn、VTBlend_EaseOut、VTBlend_EaseInOut、VTBlend_PreBlended。BlendExp 仅对三种 ease 函数有效。bLockOutgoing 会在整个混合过程中冻结旧目标的 POV——如果即将传送或销毁旧目标,请使用它。

管理器级的形式是 virtual void SetViewTarget(class AActor* NewViewTarget, FViewTargetTransitionParams TransitionParams = FViewTargetTransitionParams()),其中 FViewTargetTransitionParams 包含 BlendTime、BlendFunction、BlendExp 和 bLockOutgoing。混合期间,管理器会持有 ViewTarget 和 PendingViewTarget(二者均为 FTViewTarget,各自包含 Target 和 POV),并倒计时 BlendTimeToGo;待处理目标升为当前目标时会触发 OnBlendComplete()。

SetViewTarget 和 SetViewTargetWithBlend 仅作用于调用机器上的摄像机管理器——不会进行网络复制。若要从服务器更改某个客户端的视角,请调用客户端 RPC UFUNCTION(Reliable, Client) void ClientSetViewTarget(class AActor* A, struct FViewTargetTransitionParams TransitionParams = FViewTargetTransitionParams())。

自定义 APlayerCameraManager

// MyCameraManager.h
#pragma once

#include "CoreMinimal.h"
#include "Camera/PlayerCameraManager.h"
#include "MyCameraManager.generated.h"

UCLASS()
class MYGAME_API AMyCameraManager : public APlayerCameraManager
{
    GENERATED_BODY()

public:
    AMyCameraManager(const FObjectInitializer& ObjectInitializer);

protected:
    virtual void UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime) override;

    UPROPERTY(EditDefaultsOnly, Category = "Aim")
    float AimFieldOfView = 55.f;
    UPROPERTY(BlueprintReadWrite, Category = "Aim")
    bool bIsAiming = false;
};

// MyCameraManager.cpp
#include "MyCameraManager.h"

AMyCameraManager::AMyCameraManager(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    ViewPitchMin = -70.f;
    ViewPitchMax = 55.f;
    DefaultFOV = 90.f;
}

void AMyCameraManager::UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime)
{
    Super::UpdateViewTarget(OutVT, DeltaTime);

    if (bIsAiming)
    {
        OutVT.POV.FOV = AimFieldOfView;
    }
}

在 APlayerController 构造函数中设置 PlayerCameraManagerClass = AMyCameraManager::StaticClass(); 来注册它。其他值得了解的钩子包括:virtual void InitializeFor(class APlayerController* PC)、virtual void ProcessViewRotation(float DeltaTime, FRotator& OutViewRotation, FRotator& OutDeltaRot),以及用于限制角度的辅助函数 LimitViewPitch、LimitViewYaw、LimitViewRoll。

淡入淡出由管理器执行:virtual void StartCameraFade(float FromAlpha, float ToAlpha, float Duration, FLinearColor Color, bool bShouldFadeAudio = false, bool bHoldWhenFinished = false)、virtual void StopCameraFade();如果要自行控制 Alpha,则使用 virtual void SetManualCameraFade(float InFadeAmount, FLinearColor Color, bool bInFadeAudio)。APlayerController::ClientSetCameraFade 是用于网络复制的封装函数。

摄像机修饰器

修饰器是一种有状态的对象,每帧都会对计算出的 POV 进行后处理——例如倾斜、后坐力、呼吸效果和锁定目标微调。

// MyCameraModifier.h
#pragma once

#include "CoreMinimal.h"
#include "Camera/CameraModifier.h"
#include "MyCameraModifier.generated.h"

UCLASS()
class MYGAME_API UMyCameraModifier : public UCameraModifier
{
    GENERATED_BODY()

public:
    UMyCameraModifier(const FObjectInitializer& ObjectInitializer);

    virtual bool ModifyCamera(float DeltaTime, struct FMinimalViewInfo& InOutPOV) override;

    UPROPERTY(EditDefaultsOnly, Category = "Lean")
    float LeanRollDegrees = 8.f;
};

// MyCameraModifier.cpp
#include "MyCameraModifier.h"
#include "Camera/CameraTypes.h"   // FMinimalViewInfo is only forward-declared by CameraModifier.h

UMyCameraModifier::UMyCameraModifier(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
    Priority = 10;
    AlphaInTime = 0.2f;
    AlphaOutTime = 0.3f;
}

bool UMyCameraModifier::ModifyCamera(float DeltaTime, struct FMinimalViewInfo& InOutPOV)
{
    Super::ModifyCamera(DeltaTime, InOutPOV);

    InOutPOV.Rotation.Roll += LeanRollDegrees * Alpha;
    return false;
}

仅当要阻止优先级较低的修饰器运行时,才返回 true。Alpha 根据 AlphaInTime/AlphaOutTime 由 virtual void UpdateAlpha(float DeltaTime) 驱动;目标值由 virtual float GetTargetAlpha() 决定。可通过 virtual void EnableModifier()、virtual void DisableModifier(bool bImmediate = false) 和 virtual void ToggleModifier() 切换状态;virtual bool IsDisabled() const 会返回当前状态。

可通过管理器上的 TArray<TSubclassOf<UCameraModifier>> DefaultModifiers 声明式添加修饰器,也可在运行时调用 virtual UCameraModifier* AddNewCameraModifier(TSubclassOf<UCameraModifier> ModifierClass) 添加,它会实例化、注册并返回修饰器。之后可通过 virtual UCameraModifier* FindCameraModifierByClass(TSubclassOf<UCameraModifier> ModifierClass) 获取修饰器;virtual bool RemoveCameraModifier(UCameraModifier* ModifierToRemove) 可将其移除。virtual bool ProcessViewRotation(class AActor* ViewTarget, float DeltaTime, FRotator& OutViewRotation, FRotator& OutDeltaRot) 允许修饰器在生成 POV 之前调整玩家的瞄准方向。

摄像机震动

UCameraShakeBase 是一个轻量级容器;运动效果由其 RootShakePattern(一个 UCameraShakePattern)实现。在 C++ 中,你可以继承一个模式——通常是已提供 Duration、BlendInTime 和 BlendOutTime 的 USimpleCameraShakePattern——并重写 virtual void UpdateShakePatternImpl(const FCameraShakePatternUpdateParams& Params, FCameraShakePatternUpdateResult& OutResult),将结果写入 OutResult.Location、OutResult.Rotation 和 OutResult.FOV;使用 State.Update(Params.DeltaTime) 推进继承的 State,并按其返回的权重进行缩放,否则震动将无法结束。完整示例:references/classic-camera-stack.md。UCameraShakePattern 上的其他模式钩子包括 GetShakePatternInfoImpl(FCameraShakeInfo& OutInfo) const、StartShakePatternImpl(const FCameraShakePatternStartParams& Params)、ScrubShakePatternImpl(const FCameraShakePatternScrubParams& Params, FCameraShakePatternUpdateResult& OutResult)、IsFinishedImpl() const、StopShakePatternImpl(const FCameraShakePatternStopParams& Params) 和 TeardownShakePatternImpl()。

内置模式(模块 "EngineCameras"):UPerlinNoiseCameraShakePattern、UWaveOscillatorCameraShakePattern、UCompositeCameraShakePattern,以及由 ULegacyCameraShake 控制的 ULegacyCameraShakePattern。USequenceCameraShakePattern 使用 UCameraAnimationSequence 驱动震动,位于 TemplateSequence 插件中。UDefaultCameraShakeBase 是一个根模式默认为 Perlin 噪声的 UCameraShakeBase,通常用作 Blueprint 的起点。播放震动:

调用位置用途
APlayerCameraManager::StartCameraShake(TSubclassOf<UCameraShakeBase> ShakeClass, float Scale=1.f, ECameraShakePlaySpace PlaySpace = ECameraShakePlaySpace::CameraLocal, FRotator UserPlaySpaceRot = FRotator::ZeroRotator)本地直接播放,仅限本地玩家
APlayerController::ClientStartCameraShake(TSubclassOf<class UCameraShakeBase> Shake, float Scale = 1.f, ECameraShakePlaySpace PlaySpace = ECameraShakePlaySpace::CameraLocal, FRotator UserPlaySpaceRot = FRotator::ZeroRotator)服务器 → 单个客户端服务器驱动的反馈
UGameplayStatics::PlayWorldCameraShake(const UObject* WorldContextObject, TSubclassOf<class UCameraShakeBase> Shake, FVector Epicenter, float InnerRadius, float OuterRadius, float Falloff = 1.f, bool bOrientShakeTowardsEpicenter = false)本地、径向爆炸
UCameraShakeSourceComponent::StartCameraShake(TSubclassOf<UCameraShakeBase> InCameraShake, float Scale=1.f, ECameraShakePlaySpace PlaySpace = ECameraShakePlaySpace::CameraLocal, FRotator UserPlaySpaceRot = FRotator::ZeroRotator)本地、带衰减持续引发震动的机器

使用 APlayerController::ClientStopCameraShake(TSubclassOf<class UCameraShakeBase> Shake, bool bImmediately = true)、APlayerCameraManager::StopAllCameraShakes(bool bImmediately = true) 或 StopAllCameraShakesFromSource(UCameraShakeSourceComponent* SourceComponent, bool bImmediately = true) 停止震动。ECameraShakePlaySpace 可设为 CameraLocal、World 或 UserDefined。UCameraShakeSourceComponent 包含 Attenuation(ECameraShakeAttenuation)、InnerAttenuationRadius、OuterAttenuationRadius、CameraShake 和 bAutoStart;ACameraShakeSourceActor 是可放置的封装类。

震动由 UCameraModifier_CameraShake 应用,该修饰器默认由管理器创建;如果需要使用 FAddCameraShakeParams::DurationOverride 或自定义初始化器,可通过低级入口 virtual UCameraShakeBase* AddCameraShake(TSubclassOf<UCameraShakeBase> NewShake, const FAddCameraShakeParams& Params) 添加震动。

电影摄影机

UCineCameraComponent 通过物理摄影机设置扩展了 UCameraComponent:Filmback(FCameraFilmbackSettings)、LensSettings(FCameraLensSettings)、FocusSettings(FCameraFocusSettings)、CurrentFocalLength、CurrentAperture、CurrentFocusDistance 和 CurrentHorizontalFOV。通过设置器(SetFilmback、SetLensSettings、SetFocusSettings、void SetCurrentFocalLength(float InFocalLength)、void SetCurrentAperture(const float NewCurrentAperture))控制这些属性,以便重新计算派生值。ACineCameraActor 添加了 LookatTrackingSettings(FCameraLookatTrackingSettings)。ACameraRig_Rail 提供 CurrentPositionOnRail(沿样条线的位置,范围为 0–1)和 bLockOrientationToRail;ACameraRig_Crane 提供 CranePitch、CraneYaw、CraneArmLength、bLockMountPitch 和 bLockMountYaw。将摄影机 Actor 附加到任一装置,并为公开的浮点属性设置动画。Sequencer 的相关功能归属:摄影机切换、可生成对象、ULevelSequencePlayer 和镜头录制属于 ue-sequencer-cinematics。此技能涵盖摄影机对象本身。

Gameplay Camera System

GameplayCameras 插件(在 5.8 中为实验性功能)默认已启用。UCameraAsset 包含一个 UCameraDirector 以及进入/退出过渡;Director 每帧会选择要运行的 UCameraRigAsset;Rig 是以 RootNode 为根节点的 UCameraNode 对象树;运行时系统会在混合堆栈上混合各个 Rig,并输出 FMinimalViewInfo。将 UGameplayCameraComponent 添加到 Pawn 上,并为其指定一个 Camera Asset:

// MyGameplayCameraCharacter.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyGameplayCameraCharacter.generated.h"

class UGameplayCameraComponent;

UCLASS()
class MYGAME_API AMyGameplayCameraCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    AMyGameplayCameraCharacter();

    virtual void BeginPlay() override;

private:
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera", meta = (AllowPrivateAccess = "true"))
    TObjectPtr<UGameplayCameraComponent> GameplayCamera;
};

// MyGameplayCameraCharacter.cpp - also include GameFramework/GameplayCameraComponent.h
#include "MyGameplayCameraCharacter.h"

AMyGameplayCameraCharacter::AMyGameplayCameraCharacter()
{
    GameplayCamera = CreateDefaultSubobject<UGameplayCameraComponent>(TEXT("GameplayCamera"));
    GameplayCamera->SetupAttachment(RootComponent);
}

void AMyGameplayCameraCharacter::BeginPlay()
{
    Super::BeginPlay();

    if (APlayerController* PC = Cast<APlayerController>(GetController()))
    {
        if (PC->IsLocalController())
        {
            GameplayCamera->ActivateCameraForPlayerController(PC, true);
        }
    }
}

在 FCameraAssetReference CameraReference 上设置 Asset(该属性取代了旧的直接 UCameraAsset 指针)。激活 API 位于 UGameplayCameraComponentBase 中:void ActivateCameraForPlayerIndex(int32 PlayerIndex, bool bSetAsViewTarget = true)、void ActivateCameraForPlayerController(APlayerController* PlayerController, bool bSetAsViewTarget = true),以及从 UActorComponent 继承的 Deactivate()。实用状态包括:bRunStandaloneCameraSystem、bSetControlRotationWhenViewTarget、DefaultPlayer、FRotator GetEvaluatedCameraRotation() const 和 UCineCameraComponent* GetOutputCameraComponent() const——输出为 cine camera,因此镜头和对焦设置都可直接使用。

类作用
UGameplayCameraComponent / AGameplayCameraActor在自身的评估上下文中运行 UCameraAsset
UGameplayCameraRigComponent / AGameplayCameraRigActor运行单个 UCameraRigAsset,无需创建 Camera Asset
UGameplayCameraSystemComponent / AGameplayCameraSystemActor承载摄像机系统本身;ActivateCameraSystemForPlayerController(APlayerController*)、DeactivateCameraSystem(AActor* NextViewTarget = nullptr)、bSetPlayerControllerRotation
AGameplayCamerasPlayerCameraManager运行该系统的 APlayerCameraManager 子类;提供 ActivateGameplayCamera,以及仅限 Blueprint 使用(未导出,从 C++ 调用会导致链接错误)的 StealPlayerController / ReleasePlayerController
UGameplayControlRotationComponent使玩家的控制旋转与摄像机保持同步;提供 AxisActions、AutoActivateForPlayer;其 ActivateControlRotationManagementFor* 函数未导出,仅限 Blueprint 使用(GameplayControlRotationComponent.h:40-53)

5.8 随附的摄像机 Director:USingleCameraDirector(一个 CameraRig)、UBlueprintCameraDirector(运行 UBlueprintCameraDirectorEvaluator 子类——实现 RunCameraDirector 并调用 ActivateCameraRig)、UStateTreeCameraDirector(使用 UCameraDirectorStateTreeSchema 构建的 FStateTreeReference),以及 UPriorityQueueCameraDirector。

无需改动 Director 即可在运行时控制 Rig,可通过组件和摄像机管理器完成:FCameraRigInstanceID ActivatePersistentBaseCameraRig(UCameraRigAsset* CameraRig)(另有 Global 和 Visual 变体)、void DeactivateCameraRig(FCameraRigInstanceID InstanceID, bool bImmediately = false)、FCameraRigInstanceID StartGlobalCameraModifierRig(const UCameraRigAsset* CameraRig, int32 OrderKey = 0) / StartVisualCameraModifierRig / void StopCameraModifierRig(FCameraRigInstanceID InstanceID, bool bImmediately = false)。震屏使用 FCameraShakeInstanceID StartCameraShakeAsset(const UCameraShakeAsset* CameraShake, float ShakeScale = 1.f, ECameraShakePlaySpace PlaySpace = ECameraShakePlaySpace::CameraLocal, FRotator UserPlaySpaceRotation = FRotator::ZeroRotator) 和 bool StopCameraShakeAsset(FCameraShakeInstanceID InInstanceID, bool bImmediately = false)。节点、变量、过渡和服务目录:references/gameplay-camera-system.md。

C++ 中的自定义相机节点

一个节点由 UCameraNode(数据,可在 Rig 图表中编辑)和 FCameraNodeEvaluator(运行时,在评估器存储中分配)配对组成。节点会重写 OnBuildEvaluator,并返回 Builder.BuildEvaluator<FMyEvaluator>()。评估器必须在类中使用 UE_DECLARE_CAMERA_NODE_EVALUATOR,并在 .cpp 中使用 UE_DEFINE_CAMERA_NODE_EVALUATOR——它们会注册 RTTI 类型 ID;若未注册,评估器转换(CastThis、CastThisChecked)和类型查找会失败(GetCameraNodeAs 只是对节点执行普通的 UObject Cast,不依赖这些宏)。将可调参数公开为相机参数(FVector3dCameraParameter 等),以便设计师将它们绑定到相机变量;在 OnInitialize 中初始化 TCameraParameterReader<T> 并通过它们读取参数,然后在 OnRun 中使用 FCameraPose 的 setter 写入结果。尽量精简 ECameraNodeEvaluatorFlags——评估器默认从 Default 开始(包含参数更新、序列化和操作),因此要用 SetNodeEvaluatorFlags 清除不需要的标志。

包含有效的肩部偏移节点,以及这两个类的完整钩子列表:references/gameplay-camera-system.md。

调试相机

症状检查项
屏幕上的 Actor 错误ShowDebug Camera——输出相机管理器状态,包括视图目标
占有后没有画面检查 bAutoManageActiveCameraTarget,或确认 SetViewTarget 调用确实执行了
忽略了 CalcCamera 重写目标是 ACameraActor、Blueprint 的 BlueprintUpdateCamera 返回了 true,或重写调用了 Super::CalcCamera(它会选择相机组件)
相机穿入几何体检查弹簧臂上的 bDoCollisionTest、ProbeChannel、ProbeSize
混合直接跳变而非平滑过渡BlendTime 为 0,或 BlendFunc 为 VTBlend_PreBlended
俯仰角越过垂直方向检查相机管理器上的 ViewPitchMin / ViewPitchMax
Gameplay Cameras 没有显示内容先执行 GameplayCameras.Debug.Enable 1,再执行 GameplayCameras.Debug.Categories nodetree

值得了解的 Gameplay Cameras CVar:GameplayCameras.Debug.Enable、GameplayCameras.Debug.Categories(nodetree、directortree、blendstacks、services、posestats、viewfinder)、GameplayCameras.Debug.SystemID、GameplayCameras.Debug.Trace、GameplayCameras.Debug.NodeTree.Filter、GameplayCameras.Debug.BlendStacks.Filter。项目设置位于 UGameplayCamerasSettings(bAutoBuildInPIE、DefaultViewRotationMode)中。专用服务器不会渲染画面,因此在那里处理震动、淡入淡出和后期处理都是浪费——请通过客户端 RPC 驱动这些效果,或使用 if (GetNetMode() != NM_DedicatedServer) 进行保护。

已弃用 — 请勿使用

不要使用在 5.8 中使用来源
#include "Camera/CameraShake.h"#include "Shakes/LegacyCameraShake.h"EngineCameras/Legacy/Camera/CameraShake.h:9 中的 UE_DEPRECATED_HEADER(5.5)
#include "Shakes/MatineeCameraShake.h" / UMatineeCameraShakeULegacyCameraShake5.8 头文件中不存在 UCameraAnim 类
UCameraAnim、UCameraAnimInst、PlayCameraAnimUCameraAnimationSequence + UEngineCamerasSubsystem::PlayCameraAnimation5.8 头文件中不存在 UCameraAnim 类
FCameraRigParameterOverrides 和 F*CameraRigParameterOverride 结构体FCameraRigAssetReference 上基于 FInstancedPropertyBag 的参数覆盖GameplayCameras/Public/Core/CameraRigAssetReference.h:26-43 中的 UE_DEPRECATED(5.7)
UCameraRigProxyTableFCameraRigProxyRedirectTableGameplayCameras/Public/Core/CameraRigProxyRedirectTable.h:69 中的 UE_DEPRECATED(5.6)
将 FBlueprintCameraDirectorEvaluationParams / ActivateParams / DeactivateParams 用作承载参数的结构体直接将参数传递给 RunCameraDirector / ActivateCameraDirector / DeactivateCameraDirectorGameplayCameras/Public/Directors/BlueprintCameraDirector.h:18,32,42 中的 UE_DEPRECATED(5.6)
UActivateCameraRigFunctions::ActivatePersistentBaseCameraRig(WorldContext, PC, Rig)Gameplay Camera 组件或 Camera Manager 上的同名方法GameplayCameras/Public/GameFramework/ActivateCameraRigFunctions.h:32 中的 DeprecatedFunction
UGameplayCameraComponent::DeactivateCamera(bImmediately)Deactivate()GameplayCameras/Public/GameFramework/GameplayCameraComponentBase.h:212 中的 DeprecatedFunction
UGameplayCameraComponent::Camera(原始 UCameraAsset 指针)CameraReference(FCameraAssetReference)GameplayCameras/Public/GameFramework/GameplayCameraComponent.h:71 中的 Camera_DEPRECATED
将 USimpleBlendCameraNode::SetBlendTime 用作“当前”混合时间SetDefaultBlendTimeGameplayCameras/Public/Nodes/Blends/SimpleBlendCameraNode.h:29 中的 UE_DEPRECATED(5.7)
UCineCameraComponent::FilmbackSettingsFilmbackCinematicCamera/Public/CineCameraComponent.h:34 中的 FilmbackSettings_DEPRECATED
将 APawn::CalcCamera 当作 Pawn 自有版本来调用继承自 AActor::CalcCamera 的虚函数(Pawn 子类可按常规方式重写),或 Camera 组件5.8 中的 APawn 未声明 CalcCamera

常见错误

**在摇臂和摄像机上都设置 bUsePawnControlRotation:**控制旋转会应用两次,因此鼠标视角移动时摄像机会反向旋转。第三人称时将其设置在弹簧臂上,第一人称时设置在摄像机上,切勿同时设置在两者上。

**在自定义重载中调用 Super::CalcCamera:**当 bFindCameraComponentWhenViewTarget 为 true 时,基类 AActor::CalcCamera 会返回第一个活动摄像机组件的视图(Actor.cpp:3690-3702),覆盖你的 POV。跳过 Super,或清除该标志。

**重载 UpdateViewTarget 时不调用 Super:::**基类会从目标的摄像机组件或 CalcCamera 填充 OutVT.POV。跳过它会导致 POV 被置零,位于世界原点。

**错误重载 ModifyCamera:**应重载 virtual bool ModifyCamera(float DeltaTime, struct FMinimalViewInfo& InOutPOV),而不是桥接到 Blueprint 的 FVector/FRotator 重载,并返回 false——true 表示“我是最后一个修改器”,会静默禁用所有优先级较低的修改器,包括震动修改器。

**在服务器上调用 StartCameraShake:**服务器有自己的摄像机管理器,因此震动只会在无人观看的地方播放。从服务器调用客户端 RPC ClientStartCameraShake,或在负责渲染的机器上调用 UGameplayStatics::PlayWorldCameraShake。

忘记在 Build.cs 中添加模块:UPerlinNoiseCameraShakePattern 和 ULegacyCameraShake 需要 "EngineCameras",UCineCameraComponent 需要 "CinematicCamera",而 UE::Cameras 下的所有内容都需要 "GameplayCameras"。缺少模块会导致链接错误,而不是编译错误。

**编写摄像机节点求值器时遗漏 RTTI 宏:**类体中需要 UE_DECLARE_CAMERA_NODE_EVALUATOR,文件作用域中也需要 UE_DEFINE_CAMERA_NODE_EVALUATOR;缺少这些宏时,求值器会报告其基类的类型 ID,导致求值器类型转换和类型查找在运行时失败。

**继承 UCameraShakeBase 却不重载任何内容:**基类本身不会产生运动。设置 RootShakePattern(在构造函数中通过 ChangeRootShakePattern<T>() 设置,或在资源中设置),或者继承 UDefaultCameraShakeBase。

**将 Gameplay Camera System 视为稳定的最终 API:**该插件在 5.8 中仍为 Experimental。如果需要避免引擎升级带来的影响,请将其隔离在你自己的封装组件之后。

相关技能

  • ue-gameplay-framework — APlayerController、APawn、占有关系和视图目标所有者
  • ue-actor-component-architecture — 组件附加、插槽、Tick 顺序、CreateDefaultSubobject
  • ue-input-system — 为控制旋转和摄像机输入节点提供输入的 Enhanced Input 动作和轴
  • ue-sequencer-cinematics — Level Sequence、摄像机切换、可生成摄像机、Take 录制
  • ue-character-movement — bOrientRotationToMovement、RotationRate、蹲伏和眼睛高度变化
  • ue-ui-umg-slate — 位于摄像机画面上层的视口空间 UI、准星和宽银幕遮幅
  • ue-state-trees — State Tree,以及 UStateTreeCameraDirector 背后的架构

评论

支持 Markdown