关于 ue-gameplay-cameras
ue-gameplay-cameras 是面向 Unreal Engine 5.8 项目的摄像机开发参考 Skill,供开发者实现和排查游戏摄像机功能。内容覆盖经典摄像机栈与实验性的 Gameplay Camera System,并提供 API 指引和代码示例。
主要功能
- 01比较两种摄像机系统
- 02第三人称与第一人称摄像机配置
- 03视点目标切换与混合
- 04自定义 Camera Manager 与 Modifier
- 05摄像机抖动、电影摄像机及调试
适用场景
- 01为 Unreal Engine 5.8 配置角色摄像机
- 02实现摄像机视点切换和过渡
- 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 的子类,因此插件运行求值时,经典视图目标、淡入淡出和修饰器仍可使用。
经典管线的运行方式
APlayerController持有PlayerCameraManager(由virtual void SpawnPlayerCameraManager()从TSubclassOf<APlayerCameraManager> PlayerCameraManagerClass生成)。APlayerCameraManager::UpdateCamera(float DeltaTime)→DoUpdateCamera(float DeltaTime)→UpdateViewTarget(FTViewTarget& OutVT, float DeltaTime)。UpdateViewTarget填充OutVT.POV(一个FMinimalViewInfo)。ACameraActor目标会直接使用其摄像机组件;其他目标则调用Target->CalcCamera(PlayerCameraManager.cpp:354),其基类AActor实现会在bFindCameraComponentWhenViewTarget为 true 时使用第一个启用的摄像机组件,否则使用 Actor 的眼睛视点(Actor.cpp:3688-3706)。ApplyCameraModifiers(float DeltaTime, FMinimalViewInfo& InOutPOV)会按Priority(0 = 最高)运行ModifierList中的每个UCameraModifier。- 结果会被缓存;
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" / UMatineeCameraShake | ULegacyCameraShake | 5.8 头文件中不存在 UCameraAnim 类 |
UCameraAnim、UCameraAnimInst、PlayCameraAnim | UCameraAnimationSequence + UEngineCamerasSubsystem::PlayCameraAnimation | 5.8 头文件中不存在 UCameraAnim 类 |
FCameraRigParameterOverrides 和 F*CameraRigParameterOverride 结构体 | FCameraRigAssetReference 上基于 FInstancedPropertyBag 的参数覆盖 | GameplayCameras/Public/Core/CameraRigAssetReference.h:26-43 中的 UE_DEPRECATED(5.7) |
UCameraRigProxyTable | FCameraRigProxyRedirectTable | GameplayCameras/Public/Core/CameraRigProxyRedirectTable.h:69 中的 UE_DEPRECATED(5.6) |
将 FBlueprintCameraDirectorEvaluationParams / ActivateParams / DeactivateParams 用作承载参数的结构体 | 直接将参数传递给 RunCameraDirector / ActivateCameraDirector / DeactivateCameraDirector | GameplayCameras/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 用作“当前”混合时间 | SetDefaultBlendTime | GameplayCameras/Public/Nodes/Blends/SimpleBlendCameraNode.h:29 中的 UE_DEPRECATED(5.7) |
UCineCameraComponent::FilmbackSettings | Filmback | CinematicCamera/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 顺序、CreateDefaultSubobjectue-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背后的架构