[박치영] 충돌 및 상태패턴 변경

main
pcyoung 2023-08-06 14:03:43 +09:00 committed by PCYPC\pcy35
parent add1abe08a
commit 79cfdb003a
6 changed files with 132 additions and 57 deletions

View File

@ -57,15 +57,16 @@ ACombatCharacter::ACombatCharacter()
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) // Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)
// are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++) // are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++)
// Setting CombatComponent
CombatComponent = CreateDefaultSubobject<UCombatComponent>(TEXT("CombatComponent")); CombatComponent = CreateDefaultSubobject<UCombatComponent>(TEXT("CombatComponent"));
CombatEnabled = false; // Setting StateManagerComponent
IsTogglingCombat = false; StateManagerComponent = CreateDefaultSubobject<UStateManagerComponent>(TEXT("StateManagerComponent"));
IsDodge = false; StateManagerComponent->OnStateBegin.AddUObject(this, &ACombatCharacter::CharacterStateBegin);
IsDisabled = false; StateManagerComponent->OnStateEnd.AddUObject(this, &ACombatCharacter::CharacterStateEnd);
IsDead = false;
Health = 100.f;
Health = 100.f;
PelvisBoneName = TEXT("pelvis"); PelvisBoneName = TEXT("pelvis");
} }
@ -108,20 +109,24 @@ float ACombatCharacter::TakeDamage(float Damage, FDamageEvent const& DamageEvent
//Hit Effect //Hit Effect
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), HitEmitter, PointDamageEvent->HitInfo.Location); UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), HitEmitter, PointDamageEvent->HitInfo.Location);
if (CanReceiveHitReaction())
{
StateManagerComponent->SetState(ECharacterState::Disable);
//Play Animation //Play Animation
PlayAnimMontage(HitMontage); PlayAnimMontage(HitMontage);
}
IsDisabled = true;
} }
return fDamage; return fDamage;
} }
void ACombatCharacter::ContinueAttack_Implementation() void ACombatCharacter::ContinueAttack_Implementation()
{ {
CombatComponent->SetIsAttacking(false);
if (CombatComponent->GetIsAttackSaved()) if (CombatComponent->GetIsAttackSaved())
{ {
CombatComponent->SetIsAttackSaved(false); CombatComponent->SetIsAttackSaved(false);
if (StateManagerComponent->GetCurrentState() == ECharacterState::Attacking)
StateManagerComponent->SetState(ECharacterState::Nothing);
AttackEvent(); AttackEvent();
} }
} }
@ -134,8 +139,8 @@ void ACombatCharacter::ResetAttack_Implementation()
void ACombatCharacter::ResetCombat_Implementation() void ACombatCharacter::ResetCombat_Implementation()
{ {
CombatComponent->ResetAttack(); CombatComponent->ResetAttack();
IsTogglingCombat = false; StateManagerComponent->ResetState();
IsDodge = false; StateManagerComponent->SetState(ECharacterState::Nothing);
} }
FRotator ACombatCharacter::GetDesiredRotation_Implementation() FRotator ACombatCharacter::GetDesiredRotation_Implementation()
@ -149,7 +154,9 @@ FRotator ACombatCharacter::GetDesiredRotation_Implementation()
bool ACombatCharacter::CanReceiveDamage_Implementation() bool ACombatCharacter::CanReceiveDamage_Implementation()
{ {
return !IsDead; bool result;
result = (StateManagerComponent->GetCurrentState() != ECharacterState::Dead);
return result;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -158,7 +165,8 @@ bool ACombatCharacter::CanReceiveDamage_Implementation()
void ACombatCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) void ACombatCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{ {
// Set up action bindings // Set up action bindings
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) { if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
{
//Jumping //Jumping
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump); EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
@ -247,7 +255,7 @@ void ACombatCharacter::ToggleCombat(const FInputActionValue& Value)
void ACombatCharacter::LightAttack(const FInputActionValue& Value) void ACombatCharacter::LightAttack(const FInputActionValue& Value)
{ {
if (CombatComponent->GetIsAttacking()) if (StateManagerComponent->GetCurrentState() == ECharacterState::Attacking)
CombatComponent->SetIsAttackSaved(true); CombatComponent->SetIsAttackSaved(true);
else else
AttackEvent(); AttackEvent();
@ -259,6 +267,49 @@ void ACombatCharacter::Dodge(const FInputActionValue& Value)
PerformDodge(); PerformDodge();
} }
void ACombatCharacter::CharacterStateBegin(ECharacterState CharState)
{
switch (CharState)
{
case ECharacterState::Nothing:
break;
case ECharacterState::Attacking:
break;
case ECharacterState::Dodging:
break;
case ECharacterState::GeneralActionState:
break;
case ECharacterState::Dead:
PerformDeath();
break;
case ECharacterState::Disable:
break;
default:
break;
}
}
void ACombatCharacter::CharacterStateEnd(ECharacterState CharState)
{
switch (CharState)
{
case ECharacterState::Nothing:
break;
case ECharacterState::Attacking:
break;
case ECharacterState::Dodging:
break;
case ECharacterState::GeneralActionState:
break;
case ECharacterState::Dead:
break;
case ECharacterState::Disable:
break;
default:
break;
}
}
void ACombatCharacter::ToggleCombatEvent() void ACombatCharacter::ToggleCombatEvent()
{ {
ABaseWeapon* baseWeapon = CombatComponent->GetMainWeapon(); ABaseWeapon* baseWeapon = CombatComponent->GetMainWeapon();
@ -291,7 +342,7 @@ void ACombatCharacter::CharacterTakeDamage(float InDamage)
Health = UKismetMathLibrary::Clamp(tmp, 0, Health); Health = UKismetMathLibrary::Clamp(tmp, 0, Health);
if (Health <= 0) if (Health <= 0)
PerformDeath(); StateManagerComponent->SetState(ECharacterState::Dead);
} }
void ACombatCharacter::ApplyHitReactionPhysicsVelocity(float InitialSpeed) void ACombatCharacter::ApplyHitReactionPhysicsVelocity(float InitialSpeed)
@ -326,7 +377,7 @@ void ACombatCharacter::PerformAttack(int32 attackIndex)
if(!IsValid(attackMontage)) if(!IsValid(attackMontage))
return; return;
CombatComponent->SetIsAttacking(true); StateManagerComponent->SetState(ECharacterState::Attacking);
PlayAnimMontage(attackMontage); PlayAnimMontage(attackMontage);
int idx = attackIndex + 1; int idx = attackIndex + 1;
@ -352,7 +403,7 @@ void ACombatCharacter::PerformDodge()
UAnimMontage* dodgeMontage = CurrentWeapon->GetDodgeMontage()[montageIndex]; UAnimMontage* dodgeMontage = CurrentWeapon->GetDodgeMontage()[montageIndex];
if (IsValid(dodgeMontage)) if (IsValid(dodgeMontage))
{ {
IsDodge = true; StateManagerComponent->SetState(ECharacterState::Dodging);
PlayAnimMontage(dodgeMontage); PlayAnimMontage(dodgeMontage);
} }
else else
@ -364,7 +415,6 @@ void ACombatCharacter::PerformDodge()
void ACombatCharacter::PerformDeath() void ACombatCharacter::PerformDeath()
{ {
IsDead = true;
EnableRagdoll(); EnableRagdoll();
ApplyHitReactionPhysicsVelocity(2000.f); //충돌을 좀 더 그럴싸하게 하기 위해서 뒷방향으로 충격 ApplyHitReactionPhysicsVelocity(2000.f); //충돌을 좀 더 그럴싸하게 하기 위해서 뒷방향으로 충격
@ -383,11 +433,15 @@ void ACombatCharacter::PerformDeath()
bool ACombatCharacter::CanPerformToggleCombat() bool ACombatCharacter::CanPerformToggleCombat()
{ {
bool ReturnValue = true; bool ReturnValue = true;
ReturnValue &= !CombatComponent->GetIsAttacking();
ReturnValue &= !IsTogglingCombat; TArray<ECharacterState> inputArr = {
ReturnValue &= !IsDodge; ECharacterState::Attacking,
ReturnValue &= !IsDisabled; ECharacterState::Dodging,
ReturnValue &= !IsDead; ECharacterState::Dead,
ECharacterState::Disable,
ECharacterState::GeneralActionState
};
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
ReturnValue &= !GetCharacterMovement()->IsFalling(); ReturnValue &= !GetCharacterMovement()->IsFalling();
return ReturnValue; return ReturnValue;
} }
@ -395,23 +449,27 @@ bool ACombatCharacter::CanPerformToggleCombat()
bool ACombatCharacter::CanPerformAttack() bool ACombatCharacter::CanPerformAttack()
{ {
bool ReturnValue = true; bool ReturnValue = true;
ReturnValue &= !CombatComponent->GetIsAttacking(); TArray<ECharacterState> inputArr = {
ReturnValue &= !IsTogglingCombat; ECharacterState::Attacking,
ReturnValue &= !IsDodge; ECharacterState::Dodging,
ReturnValue &= !IsDisabled; ECharacterState::Dead,
ReturnValue &= !IsDead; ECharacterState::Disable,
ReturnValue &= !GetCharacterMovement()->IsFalling(); ECharacterState::GeneralActionState
};
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
return ReturnValue; return ReturnValue;
} }
bool ACombatCharacter::CanPerformDodge() bool ACombatCharacter::CanPerformDodge()
{ {
bool ReturnValue = true; bool ReturnValue = true;
ReturnValue &= !CombatComponent->GetIsAttacking(); TArray<ECharacterState> inputArr = {
ReturnValue &= !IsTogglingCombat; ECharacterState::Dodging,
ReturnValue &= !IsDodge; ECharacterState::Dead,
ReturnValue &= !IsDisabled; ECharacterState::Disable,
ReturnValue &= !IsDead; ECharacterState::GeneralActionState
};
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
ReturnValue &= !GetCharacterMovement()->IsFalling(); ReturnValue &= !GetCharacterMovement()->IsFalling();
return ReturnValue; return ReturnValue;
} }
@ -419,14 +477,26 @@ bool ACombatCharacter::CanPerformDodge()
bool ACombatCharacter::CanJumping() bool ACombatCharacter::CanJumping()
{ {
bool ReturnValue = true; bool ReturnValue = true;
ReturnValue &= !CombatComponent->GetIsAttacking(); TArray<ECharacterState> inputArr = {
ReturnValue &= !IsTogglingCombat; ECharacterState::Dodging,
ReturnValue &= !IsDodge; ECharacterState::Dead,
ReturnValue &= !IsDisabled; ECharacterState::Disable,
ReturnValue &= !IsDead; ECharacterState::GeneralActionState
};
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
ReturnValue &= !GetCharacterMovement()->IsFalling(); ReturnValue &= !GetCharacterMovement()->IsFalling();
return ReturnValue; return ReturnValue;
} }
bool ACombatCharacter::CanReceiveHitReaction()
{
bool ReturnValue = true;
TArray<ECharacterState> inputArr = {
ECharacterState::Dead,
};
ReturnValue &= !StateManagerComponent->IsCurrentStateEqualToAny(inputArr);
return ReturnValue;
}

View File

@ -6,6 +6,7 @@
#include "GameFramework/Character.h" #include "GameFramework/Character.h"
#include "InputActionValue.h" #include "InputActionValue.h"
#include "Interface/CombatInterface.h" #include "Interface/CombatInterface.h"
#include "Components/StateManagerComponent.h"
#include "CombatCharacter.generated.h" #include "CombatCharacter.generated.h"
@ -93,6 +94,10 @@ protected:
void LightAttack(const FInputActionValue& Value); void LightAttack(const FInputActionValue& Value);
void Dodge(const FInputActionValue& Value); void Dodge(const FInputActionValue& Value);
private:
void CharacterStateBegin(ECharacterState CharState);
void CharacterStateEnd(ECharacterState CharState);
private: private:
void ToggleCombatEvent(); void ToggleCombatEvent();
void AttackEvent(); void AttackEvent();
@ -102,6 +107,7 @@ private:
void PerformAttack(int32 attackIndex); void PerformAttack(int32 attackIndex);
void PerformDodge(); void PerformDodge();
UFUNCTION(BlueprintCallable) //Àӽà UFUNCTION(BlueprintCallable) //ÀÓ½Ã
void PerformDeath(); void PerformDeath();
@ -109,10 +115,14 @@ private:
bool CanPerformAttack(); bool CanPerformAttack();
bool CanPerformDodge(); bool CanPerformDodge();
bool CanJumping(); bool CanJumping();
bool CanReceiveHitReaction();
public: public:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true")) UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true"))
TObjectPtr<class UCombatComponent> CombatComponent; TObjectPtr<class UCombatComponent> CombatComponent;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true"))
TObjectPtr<class UStateManagerComponent> StateManagerComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon", meta = (AllowPrivateAccess = "true")) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon", meta = (AllowPrivateAccess = "true"))
TSubclassOf<class ABaseEquippable> Weapon; TSubclassOf<class ABaseEquippable> Weapon;
@ -130,12 +140,5 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats", meta = (AllowPrivateAccess = "true")) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats", meta = (AllowPrivateAccess = "true"))
float Health; float Health;
private:
bool CombatEnabled;
bool IsTogglingCombat;
bool IsDodge;
bool IsDisabled;
bool IsDead;
}; };

View File

@ -34,7 +34,6 @@ void UCombatComponent::ResetAttack()
{ {
AttackCount = 0; AttackCount = 0;
bIsAttackSaved = false; bIsAttackSaved = false;
bIsAttacking = false;
} }
void UCombatComponent::SetMainWeapon(ABaseWeapon* NewWeapon) void UCombatComponent::SetMainWeapon(ABaseWeapon* NewWeapon)

View File

@ -29,9 +29,6 @@ public:
void SetMainWeapon(ABaseWeapon* NewWeapon); void SetMainWeapon(ABaseWeapon* NewWeapon);
FORCEINLINE ABaseWeapon* GetMainWeapon() const; FORCEINLINE ABaseWeapon* GetMainWeapon() const;
FORCEINLINE void SetIsAttacking(bool attacking) { bIsAttacking = attacking; }
FORCEINLINE bool GetIsAttacking() const { return bIsAttacking; }
FORCEINLINE void SetIsAttackSaved(bool attackSaved) { bIsAttackSaved = attackSaved; } FORCEINLINE void SetIsAttackSaved(bool attackSaved) { bIsAttackSaved = attackSaved; }
FORCEINLINE bool GetIsAttackSaved() const { return bIsAttackSaved; } FORCEINLINE bool GetIsAttackSaved() const { return bIsAttackSaved; }
@ -48,9 +45,6 @@ private:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(AllowPrivateAccess="true")) UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(AllowPrivateAccess="true"))
bool bIsAttackSaved; bool bIsAttackSaved;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(AllowPrivateAccess="true"))
bool bIsAttacking;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(AllowPrivateAccess="true")) UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(AllowPrivateAccess="true"))
int32 AttackCount; int32 AttackCount;
}; };

View File

@ -36,9 +36,9 @@ void UStateManagerComponent::SetState(ECharacterState NewState)
{ {
if (NewState != CurrentState) if (NewState != CurrentState)
{ {
//TODO : Delegate 함수 호출 (Call on State End) OnStateEnd.Broadcast(CurrentState);
CurrentState = NewState; CurrentState = NewState;
//TODO : Delegate 함수 호출 (Call on State Begin) OnStateBegin.Broadcast(CurrentState);
} }
} }

View File

@ -17,6 +17,9 @@ enum class ECharacterState : uint8
Disable UMETA(DisplayName = "Disable") Disable UMETA(DisplayName = "Disable")
}; };
DECLARE_MULTICAST_DELEGATE_OneParam(FStateBegin, ECharacterState);
DECLARE_MULTICAST_DELEGATE_OneParam(FStateEnd, ECharacterState);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class D1_API UStateManagerComponent : public UActorComponent class D1_API UStateManagerComponent : public UActorComponent
{ {
@ -39,6 +42,12 @@ public:
ECharacterState GetCurrentState(); ECharacterState GetCurrentState();
void ResetState(); void ResetState();
bool IsCurrentStateEqualToAny(TArray<ECharacterState> StatesToCheck); bool IsCurrentStateEqualToAny(TArray<ECharacterState> StatesToCheck);
public: //Delegate
FStateBegin OnStateBegin;
FStateEnd OnStateEnd;
private: private:
ECharacterState CurrentState; ECharacterState CurrentState;
}; };