第一次提交

This commit is contained in:
不明不惑
2026-03-03 01:23:02 +08:00
commit 3e434877e8
1053 changed files with 102411 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
// Copyright(c) Aurora Devs 2022-2025. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "CameraAnimationCameraModifier.h"
#include "DrawDebugHelpers.h"
#include "UGC_CameraAnimationModifier.generated.h"
/**
* Delegate for when a UGC Camera Animation is completed, whether the animation has been interrupted or finished.
*
* bInterrupted = true if it was not property finished
*/
DECLARE_DELEGATE_TwoParams(FOnCameraAnimationEnded, class UCameraAnimationSequence*, bool /*bInterrupted*/)
/**
* Delegate for when a UGC Camera Animation started easing out, whether the animation has actually been interrupted or not.
*
* bInterrupted = true if it was not property finished
*/
DECLARE_DELEGATE_OneParam(FOnCameraAnimationEaseOutStarted, class UCameraAnimationSequence*)
UENUM()
enum class ECameraAnimationResetType : uint8
{
BackToStart UMETA(ToolTip = "The camera will go back to the position it started from."),
ResetToZero UMETA(ToolTip = "The camera's orientation will be reset to zero. This is usually the back of the character. If UseControllerRotationYaw is true, this is forcefully used."),
ContinueFromEnd UMETA(ToolTip = "The camera will blend out from the last position of the animation.")
};
USTRUCT()
struct FUGCActiveAnimationInfo
{
GENERATED_USTRUCT_BODY()
ECameraAnimationResetType ResetType = ECameraAnimationResetType::ResetToZero;
/** Runtime interpolated distance percentage (0 = fully blocked, 1 = clear) */
float DistBlockedPct = 1.f;
bool bDoCollisionChecks = false;
bool bWasEasingOut = false;
};
/**
* Gameplay Camera Animation Modifier which plays in the correct transform space in rgeards to the owning player.
*/
UCLASS(abstract, ClassGroup = "UGC Camera Modifiers")
class AURORADEVS_UGC_API UUGC_CameraAnimationModifier : public UCameraAnimationCameraModifier
{
GENERATED_BODY()
public:
// UCameraModifier interface
virtual bool ModifyCamera(float DeltaTime, FMinimalViewInfo& InOutPOV) override;
void CameraAnimation_SetEasingOutDelegate(FOnCameraAnimationEaseOutStarted& InOnAnimationEaseOutStarted, FCameraAnimationHandle AnimationHandle);
void CameraAnimation_SetEndedDelegate(FOnCameraAnimationEnded& InOnAnimationEnded, FCameraAnimationHandle AnimationHandle);
FCameraAnimationHandle PlaySingleCameraAnimation(UCameraAnimationSequence* Sequence, FCameraAnimationParams Params, ECameraAnimationResetType ResetType, bool bInterruptOthers, bool bDoCollisionChecks);
/**
* Stops the given camera animation sequence. If nullptr, will stop whatever is currently active.
* @param Sequence The camera sequence animation.
* @param bImmediate True to stop it right now and ignore blend out, false to let it blend out as indicated.
*/
UFUNCTION(BlueprintCallable, Category = "UGC|Modifiers|Camera Animation")
void StopCameraAnimationSequence(UCameraAnimationSequence* Sequence, bool bImmediate = false);
/**
* Get the current camera animation playing on this modifier.
* @return The current camera animation playing.
*/
UFUNCTION(BlueprintCallable, Category = "UGC|Modifiers|Camera Animations")
void GetCurrentCameraAnimations(TArray<UCameraAnimationSequence*>& OutAnimations) const;
/**
* Returns whether the given camera animation is playing on this modifier.
* @param Sequence The Camera Animation Sequence.
* @return Whether the corresponding camera animation is playing or not.
*/
UFUNCTION(BlueprintCallable, Category = "UGC|Modifiers|Camera Animations")
bool IsCameraAnimationSequenceActive(UCameraAnimationSequence* Sequence) const;
/**
* Returns whether any camera animation is playing on this modifier.
* @param Sequence The Camera Animation Sequence.
* @return Whether any camera animation is playing or not.
*/
UFUNCTION(BlueprintCallable, Category = "UGC|Modifiers|Camera Animations")
bool IsAnyCameraAnimationSequence() const;
protected:
void UGCDeactivateCameraAnimation(FActiveCameraAnimationInfo& ActiveAnimation);
// UCameraAnimationCameraModifier interface
virtual void UGCTickActiveAnimation(float DeltaTime, FMinimalViewInfo& InOutPOV);
// UCameraAnimationCameraModifier interface
virtual void UGCTickAnimation(FActiveCameraAnimationInfo& CameraAnimation, float DeltaTime, FMinimalViewInfo& InOutPOV, int Index);
virtual void UGCTickAnimCollision(FActiveCameraAnimationInfo& CameraAnimation, float DeltaTime, FMinimalViewInfo& InOutPOV, int Index);
FVector GetTraceSafeLocation(FMinimalViewInfo const& InPOV);
template<typename T>
T* GetViewTargetAs() const
{
return Cast<T>(GetViewTarget());
}
private:
#if ENABLE_DRAW_DEBUG
void UGCDebugAnimation(FActiveCameraAnimationInfo& ActiveAnimation, float DeltaTime);
#endif
private:
UPROPERTY(Transient)
TObjectPtr<class AUGC_PlayerCameraManager> UGCCameraManager = nullptr;
UPROPERTY(Transient)
TObjectPtr<class UUGC_CameraCollisionModifier> CollisionModifier = nullptr;
/** How should the camera behave after the current animation is over. */
UPROPERTY(Transient)
TArray<FUGCActiveAnimationInfo> UGCAnimInfo;
UPROPERTY(Transient)
int LastIndex = 0;
// Delegates
FOnCameraAnimationEnded OnAnimationEnded;
FOnCameraAnimationEaseOutStarted OnAnimationEaseOutStarted;
};

View File

@@ -0,0 +1,63 @@
// Copyright(c) Aurora Devs 2022-2025. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UGC_CameraModifier.h"
#include "Camera/Data/UGC_CameraData.h"
#include "Camera/CameraTypes.h"
#include "DrawDebugHelpers.h"
#include "Containers/StaticBitArray.h"
#include "UGC_CameraCollisionModifier.generated.h"
/**
* DEPRECATED. USE UGC_SpringArmComponent INSTEAD.
* Camera Modifier which does camera avoidance using predictive collision feelers.
*/
UCLASS(abstract, ClassGroup = "UGC Camera Modifiers", meta = (Deprecated = 5.5))
class AURORADEVS_UGC_API UUGC_CameraCollisionModifier : public UUGC_CameraModifier
{
GENERATED_BODY()
UUGC_CameraCollisionModifier();
public:
// Force collision modifier to use a single ray by another modifier. Do not use this if you're not familiar with it.
UFUNCTION(BlueprintCallable, Category = "UGC|Modifiers|Collision")
void AddSingleRayOverrider(UCameraModifier const* OverridingModifier) { if (OverridingModifier) SingleRayOverriders.AddUnique(OverridingModifier); }
// Remove single ray modifier override. Do not use this if you're not familiar with it.
UFUNCTION(BlueprintCallable, Category = "UGC|Modifiers|Collision")
void RemoveSingleRayOverrider(UCameraModifier const* OverridingModifier) { if (OverridingModifier) SingleRayOverriders.Remove(OverridingModifier); }
protected:
virtual bool ModifyCamera(float DeltaTime, FMinimalViewInfo& InOutPOV) override;
void UpdatePreventPenetration(float DeltaTime, FMinimalViewInfo& InOutPOV);
void PreventCameraPenetration(class AActor const& ViewTarget, FVector const& SafeLoc, FVector& OutCameraLoc, float const& DeltaTime, float& OutDistBlockedPct, bool bSingleRayOnly);
FVector GetTraceSafeLocation(FMinimalViewInfo const& POV);
void ResetSingleRayOverriders() { SingleRayOverriders.Reset(); }
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UGC|Modifiers|Collision")
FCameraCollisionSettings CollisionSettings;
// If you don't want the camera to start close to the character and smoothly pan out once your character is spawned, default-initialize this variable to 1.f.
UPROPERTY(Transient)
float AimLineToDesiredPosBlockedPct = 1.f;
UPROPERTY(Transient)
TArray<TObjectPtr<const AActor>> DebugActorsHitDuringCameraPenetration;
protected:
TArray<UCameraModifier const*> SingleRayOverriders;
TStaticBitArray<128u> CollidingFeelers;
#if ENABLE_DRAW_DEBUG
mutable float LastDrawDebugTime = -MAX_FLT;
#endif
};

View File

@@ -0,0 +1,93 @@
// Copyright(c) Aurora Devs 2022-2025. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Camera/Modifiers/UGC_CameraModifier.h"
#include "Camera/Data/UGC_CameraData.h"
#include "DrawDebugHelpers.h"
#include "UGC_CameraDitheringModifier.generated.h"
UENUM()
enum class EDitherType : uint8
{
None,
BlockingLOS,
OverlappingCamera
};
USTRUCT(BlueprintType)
struct FDitheredActorState
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UGC|Modifiers|Camera Dithering")
TObjectPtr<AActor> Actor;
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "UGC|Modifiers|Camera Dithering")
float CurrentOpacity = 1.f;
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "UGC|Modifiers|Camera Dithering")
float CollisionTime = 0.f;
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "UGC|Modifiers|Camera Dithering")
bool bIsDitheringIn = false;
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "UGC|Modifiers|Camera Dithering")
bool bIsDitheringOut = false;
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "UGC|Modifiers|Camera Dithering")
EDitherType DitherType = EDitherType::None;
bool IsValid() const { return Actor != nullptr && DitherType != EDitherType::None; }
void StartDithering(AActor* InActor, EDitherType InDitherType);
void Invalidate();
friend bool operator==(FDitheredActorState const& lhs, FDitheredActorState const& rhs)
{
return lhs.Actor == rhs.Actor;
}
void ComputeOpacity(float DeltaTime, float DitherInTime, float DitherOutTime, float DitherMin);
};
/**
* UGC Camera Modifier used to dither objects colliding with the camera
*/
UCLASS()
class AURORADEVS_UGC_API UUGC_CameraDitheringModifier : public UUGC_CameraModifier
{
GENERATED_BODY()
public:
UUGC_CameraDitheringModifier();
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "UGC|Modifiers|Dithering")
void ResetDitheredActors();
protected:
virtual bool ModifyCamera(float DeltaTime, FMinimalViewInfo& InOutPOV) override;
virtual void ApplyDithering(float DeltaTime, FDitheredActorState& DitherState);
private:
#if ENABLE_DRAW_DEBUG
void UGCDebugDithering(FDitheredActorState& DitherState, float DeltaTime, float DitherMin);
#endif
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UGC|Modifiers|Dithering")
FCameraDitheringSettings DitheringSettings;
/** Material Parameter Collection for everything dithering-related */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UGC|Modifiers|Dithering")
TSoftObjectPtr<class UMaterialParameterCollection> DitheringMPC;
UPROPERTY(Transient)
TSoftObjectPtr<class UMaterialParameterCollectionInstance> DitheringMPCInstance;
UPROPERTY(Transient)
TArray<FDitheredActorState> DitheredActorStates;
};

View File

@@ -0,0 +1,233 @@
// Copyright(c) Aurora Devs 2022-2025. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Camera/CameraModifier.h"
#include "UGC_CameraModifier.generated.h"
/**
* Base Camera Modifier Class
*/
UCLASS(abstract, ClassGroup = "UGC|Camera Modifiers")
class AURORADEVS_UGC_API UUGC_CameraModifier : public UCameraModifier
{
GENERATED_BODY()
public:
virtual void EnableModifier() override;
virtual void DisableModifier(bool bImmediate) override;
bool GetDebugEnabled() const { return bDebug; }
/**
* Function called once this modifier gets enabled.
* @param LastPOV - the last view POV of the camera.
*/
UFUNCTION(BlueprintNativeEvent, Category = "UGC|Camera Modifier")
void OnModifierEnabled(FMinimalViewInfo const& LastPOV);
/**
* Function called once this modifier gets disabled.
* @param bWasImmediate - true if modifier was disabled without a blend out.
* @param LastPOV - the last view POV of the camera.
*/
UFUNCTION(BlueprintNativeEvent, Category = "UGC|Camera Modifier")
void OnModifierDisabled(FMinimalViewInfo const& LastPOV, bool bWasImmediate);
/**
* Called to give modifiers a chance to adjust view rotation updates before they are applied.
*
* Default just returns ViewRotation unchanged
* @param ViewTarget - Current view target.
* @param InLocalControlRotation - The difference between the actor rotation and the control rotation.
* @param DeltaTime - Frame time in seconds.
* @param InViewLocation - In. The view location of the camera.
* @param InViewRotation - In. The view rotation of the camera.
* @param InDeltaRot - In/out. How much the rotation changed this frame.
* @param OutDeltaRot - Out. How much the control rotation should change this frame.
* @return Return true to prevent subsequent (lower priority) modifiers to further adjust rotation, false otherwise.
*/
UFUNCTION(BlueprintNativeEvent, Category = "UGC|Camera Modifier")
bool ProcessControlRotation(AActor* ViewTarget, float DeltaTime, FVector InViewLocation, FRotator InViewRotation, FRotator InLocalControlRotation, FRotator InDeltaRot, FRotator& OutDeltaRot);
/**
* Called to give modifiers a chance to adjust arm length and FOV before they are applied.
*
* @param DeltaTime - Frame time in seconds.
* @param InFOV - The Current FOV of the camera.
* @param InArmLength - The Current Arm Length of the camera.
* @param ViewLocation - The view location of the camera.
* @param ViewRotation - The view rotation of the camera.
* @param OutFOV - The New FOV of the camera.
* @param OutArmLength - The New Arm Length of the camera.
*/
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "UGC|Camera Modifier")
void ProcessBoomLengthAndFOV(float DeltaTime, float InFOV, float InArmLength, FVector ViewLocation, FRotator ViewRotation, float& OutFOV, float& OutArmLength);
/**
* Called to give modifiers a chance to adjust arm offsets before they are applied.
*
* @param DeltaTime - Frame time in seconds.
* @param InSocketOffset - The Current Socket Offset of the camera.
* @param InTargetOffset - The Current Target Offset of the camera.
* @param ViewLocation - The view location of the camera.
* @param ViewRotation - The view rotation of the camera.
* @param OutSocketOffset - New Socket Offset of the camera.
* @param OutTargetOffset - New Target Offset of the camera.
*/
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "UGC|Camera Modifier")
void ProcessBoomOffsets(float DeltaTime, FVector InSocketOffset, FVector InTargetOffset, FVector ViewLocation, FRotator ViewRotation, FVector& OutSocketOffset, FVector& OutTargetOffset);
/**
* Called to give modifiers a chance to adjust miscelaneous stuff at the end of the update order.
*
* @param DeltaTime - Frame time in seconds.
* @param ViewLocation - The view location of the camera.
* @param ViewRotation - The view rotation of the camera.
*/
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "UGC|Camera Modifier")
void PostUpdate(float DeltaTime, FVector ViewLocation, FRotator ViewRotation);
UFUNCTION(BlueprintNativeEvent, Category = "UGC|Camera Modifier")
void OnAnyLevelSequenceStarted();
UFUNCTION(BlueprintNativeEvent, Category = "UGC|Camera Modifier")
void OnAnyLevelSequenceEnded();
UFUNCTION(BlueprintNativeEvent, Category = "UGC|Camera Modifier")
void OnSetViewTarget(bool bImmediate, bool bNewTargetIsOwner);
UFUNCTION(BlueprintPure, Category = "UGC|Camera Modifier")
bool IsDebugEnabled() const;
UFUNCTION(BlueprintCallable, Category = "UGC|Camera Modifier")
void ToggleDebug(bool const bEnabled);
UFUNCTION(BlueprintCallable, Category = "UGC|Camera Modifier")
void SetAlpha(float InAlpha) { Alpha = InAlpha; }
/**
* Called to give modifiers a chance to adjust both the yaw turn rate and pitch turn rate. However the input for looking needs to have UGC_CameraTurnRateModifier.
*
* @param DeltaTime - Frame time in seconds.
* @param InLocalControlRotation - The difference between the actor rotation and the control rotation.
* @param OutPitchTurnRate - Out. New value of the pitch turn rate (between 0 and 1).
* @param OutYawTurnRate - Out. New value of the yaw turn rate (between 0 and 1).
* @return Return true to prevent subsequent (lower priority) modifiers to further adjust rotation, false otherwise.
*/
UFUNCTION(BlueprintNativeEvent, Category = "UGC|Camera Modifier")
bool ProcessTurnRate(float DeltaTime, FRotator InLocalControlRotation, float InPitchTurnRate, float InYawTurnRate, float& OutPitchTurnRate, float& OutYawTurnRate);
bool CanPlayDuringCameraAnimation() const { return bPlayDuringCameraAnimations; }
UFUNCTION(BlueprintPure, Category = "UGC|Camera Modifier|Movement")
FVector GetOwnerVelocity() const;
UFUNCTION(BlueprintPure, Category = "UGC|Camera Modifier|Movement")
bool IsOwnerFalling() const;
UFUNCTION(BlueprintPure, Category = "UGC|Camera Modifier|Movement")
bool IsOwnerStrafing() const;
UFUNCTION(BlueprintPure, Category = "UGC|Camera Modifier|Movement")
bool IsOwnerMovingOnGround() const;
UFUNCTION(BlueprintPure, Category = "UGC|Camera Modifier|Movement")
void ComputeOwnerFloorDistance(float SweepDistance, float CapsuleRadius, bool& bOutFloorExists, float& OutFloorDistance) const;
UFUNCTION(BlueprintPure, Category = "UGC|Camera Modifier|Movement")
void ComputeOwnerFloorNormal(float SweepDistance, float CapsuleRadius, bool& bOutFloorExists, FVector& OutFloorNormal) const;
UFUNCTION(BlueprintPure, Category = "UGC|Camera Modifier|Movement")
void ComputeOwnerSlopeAngle(float& OutSlopePitchDegrees, float& OutSlopeRollDegrees);
/*
* Returns value betwen 1 (the character is looking where they're moving) or -1 (looking in the opposite direction they're moving).
* Will return 0 if the character isn't moving.
*/
UFUNCTION(BlueprintPure, Category = "UGC|Camera Modifier|Movement")
float ComputeOwnerLookAndMovementDot();
protected:
virtual bool ModifyCamera(float DeltaTime, FMinimalViewInfo& InOutPOV) override;
virtual void ModifyCamera(float DeltaTime, FVector ViewLocation, FRotator ViewRotation, float FOV, FVector& OutViewLocation, FRotator& OutViewRotation, float& OutFOV) override;
virtual bool ProcessViewRotation(AActor* ViewTarget, float DeltaTime, FRotator& OutViewRotation, FRotator& OutDeltaRot) override;
template<typename T>
T* GetViewTargetAs() const { return Cast<T>(GetViewTarget()); }
void UpdateOwnerReferences();
void UpdateInternalVariables(float DeltaTime);
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Modifier Settings")
bool bPlayDuringCameraAnimations = false;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
TObjectPtr<class AUGC_PlayerCameraManager> UGCCameraManager = nullptr;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
TObjectPtr<class APlayerController> OwnerController = nullptr;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
TObjectPtr<class ACharacter> OwnerCharacter = nullptr;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
TObjectPtr<class APawn> OwnerPawn = nullptr;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
TObjectPtr<class USpringArmComponent> SpringArm = nullptr;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
TObjectPtr<class UCharacterMovementComponent> MovementComponent = nullptr;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
FVector CurrentSocketOffset;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
FVector CurrentTargetOffset;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
float CurrentArmLength;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
bool bHasMovementInput;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
FVector PreviousMovementInput;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
FVector MovementInput;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
float TimeSinceMovementInput;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
bool bHasRotationInput;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
FRotator RotationInput;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "UGC|Camera Modifier|Internal")
float TimeSinceRotationInput;
};
/**
* Base Camera Modifier Class for Add-on modifiers
*/
UCLASS(abstract, ClassGroup = "UGC|Add On|Camera Modifiers")
class AURORADEVS_UGC_API UUGC_CameraAddOnModifier : public UUGC_CameraModifier
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "UGC|Add On|Camera Modifiers")
void SetSettings(class UUGC_CameraAddOnModifierSettings* InSettings);
// Add-On Settings class associated to this add-on modifier.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings")
TSubclassOf<class UUGC_CameraAddOnModifierSettings> SettingsClass;
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Settings")
TObjectPtr<UUGC_CameraAddOnModifierSettings> Settings;
};

View File

@@ -0,0 +1,86 @@
// Copyright(c) Aurora Devs 2022-2025. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Camera/Modifiers/UGC_CameraModifier.h"
#include "Misc/Build.h"
#include "Misc/Guid.h"
#include "UGC_CameraPropertyRequestStackHelper.h"
#include "UGC_CameraPropertiesAnimNotifyModifiers.generated.h"
/**
* Camera Modifier in charge of handling FOV change requests from Anim Notifies.
*/
UCLASS(abstract, ClassGroup = "UGC Camera Modifiers")
class AURORADEVS_UGC_API UUGC_FOVAnimNotifyCameraModifier : public UUGC_CameraModifier
{
GENERATED_BODY()
public:
UUGC_FOVAnimNotifyCameraModifier();
protected:
void PushFOVAnimNotifyRequest(FGuid RequestId, float TargetFOV, float TotalDuration, float BlendInDuration, UCurveFloat* BlendInCurve, float BlendOutDuration, UCurveFloat* BlendOutCurve);
void PopFOVAnimNotifyRequest(FGuid RequestId);
protected:
void ProcessBoomLengthAndFOV_Implementation(float DeltaTime, float InFOV, float InArmLength, FVector ViewLocation, FRotator ViewRotation, float& OutFOV, float& OutArmLength) override;
void OnModifierDisabled_Implementation(FMinimalViewInfo const& LastPOV, bool bWasImmediate);
protected:
friend class UUGC_FOVRequestAnimNotifyState;
UGC_CameraPropertyRequestStackHelper<float> RequestHelper;
};
/**
* Camera Modifier in charge of handling Arm Offset changes requests from Anim Notifies.
*/
UCLASS(abstract, ClassGroup = "UGC Camera Modifiers")
class AURORADEVS_UGC_API UUGC_ArmOffsetAnimNotifyCameraModifier : public UUGC_CameraModifier
{
GENERATED_BODY()
public:
UUGC_ArmOffsetAnimNotifyCameraModifier();
protected:
void PushArmSocketOffsetAnimNotifyRequest(FGuid RequestId, FVector TargetOffset, float TotalDuration, float BlendInDuration, UCurveFloat* BlendInCurve, float BlendOutDuration, UCurveFloat* BlendOutCurve);
void PopArmSocketOffsetAnimNotifyRequest(FGuid RequestId);
void PushArmTargetOffsetAnimNotifyRequest(FGuid RequestId, FVector TargetOffset, float TotalDuration, float BlendInDuration, UCurveFloat* BlendInCurve, float BlendOutDuration, UCurveFloat* BlendOutCurve);
void PopArmTargetOffsetAnimNotifyRequest(FGuid RequestId);
protected:
void ProcessBoomOffsets_Implementation(float DeltaTime, FVector InSocketOffset, FVector InTargetOffset, FVector ViewLocation, FRotator ViewRotation, FVector& OutSocketOffset, FVector& OutTargetOffset) override;
void OnModifierDisabled_Implementation(FMinimalViewInfo const& LastPOV, bool bWasImmediate);
protected:
friend class UUGC_ArmOffsetRequestAnimNotifyState;
UGC_CameraPropertyRequestStackHelper<FVector> SocketOffsetRequestHelper;
UGC_CameraPropertyRequestStackHelper<FVector> TargetOffsetRequestHelper;
};
/**
* Camera Modifier in charge of handling Arm Length changes requests from Anim Notifies.
*/
UCLASS(abstract, ClassGroup = "UGC Camera Modifiers")
class AURORADEVS_UGC_API UUGC_ArmLengthAnimNotifyCameraModifier : public UUGC_CameraModifier
{
GENERATED_BODY()
public:
UUGC_ArmLengthAnimNotifyCameraModifier();
protected:
void PushArmLengthAnimNotifyRequest(FGuid RequestId, float TargetLength, float TotalDuration, float BlendInDuration, UCurveFloat* BlendInCurve, float BlendOutDuration, UCurveFloat* BlendOutCurve);
void PopArmLengthAnimNotifyRequest(FGuid RequestId);
protected:
void ProcessBoomLengthAndFOV_Implementation(float DeltaTime, float InFOV, float InArmLength, FVector ViewLocation, FRotator ViewRotation, float& OutFOV, float& OutArmLength) override;
void OnModifierDisabled_Implementation(FMinimalViewInfo const& LastPOV, bool bWasImmediate);
protected:
friend class UUGC_ArmLengthRequestAnimNotifyState;
UGC_CameraPropertyRequestStackHelper<float> RequestHelper;
};

View File

@@ -0,0 +1,72 @@
// Copyright(c) Aurora Devs 2022-2025. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Misc/Build.h"
#include "Misc/Guid.h"
#include "Camera/CameraTypes.h"
class UUGC_CameraModifier;
template<typename ValueType>
struct UGC_CameraPropertyValueRequest
{
public:
bool IsValid() const { return RequestId.IsValid(); }
void Invalidate();
public:
FGuid RequestId = FGuid();
ValueType TargetValue = {};
float TotalDuration = 0.f;
float BlendInDuration = 0.f;
float BlendOutDuration = 0.f;
float CurrentTime = 0.f;
float BlendInCurrentTime = 0.f;
float BlendOutCurrentTime = 0.f;
class UCurveFloat* BlendInCurve = nullptr;
class UCurveFloat* BlendOutCurve = nullptr;
bool bBlendingIn = false;
bool bBlendingOut = false;
};
/**
* Camera Modifier Helper in charge of handling value change requests from Anim Notifies.
*/
template<typename ValueType>
class AURORADEVS_UGC_API UGC_CameraPropertyRequestStackHelper final
{
public:
void Init(const FName& PropertyName, const TFunction<bool()>& DebugGetterFunction);
public:
void PushValueRequest(FGuid RequestId, ValueType TargetValue, float TotalDuration, float BlendInDuration, UCurveFloat* BlendInCurve, float BlendOutDuration, UCurveFloat* BlendOutCurve);
void PopValueRequest(FGuid RequestId);
void ProcessValue(float DeltaTime, ValueType InValue, FVector ViewLocation, FRotator ViewRotation, ValueType& OutValue);
void OnModifierDisabled(FMinimalViewInfo const& LastPOV, bool bWasImmediate);
protected:
void InvalidateRequest(int32 RequestIndex);
int32 FindInactiveRequest();
protected:
friend class UUGC_FOVRequestAnimNotifyState;
TArray<UGC_CameraPropertyValueRequest<ValueType>> Requests;
TFunction<bool()> DebugGetterFunction;
FName PropertyName = TEXT("");
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
public:
FLinearColor PropertyColor = FColor::Red;
protected:
uint32 NumberActive = 0;
#endif
};
#include "UGC_CameraPropertyRequestStackHelper.inl"

View File

@@ -0,0 +1,211 @@
#pragma once
#include "Curves/CurveFloat.h"
#include "Engine/Engine.h"
#include "Containers/UnrealString.h"
#include "Templates/IsArithmetic.h"
#include "Templates/Decay.h"
template<typename ValueType>
void UGC_CameraPropertyValueRequest<ValueType>::Invalidate()
{
*this = UGC_CameraPropertyValueRequest<ValueType>();
}
template<typename ValueType>
void UGC_CameraPropertyRequestStackHelper<ValueType>::Init(const FName& InPropertyName, const TFunction<bool()>& BoolDebugGetterFunction)
{
PropertyName = InPropertyName;
DebugGetterFunction = BoolDebugGetterFunction;
}
template<typename ValueType>
void UGC_CameraPropertyRequestStackHelper<ValueType>::PushValueRequest(FGuid RequestId, ValueType TargetValue, float TotalDuration, float BlendInDuration, UCurveFloat* BlendInCurve, float BlendOutDuration, UCurveFloat* BlendOutCurve)
{
if (!RequestId.IsValid() || TotalDuration <= 0.f)
{
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__ ": Wrong request."));
return;
}
UGC_CameraPropertyValueRequest<ValueType> Request;
Request.RequestId = RequestId;
Request.CurrentTime = 0.f;
Request.TargetValue = TargetValue;
Request.TotalDuration = TotalDuration;
Request.bBlendingIn = BlendInDuration > 0.f;
Request.BlendInDuration = BlendInDuration;
Request.BlendInCurve = BlendInCurve;
Request.BlendInCurrentTime = 0.f;
Request.bBlendingOut = false;
Request.BlendOutDuration = BlendOutDuration;
Request.BlendOutCurve = BlendOutCurve;
Request.BlendOutCurrentTime = 0.f;
const int32 NewIndex = FindInactiveRequest();
check(NewIndex < MAX_uint16);
Requests[NewIndex] = MoveTemp(Request);
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
NumberActive++;
#endif
}
template<typename ValueType>
void UGC_CameraPropertyRequestStackHelper<ValueType>::PopValueRequest(FGuid RequestId)
{
int32 FoundIndex = -1;
for (int32 Index = 0; Index < Requests.Num(); ++Index)
{
if (Requests[Index].RequestId == RequestId)
{
FoundIndex = Index;
break;
}
}
if (FoundIndex >= 0)
{
InvalidateRequest(FoundIndex);
}
}
template<typename ValueType>
int32 UGC_CameraPropertyRequestStackHelper<ValueType>::FindInactiveRequest()
{
for (int32 Index = 0; Index < Requests.Num(); ++Index)
{
const UGC_CameraPropertyValueRequest<ValueType>& Request(Requests[Index]);
if (!Request.IsValid())
{
return Index;
}
}
return Requests.Emplace();
}
template<typename ValueType>
void UGC_CameraPropertyRequestStackHelper<ValueType>::InvalidateRequest(int32 RequestIndex)
{
if (RequestIndex >= 0 && RequestIndex < Requests.Num())
{
Requests[RequestIndex].Invalidate();
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
--NumberActive;
#endif
}
}
template<typename ValueType>
void UGC_CameraPropertyRequestStackHelper<ValueType>::ProcessValue(float DeltaTime, ValueType InValue, FVector ViewLocation, FRotator ViewRotation, ValueType& OutValue)
{
ValueType FinalValue = InValue;
for (int32 Index = 0; Index < Requests.Num(); ++Index)
{
UGC_CameraPropertyValueRequest<ValueType>& Request = Requests[Index];
if (!Request.IsValid())
{
continue;
}
Request.CurrentTime += DeltaTime;
// Advance any easing times.
if (Request.bBlendingIn)
{
Request.BlendInCurrentTime += DeltaTime;
}
if (Request.bBlendingOut)
{
Request.BlendOutCurrentTime += DeltaTime;
}
// Start easing out if we're nearing the end.
if (!Request.bBlendingOut)
{
const float BlendOutStartTime = Request.TotalDuration - Request.BlendOutDuration;
if (Request.CurrentTime > BlendOutStartTime)
{
Request.bBlendingOut = true;
Request.BlendOutCurrentTime = Request.CurrentTime - BlendOutStartTime;
}
}
// Check if we're done easing in or out.
bool bIsDoneEasingOut = false;
if (Request.bBlendingIn)
{
if (Request.BlendInCurrentTime > Request.BlendInDuration || Request.BlendInDuration == 0.f)
{
Request.bBlendingIn = false;
}
}
if (Request.bBlendingOut)
{
if (Request.BlendOutCurrentTime > Request.BlendOutDuration)
{
bIsDoneEasingOut = true;
}
}
// Figure out the final easing weight.
const float EasingInT = FMath::Clamp((Request.BlendInCurrentTime / Request.BlendInDuration), 0.f, 1.f);
const float EasingInWeight = Request.bBlendingIn ?
(Request.BlendInCurve ? Request.BlendInCurve->GetFloatValue(EasingInT) : EasingInT) : 1.f;
const float EasingOutT = FMath::Clamp((1.f - Request.BlendOutCurrentTime / Request.BlendOutDuration), 0.f, 1.f);
const float EasingOutWeight = Request.bBlendingOut ?
(Request.BlendOutCurve ? Request.BlendOutCurve->GetFloatValue(EasingOutT) : EasingOutT) : 1.f;
const float TotalEasingWeight = FMath::Min(EasingInWeight, EasingOutWeight);
// We might be done playing or there was a DisableModifier() call with bImmediate=false to let a value request blend out.
if (bIsDoneEasingOut || TotalEasingWeight <= 0.f)
{
InvalidateRequest(Index);
continue;
}
// Using FinalValue so that having multiple value requests at the same time doesn't cause jumps in values.
FinalValue = FMath::Lerp(FinalValue, Request.TargetValue, TotalEasingWeight);
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (DebugGetterFunction && DebugGetterFunction() && GEngine)
{
const float TextAlpha = (TotalEasingWeight * static_cast<float>(Index + 1) / static_cast<float>(NumberActive));
const FLinearColor TextColor = FMath::Lerp(FLinearColor::White, PropertyColor, TextAlpha);
FString ValueStr = "";
if constexpr (TIsArithmetic<ValueType>::Value) ValueStr = LexToSanitizedString<FString, ValueType>(FinalValue);
else ValueStr = FinalValue.ToCompactString();
GEngine->AddOnScreenDebugMessage(-1, DeltaTime, TextColor.ToFColor(true),
FString::Printf(TEXT("UUGC_%sAnimNotifyRequest: Notify %d - %s"), *PropertyName.ToString(), Index, *ValueStr));
}
#endif
}
OutValue = FinalValue;
}
template<typename ValueType>
void UGC_CameraPropertyRequestStackHelper<ValueType>::OnModifierDisabled(FMinimalViewInfo const& LastPOV, bool bWasImmediate)
{
for (int32 Index = 0; Index < Requests.Num(); ++Index)
{
if (!Requests[Index].IsValid())
{
continue;
}
if (bWasImmediate)
{
InvalidateRequest(Index);
}
else if (!Requests[Index].bBlendingOut)
{
Requests[Index].bBlendingOut = true;
}
}
}

View File

@@ -0,0 +1,114 @@
// Copyright(c) Aurora Devs 2022-2025. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "UObject/ObjectMacros.h"
#include "UObject/Object.h"
#include "UObject/ScriptMacros.h"
#include "UGC_CameraAnimationModifier.h"
#include "UGC_PlayCameraAnimCallbackProxy.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnCameraAnimationPlayDelegate);
/** Parameter struct for adding new camera animations to UGCCameraAnimationCameraModifier */
USTRUCT(BlueprintType)
struct FUGCCameraAnimationParams
{
GENERATED_BODY()
/** Time scale for playing the new camera animation */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera Animation")
float PlayRate = 1.f;
/** Ease-in function type */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera Animation")
ECameraAnimationEasingType EaseInType = ECameraAnimationEasingType::Linear;
/** Ease-in duration in seconds */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera Animation")
float EaseInDuration = 0.f;
/** Ease-out function type */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera Animation")
ECameraAnimationEasingType EaseOutType = ECameraAnimationEasingType::Linear;
/** Ease-out duration in seconds */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera Animation")
float EaseOutDuration = 0.f;
/** How should the camera behave after the animation is over. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera Animation")
ECameraAnimationResetType ResetType = ECameraAnimationResetType::ResetToZero;
explicit operator FCameraAnimationParams() const;
};
UCLASS()
class AURORADEVS_UGC_API UUGC_PlayCameraAnimCallbackProxy : public UObject
{
GENERATED_UCLASS_BODY()
// Called when Camera Animation finished playing and wasn't interrupted
UPROPERTY(BlueprintAssignable)
FOnCameraAnimationPlayDelegate OnCompleted;
// Called when Camera Animation starts blending out and is not interrupted
UPROPERTY(BlueprintAssignable)
FOnCameraAnimationPlayDelegate OnEaseOut;
// Called when Camera Animation has been interrupted (or failed to play)
UPROPERTY(BlueprintAssignable)
FOnCameraAnimationPlayDelegate OnInterrupted;
// Called to perform the query internally
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))
static UUGC_PlayCameraAnimCallbackProxy* CreateProxyObjectForPlayCameraAnim(
class APlayerCameraManager* InPlayerCameraManager,
TSubclassOf<class UUGC_CameraAnimationModifier> ModifierClass,
class UCameraAnimationSequence* CameraSequence,
FUGCCameraAnimationParams Params,
struct FCameraAnimationHandle& Handle,
bool bInterruptOthers,
bool bDoCollisionChecks);
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))
static UUGC_PlayCameraAnimCallbackProxy* CreateProxyObjectForPlayCameraAnimForModifier(
class UUGC_CameraAnimationModifier* CameraAnimationModifier,
class UCameraAnimationSequence* CameraSequence,
FUGCCameraAnimationParams Params,
struct FCameraAnimationHandle& Handle,
bool bInterruptOthers,
bool bDoCollisionChecks);
protected:
UFUNCTION()
void OnCameraAnimationEasingOut(UCameraAnimationSequence* CameraAnimation);
UFUNCTION()
void OnCameraAnimationEnded(UCameraAnimationSequence* CameraAnimation, bool bInterrupted);
private:
TWeakObjectPtr<class UUGC_CameraAnimationModifier> CameraAnimationModifierPtr;
bool bInterruptedCalledBeforeBlendingOut = false;
FOnCameraAnimationEaseOutStarted CameraAnimationEasingOutDelegate;
FOnCameraAnimationEnded CameraAnimationEndedDelegate;
void PlayCameraAnimation(
class APlayerCameraManager* InPlayerCameraManager,
TSubclassOf<class UUGC_CameraAnimationModifier> ModifierClass,
class UCameraAnimationSequence* CameraSequence,
FUGCCameraAnimationParams Params,
struct FCameraAnimationHandle& Handle,
bool bInterruptOthers,
bool bDoCollisionChecks);
void PlayCameraAnimation(
class UUGC_CameraAnimationModifier* CameraAnimationModifier,
class UCameraAnimationSequence* CameraSequence,
FUGCCameraAnimationParams Params,
struct FCameraAnimationHandle& Handle,
bool bInterruptOthers,
bool bDoCollisionChecks);
};