[박치영]

- 각종 이슈 해결
- 회전 시 Timeline 기능 추가 중
main
pcyoung 2023-09-04 23:00:52 +09:00 committed by PCYPC\pcy35
parent 4144aaa60a
commit 86dbaf0037
15 changed files with 121 additions and 28 deletions

View File

@ -7,6 +7,7 @@
#include "Components/CollisionComponent.h"
#include "Components/WidgetComponent.h"
#include "Components/CombatComponent.h"
#include "Components/StateManagerComponent.h"
#include "DamageType/AttackDamageType.h"
#include "Kismet/GameplayStatics.h"
#include "UI/UI_HealthBar.h"
@ -108,7 +109,8 @@ void ABossEnemy::SetBossHealthVisibility(bool IsVisible)
if(!IsValid(BossHealthWidget))
return;
if(IsVisible)
FGameplayTagContainer GameplayTagContainer(FCombatGameplayTags::Get().Character_State_Dead);
if(IsVisible && !StateManagerComponent->IsCurrentStateEqualToAny(GameplayTagContainer))
BossHealthWidget->SetVisibility(ESlateVisibility::Visible);
else
BossHealthWidget->SetVisibility(ESlateVisibility::Hidden);

View File

@ -95,6 +95,9 @@ AMasterAI::AMasterAI()
WalkingSpeed = 200.f;
JoggingSpeed = 500.f;
SprintSpeed = 700.f;
//Settings OwnedGameplayTags
OwnedGameplayTags.AddTag(FCombatGameplayTags::Get().Character_Enemy);
PelvisBoneName = TEXT("pelvis");
}
@ -215,7 +218,9 @@ float AMasterAI::PerformAction(FGameplayTag ActionTag, FGameplayTag StateTag, in
{
StateManagerComponent->SetCurrentState(StateTag);
StateManagerComponent->SetCurrentAction(ActionTag);
actionDuration = PlayAnimMontage(actionMontage);
if(!IsValid(GetMesh()->GetAnimInstance()))
return 0.f;
actionDuration = GetMesh()->GetAnimInstance()->Montage_Play(actionMontage);
}
else
{
@ -250,7 +255,9 @@ float AMasterAI::PerformAttack(FGameplayTag AttackType, int32 AttackIndex, bool
StateManagerComponent->SetCurrentState(FCombatGameplayTags::Get().Character_State_Attacking);
StateManagerComponent->SetCurrentAction(AttackType);
attackDuration = PlayAnimMontage(attackMontage);
if(!IsValid(GetMesh()->GetAnimInstance()))
return 0.f;
attackDuration = GetMesh()->GetAnimInstance()->Montage_Play(attackMontage);
int idx = attackIdx + 1;
if (idx >= montages.Num())
@ -424,7 +431,11 @@ void AMasterAI::ApplyImpactEffect(EDamageType InDamageType)
void AMasterAI::PerformDeath()
{
EnableRagdoll();
ApplyHitReactionPhysicsVelocity(2000.f); //충돌을 좀 더 그럴싸하게 하기 위해서 뒷방향으로 충격
if(bHitFront) //충돌을 좀 더 그럴싸하게 하기 위해서 피격방향으로 충격
ApplyHitReactionPhysicsVelocity(2000.f);
else
ApplyHitReactionPhysicsVelocity(-2000.f);
FTimerHandle deathTimer;
GetWorld()->GetTimerManager().SetTimer(deathTimer, FTimerDelegate::CreateLambda([&]()

View File

@ -3,6 +3,7 @@
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagAssetInterface.h"
#include "Components/StatsComponent.h"
#include "GameFramework/Character.h"
#include "Interface/CombatInterface.h"
@ -12,7 +13,7 @@
#include "MasterAI.generated.h"
UCLASS()
class D1_API AMasterAI : public ACharacter, public ICombatInterface, public ITargetingInterface
class D1_API AMasterAI : public ACharacter, public ICombatInterface, public ITargetingInterface, public IGameplayTagAssetInterface
{
GENERATED_BODY()
@ -71,6 +72,9 @@ public:
// Inherited via ITargetingInterface
virtual bool CanBeTargeted() override;
virtual void OnTargeted(bool bIsTargeted) override;
// Inherited via IGameplayTagAssetInterface
virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override { TagContainer = OwnedGameplayTags; }
public: //Using Child Class
virtual void OnTargetSet(AActor* NewTarget);
public:
@ -152,6 +156,8 @@ private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Patrol", meta = (AllowPrivateAccess = "true"))
TArray<TObjectPtr<ATargetPoint>> PatrolPoints;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameplayTags", meta = (AllowPrivateAccess = "true"))
FGameplayTagContainer OwnedGameplayTags;
private:
FTimerHandle StaminaTimerHandle;

View File

@ -102,6 +102,12 @@ ACombatPlayerCharacter::ACombatPlayerCharacter()
ChargeAttackTime = 0.18f;
PelvisBoneName = TEXT("pelvis");
//Setting Timeline
FOnTimelineFloat CurveFloatCallback;
CurveFloatCallback.BindUFunction(this, FName("RotateToTargetUpdate"));
RotateToTargetTimeLineComponent = CreateDefaultSubobject<UTimelineComponent>(TEXT("RotateToTargetTimeLineComponent"));
RotateToTargetTimeLineComponent->SetTimelineLength(5.0f);
RotateToTargetTimeLineComponent->AddInterpFloat(CurveFloatTimeline, CurveFloatCallback);
}
void ACombatPlayerCharacter::BeginPlay()
@ -127,6 +133,11 @@ void ACombatPlayerCharacter::BeginPlay()
SpawnItem->OnEquipped();
}
void ACombatPlayerCharacter::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
}
float ACombatPlayerCharacter::TakeDamage(float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float fDamage = Super::TakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser);
@ -282,12 +293,13 @@ float ACombatPlayerCharacter::PerformAction(FGameplayTag ActionTag, FGameplayTag
{
StateManagerComponent->SetCurrentState(StateTag);
StateManagerComponent->SetCurrentAction(ActionTag);
actionDuration = PlayAnimMontage(actionMontage);
return true;
if(!IsValid(GetMesh()->GetAnimInstance()))
return 0.f;
actionDuration = GetMesh()->GetAnimInstance()->Montage_Play(actionMontage);
}
else
{
FString str = FString::Printf(TEXT("Dodge Index %n is NOT VALID!!"), montageIdx);
FString str = FString::Printf(TEXT("Dodge Index %d is NOT VALID!!"), montageIdx);
GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, str);
}
return actionDuration;
@ -324,9 +336,11 @@ float ACombatPlayerCharacter::PerformAttack(FGameplayTag AttackType, int32 Attac
{
StateManagerComponent->SetCurrentState(FCombatGameplayTags::Get().Character_State_Attacking);
StateManagerComponent->SetCurrentAction(AttackType);
attackDuration = PlayAnimMontage(attackMontage);
if(!IsValid(GetMesh()->GetAnimInstance()))
return 0.f;
attackDuration = GetMesh()->GetAnimInstance()->Montage_Play(attackMontage);
int idx = attackIdx + 1;
if (idx >= montages.Num())
idx = 0;
@ -521,7 +535,9 @@ void ACombatPlayerCharacter::CharacterStateBegin(FGameplayTag CharState)
if (FGameplayTag::EmptyTag == CharState)
{/*None*/}
else if (FCombatGameplayTags::Get().Character_State_Attacking == CharState)
{/*None*/}
{
RotateToTarget();
}
else if (FCombatGameplayTags::Get().Character_State_Dodging == CharState)
{/*None*/}
else if (FCombatGameplayTags::Get().Character_State_GeneralActionState == CharState)
@ -539,7 +555,9 @@ void ACombatPlayerCharacter::CharacterStateEnd(FGameplayTag CharState)
if (FGameplayTag::EmptyTag == CharState)
{/*None*/}
else if (FCombatGameplayTags::Get().Character_State_Attacking == CharState)
{/*None*/}
{
StopRotateToTarget();
}
else if (FCombatGameplayTags::Get().Character_State_Dodging == CharState)
{/*None*/}
else if (FCombatGameplayTags::Get().Character_State_GeneralActionState == CharState)
@ -693,11 +711,39 @@ void ACombatPlayerCharacter::ApplyImpactEffect(EDamageType InDamageType)
UNiagaraFunctionLibrary::SpawnSystemAtLocation(GetWorld(), HitEmitter, LastHitInfo.Location);
}
void ACombatPlayerCharacter::RotateToTarget()
{
RotateToTargetTimeLineComponent->PlayFromStart();
}
void ACombatPlayerCharacter::StopRotateToTarget()
{
RotateToTargetTimeLineComponent->Stop();
}
void ACombatPlayerCharacter::RotateToTargetUpdate(float Output)
{
if(!IsValid(TargetingComponent))
return;
const FRotator CurrentRotator = GetActorRotation();
FRotator TargetRotator = UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), TargetingComponent->GetTargetActor()->GetActorLocation());
double deltaTime = UGameplayStatics::GetWorldDeltaSeconds(GetOwner());
FRotator NewRotator = FMath::RInterpTo(CurrentRotator, TargetRotator, deltaTime, RotateToTargetInterpSpeed);
NewRotator.Roll = CurrentRotator.Roll;
NewRotator.Pitch = CurrentRotator.Pitch;
SetActorRotation(NewRotator);
}
void ACombatPlayerCharacter::PerformDeath()
{
EnableRagdoll();
ApplyHitReactionPhysicsVelocity(2000.f); //충돌을 좀 더 그럴싸하게 하기 위해서 뒷방향으로 충격
if(bHitFront) //충돌을 좀 더 그럴싸하게 하기 위해서 피격방향으로 충격
ApplyHitReactionPhysicsVelocity(2000.f);
else
ApplyHitReactionPhysicsVelocity(-2000.f);
if (IsValid(CombatComponent->GetMainWeapon()))
CombatComponent->GetMainWeapon()->SimulateWeaponPhysics(); //무기의 충돌킴

View File

@ -11,6 +11,7 @@
#include "Components/StateManagerComponent.h"
#include "Components/StatsComponent.h"
#include "Components/TargetingComponent.h"
#include "Components/TimelineComponent.h"
#include "Definitions/GameEnums.h"
#include "CombatPlayerCharacter.generated.h"
@ -85,6 +86,7 @@ protected:
// APawn interface
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
virtual float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
public:
@ -158,6 +160,11 @@ private:
void ApplyHitReaction(EDamageType InDamageType);
void ApplyImpactEffect(EDamageType InDamageType);
//Timeline
void RotateToTarget();
void StopRotateToTarget();
void RotateToTargetUpdate(float Output);
private:
void PerformDeath();
bool PerformHitStun();
@ -210,6 +217,13 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Montage", meta = (AllowPrivateAccess = "true"))
TObjectPtr<UAnimMontage> KnockdownBackMontage;
private: //Timeline
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Timeline", meta = (AllowPrivateAccess = "true"))
TObjectPtr<UTimelineComponent> RotateToTargetTimeLineComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Timeline", meta = (AllowPrivateAccess = "true"))
TObjectPtr<UCurveFloat> CurveFloatTimeline;
const float RotateToTargetInterpSpeed = 9.f;
private:
FTimerHandle StaminaTimerHandle;

View File

@ -48,7 +48,7 @@ void UCollisionComponent::CollisionTrace()
for (auto hitResult : OutHits)
{
LastHit = hitResult;
if (!AlreadyHitActors.Contains(LastHit.GetActor()))
if (CanHitActor(LastHit.GetActor()))
{
HitActor = LastHit.GetActor();
AlreadyHitActors.Add(HitActor);
@ -65,10 +65,14 @@ void UCollisionComponent::ActivateCollision()
bool UCollisionComponent::CanHitActor(AActor* InActor)
{
bool result = false;
IGameplayTagAssetInterface* tagInterface = Cast<IGameplayTagAssetInterface>(InActor);
if(tagInterface)
{
result &= !tagInterface->HasAnyMatchingGameplayTags(GameplayTagsIgnore); //Ignore Tag
result &= !AlreadyHitActors.Contains(InActor); //Alread Hit
result &= !ActorsToIgnore.Contains(InActor); //Ignore actor
}
return result;
}

View File

@ -3,6 +3,7 @@
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Components/ActorComponent.h"
#include "Kismet/KismetSystemLibrary.h"
#include "CollisionComponent.generated.h"
@ -48,6 +49,7 @@ public:
FORCEINLINE void SetEndSocketName(FName InpuEndSocketName) { EndSocketName = InpuEndSocketName; }
FORCEINLINE void SetCollisionObjectTypes(TArray<TEnumAsByte<EObjectTypeQuery>> InputCollisionObjectTypes) { CollisionObjectTypes = InputCollisionObjectTypes; }
FORCEINLINE void SetDrawDebugType(TEnumAsByte<EDrawDebugTrace::Type> InputDrawDebugType) { DrawDebugType = InputDrawDebugType; }
FORCEINLINE void SetGameplayTagsIgnore(FGameplayTagContainer& InputGameplayTagContainer) { GameplayTagsIgnore = InputGameplayTagContainer; }
public:
UFUNCTION(BlueprintCallable)
FORCEINLINE void ActivateCollision();
@ -58,27 +60,29 @@ public:
private:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Initialization", meta=(AllowPrivateAccess="true"))
float TraceRadius;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Initialization", meta = (AllowPrivateAccess = "true"))
FName StartSocketName;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Initialization", meta = (AllowPrivateAccess = "true"))
FName EndSocketName;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Initialization", meta = (AllowPrivateAccess = "true"))
TArray<TEnumAsByte<EObjectTypeQuery>> CollisionObjectTypes;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Initialization", meta = (AllowPrivateAccess = "true"))
TEnumAsByte<EDrawDebugTrace::Type> DrawDebugType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Initialization", meta = (AllowPrivateAccess = "true"))
FGameplayTagContainer GameplayTagsIgnore;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta = (AllowPrivateAccess = "true"))
TObjectPtr<UPrimitiveComponent> CollisionMeshComponent;
bool bCollisionEnabled;
UPROPERTY()
TArray<TObjectPtr<AActor>> AlreadyHitActors;
UPROPERTY()
TArray<TObjectPtr<AActor>> ActorsToIgnore;
FHitResult LastHit;
UPROPERTY()
TObjectPtr<AActor> HitActor;
bool bCollisionEnabled;
FHitResult LastHit;
public:
FOnHit OnHitDelegate;

View File

@ -52,7 +52,7 @@ void UStateManagerComponent::ResetState()
CurrentState = FGameplayTag::EmptyTag;
}
bool UStateManagerComponent::IsCurrentStateEqualToAny(FGameplayTagContainer StatesToCheck)
bool UStateManagerComponent::IsCurrentStateEqualToAny(FGameplayTagContainer& StatesToCheck)
{
return StatesToCheck.HasTagExact(CurrentState);
}
@ -72,7 +72,7 @@ FGameplayTag UStateManagerComponent::GetCurrentAction()
return CurrentAction;
}
bool UStateManagerComponent::IsCurrentActionEqualToAny(FGameplayTagContainer ActionToCheck)
bool UStateManagerComponent::IsCurrentActionEqualToAny(FGameplayTagContainer& ActionToCheck)
{
return ActionToCheck.HasTagExact(CurrentAction);
}

View File

@ -34,11 +34,11 @@ public:
void SetCurrentState(FGameplayTag NewState);
FGameplayTag GetCurrentState();
void ResetState();
bool IsCurrentStateEqualToAny(FGameplayTagContainer StatesToCheck);
bool IsCurrentStateEqualToAny(FGameplayTagContainer& StatesToCheck);
void SetCurrentAction(FGameplayTag NewAction);
FGameplayTag GetCurrentAction();
bool IsCurrentActionEqualToAny(FGameplayTagContainer ActionToCheck);
bool IsCurrentActionEqualToAny(FGameplayTagContainer& ActionToCheck);
public: //Delegate
FStateBegin OnStateBegin;

View File

@ -12,12 +12,17 @@ void FCombatGameplayTags::InitializeNativeGameplayTags()
return;
/**
* Player
* Character
*/
GameplayTags.Character_Player = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Character.Player"),
FString("Player")
);
GameplayTags.Character_Enemy = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Character.Enemy"),
FString("Enemy")
);
/**
* State

View File

@ -14,6 +14,7 @@ public:
public:
//Character
FGameplayTag Character_Player;
FGameplayTag Character_Enemy;
//State
FGameplayTag Character_State_Attacking;