test/Source/MyProject/Variant_Combat/CombatCharacter.h

335 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "CombatAttacker.h"
#include "CombatDamageable.h"
#include "Animation/AnimInstance.h"
#include "CombatCharacter.generated.h"
class USpringArmComponent;
class UCameraComponent;
class UInputAction;
struct FInputActionValue;
class UCombatLifeBar;
class UWidgetComponent;
DECLARE_LOG_CATEGORY_EXTERN(LogCombatCharacter, Log, All);
/**
* An enhanced Third Person Character with melee combat capabilities:
* - Combo attack string
* - Press and hold charged attack
* - Damage dealing and reaction
* - Death
* - Respawning
*/
UCLASS(abstract)
class ACombatCharacter : public ACharacter, public ICombatAttacker, public ICombatDamageable
{
GENERATED_BODY()
/** Camera boom positioning the camera behind the character */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
USpringArmComponent* CameraBoom;
/** Follow camera */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
UCameraComponent* FollowCamera;
/** Life bar widget component */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
UWidgetComponent* LifeBar;
protected:
/** Jump Input Action */
UPROPERTY(EditAnywhere, Category ="Input")
UInputAction* JumpAction;
/** Move Input Action */
UPROPERTY(EditAnywhere, Category ="Input")
UInputAction* MoveAction;
/** Look Input Action */
UPROPERTY(EditAnywhere, Category ="Input")
UInputAction* LookAction;
/** Mouse Look Input Action */
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* MouseLookAction;
/** Combo Attack Input Action */
UPROPERTY(EditAnywhere, Category ="Input")
UInputAction* ComboAttackAction;
/** Charged Attack Input Action */
UPROPERTY(EditAnywhere, Category ="Input")
UInputAction* ChargedAttackAction;
/** Toggle Camera Side Input Action */
UPROPERTY(EditAnywhere, Category ="Input")
UInputAction* ToggleCameraAction;
/** Max amount of HP the character will have on respawn */
UPROPERTY(EditAnywhere, Category="Damage", meta = (ClampMin = 0, ClampMax = 100))
float MaxHP = 5.0f;
/** Current amount of HP the character has */
UPROPERTY(VisibleAnywhere, Category="Damage")
float CurrentHP = 0.0f;
/** Life bar widget fill color */
UPROPERTY(EditAnywhere, Category="Damage")
FLinearColor LifeBarColor;
/** Name of the pelvis bone, for damage ragdoll physics */
UPROPERTY(EditAnywhere, Category="Damage")
FName PelvisBoneName;
/** Pointer to the life bar widget */
UPROPERTY(EditAnywhere, Category="Damage")
TObjectPtr<UCombatLifeBar> LifeBarWidget;
/** Max amount of time that may elapse for a non-combo attack input to not be considered stale */
UPROPERTY(EditAnywhere, Category="Melee Attack", meta = (ClampMin = 0, ClampMax = 5, Units = "s"))
float AttackInputCacheTimeTolerance = 1.0f;
/** Time at which an attack button was last pressed */
float CachedAttackInputTime = 0.0f;
/** If true, the character is currently playing an attack animation */
bool bIsAttacking = false;
/** Distance ahead of the character that melee attack sphere collision traces will extend */
UPROPERTY(EditAnywhere, Category="Melee Attack|Trace", meta = (ClampMin = 0, ClampMax = 500, Units="cm"))
float MeleeTraceDistance = 75.0f;
/** Radius of the sphere trace for melee attacks */
UPROPERTY(EditAnywhere, Category="Melee Attack|Trace", meta = (ClampMin = 0, ClampMax = 200, Units = "cm"))
float MeleeTraceRadius = 75.0f;
/** Distance ahead of the character that enemies will be notified of incoming attacks */
UPROPERTY(EditAnywhere, Category="Melee Attack|Trace", meta = (ClampMin = 0, ClampMax = 500, Units="cm"))
float DangerTraceDistance = 300.0f;
/** Radius of the sphere trace to notify enemies of incoming attacks */
UPROPERTY(EditAnywhere, Category="Melee Attack|Trace", meta = (ClampMin = 0, ClampMax = 200, Units = "cm"))
float DangerTraceRadius = 100.0f;
/** Amount of damage a melee attack will deal */
UPROPERTY(EditAnywhere, Category="Melee Attack|Damage", meta = (ClampMin = 0, ClampMax = 100))
float MeleeDamage = 1.0f;
/** Amount of knockback impulse a melee attack will apply */
UPROPERTY(EditAnywhere, Category="Melee Attack|Damage", meta = (ClampMin = 0, ClampMax = 1000, Units = "cm/s"))
float MeleeKnockbackImpulse = 250.0f;
/** Amount of upwards impulse a melee attack will apply */
UPROPERTY(EditAnywhere, Category="Melee Attack|Damage", meta = (ClampMin = 0, ClampMax = 1000, Units = "cm/s"))
float MeleeLaunchImpulse = 300.0f;
/** AnimMontage that will play for combo attacks */
UPROPERTY(EditAnywhere, Category="Melee Attack|Combo")
UAnimMontage* ComboAttackMontage;
/** Names of the AnimMontage sections that correspond to each stage of the combo attack */
UPROPERTY(EditAnywhere, Category="Melee Attack|Combo")
TArray<FName> ComboSectionNames;
/** Max amount of time that may elapse for a combo attack input to not be considered stale */
UPROPERTY(EditAnywhere, Category="Melee Attack|Combo", meta = (ClampMin = 0, ClampMax = 5, Units = "s"))
float ComboInputCacheTimeTolerance = 0.45f;
/** Index of the current stage of the melee attack combo */
int32 ComboCount = 0;
/** AnimMontage that will play for charged attacks */
UPROPERTY(EditAnywhere, Category="Melee Attack|Charged")
UAnimMontage* ChargedAttackMontage;
/** Name of the AnimMontage section that corresponds to the charge loop */
UPROPERTY(EditAnywhere, Category="Melee Attack|Charged")
FName ChargeLoopSection;
/** Name of the AnimMontage section that corresponds to the attack */
UPROPERTY(EditAnywhere, Category="Melee Attack|Charged")
FName ChargeAttackSection;
/** Flag that determines if the player is currently holding the charged attack input */
bool bIsChargingAttack = false;
/** If true, the charged attack hold check has been tested at least once */
bool bHasLoopedChargedAttack = false;
/** Camera boom length while the character is dead */
UPROPERTY(EditAnywhere, Category="Camera", meta = (ClampMin = 0, ClampMax = 1000, Units = "cm"))
float DeathCameraDistance = 400.0f;
/** Camera boom length when the character respawns */
UPROPERTY(EditAnywhere, Category="Camera", meta = (ClampMin = 0, ClampMax = 1000, Units = "cm"))
float DefaultCameraDistance = 100.0f;
/** Time to wait before respawning the character */
UPROPERTY(EditAnywhere, Category="Respawn", meta = (ClampMin = 0, ClampMax = 10, Units = "s"))
float RespawnTime = 3.0f;
/** Attack montage ended delegate */
FOnMontageEnded OnAttackMontageEnded;
/** Character respawn timer */
FTimerHandle RespawnTimer;
/** Copy of the mesh's transform so we can reset it after ragdoll animations */
FTransform MeshStartingTransform;
public:
/** Constructor */
ACombatCharacter();
protected:
/** Called for movement input */
void Move(const FInputActionValue& Value);
/** Called for looking input */
void Look(const FInputActionValue& Value);
/** Called for combo attack input */
void ComboAttackPressed();
/** Called for combo attack input pressed */
void ChargedAttackPressed();
/** Called for combo attack input released */
void ChargedAttackReleased();
/** Called for toggle camera side input */
void ToggleCamera();
/** BP hook to animate the camera side switch */
UFUNCTION(BlueprintImplementableEvent, Category="Combat")
void BP_ToggleCamera();
public:
/** Handles move inputs from either controls or UI interfaces */
UFUNCTION(BlueprintCallable, Category="Input")
virtual void DoMove(float Right, float Forward);
/** Handles look inputs from either controls or UI interfaces */
UFUNCTION(BlueprintCallable, Category="Input")
virtual void DoLook(float Yaw, float Pitch);
/** Handles combo attack pressed from either controls or UI interfaces */
UFUNCTION(BlueprintCallable, Category="Input")
virtual void DoComboAttackStart();
/** Handles combo attack released from either controls or UI interfaces */
UFUNCTION(BlueprintCallable, Category="Input")
virtual void DoComboAttackEnd();
/** Handles charged attack pressed from either controls or UI interfaces */
UFUNCTION(BlueprintCallable, Category="Input")
virtual void DoChargedAttackStart();
/** Handles charged attack released from either controls or UI interfaces */
UFUNCTION(BlueprintCallable, Category="Input")
virtual void DoChargedAttackEnd();
protected:
/** Resets the character's current HP to maximum */
void ResetHP();
/** Performs a combo attack */
void ComboAttack();
/** Performs a charged attack */
void ChargedAttack();
/** Called from a delegate when the attack montage ends */
void AttackMontageEnded(UAnimMontage* Montage, bool bInterrupted);
public:
// ~begin CombatAttacker interface
/** Performs the collision check for an attack */
virtual void DoAttackTrace(FName DamageSourceBone) override;
/** Performs the combo string check */
virtual void CheckCombo() override;
/** Performs the charged attack hold check */
virtual void CheckChargedAttack() override;
// ~end CombatAttacker interface
// ~begin CombatDamageable interface
/** Notifies nearby enemies that an attack is coming so they can react */
void NotifyEnemiesOfIncomingAttack();
/** Handles damage and knockback events */
virtual void ApplyDamage(float Damage, AActor* DamageCauser, const FVector& DamageLocation, const FVector& DamageImpulse) override;
/** Handles death events */
virtual void HandleDeath() override;
/** Handles healing events */
virtual void ApplyHealing(float Healing, AActor* Healer) override;
/** Allows reaction to incoming attacks */
virtual void NotifyDanger(const FVector& DangerLocation, AActor* DangerSource) override;
// ~end CombatDamageable interface
/** Called from the respawn timer to destroy and re-create the character */
void RespawnCharacter();
public:
/** Overrides the default TakeDamage functionality */
virtual float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
/** Overrides landing to reset damage ragdoll physics */
virtual void Landed(const FHitResult& Hit) override;
protected:
/** Blueprint handler to play damage dealt effects */
UFUNCTION(BlueprintImplementableEvent, Category="Combat")
void DealtDamage(float Damage, const FVector& ImpactPoint);
/** Blueprint handler to play damage received effects */
UFUNCTION(BlueprintImplementableEvent, Category="Combat")
void ReceivedDamage(float Damage, const FVector& ImpactPoint, const FVector& DamageDirection);
protected:
/** Initialization */
virtual void BeginPlay() override;
/** Cleanup */
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
/** Handles input bindings */
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
/** Handles possessed initialization */
virtual void NotifyControllerChanged() override;
public:
/** Returns CameraBoom subobject **/
FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
/** Returns FollowCamera subobject **/
FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};