[박치영]

- boss monster 추가
- boss behavior tree 셋팅
- boss health bar 작업 중
main
PCYPC\pcy35 2023-09-01 19:28:43 +09:00
parent 126c50c567
commit 51505f13cf
39 changed files with 535 additions and 36 deletions

View File

@ -138,4 +138,6 @@ ManualIPAddress=
+PropertyRedirects=(OldName="/Script/D1.T_FindNextPatrolPoint.TargetLocation",NewName="/Script/D1.T_FindNextPatrolPoint.BlackboardKey_TargetLocation")
+PropertyRedirects=(OldName="/Script/D1.T_FindNextPatrolPoint.PatrolIndex",NewName="/Script/D1.T_FindNextPatrolPoint.BlackboardKey_PatrolIndex")
+PropertyRedirects=(OldName="/Script/D1.CombatCharacter.ToggleCombatAction",NewName="/Script/D1.CombatCharacter.ToggleCombatInputAction")
+FunctionRedirects=(OldName="/Script/D1.BaseWeapon.ToggleCombat",NewName="/Script/D1.BaseWeapon.ToggleWeaponCombat")
+FunctionRedirects=(OldName="/Script/D1.BaseWeapon.ToggleCombat",NewName="/Script/D1.BaseWeapon.ToggleWeaponCombat")
+PropertyRedirects=(OldName="/Script/D1.S_UpdateBehavior.AttackingRange",NewName="/Script/D1.S_UpdateBehavior.TotalAttackingDistance")
+PropertyRedirects=(OldName="/Script/D1.S_UpdateBehavior.TotalAttackingDistanceRange",NewName="/Script/D1.S_UpdateBehavior.TotalAttackingDistance")

Binary file not shown.

View File

@ -0,0 +1,14 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AI/BehaviorTreeNodes/D_ChanceCondition.h"
#include "Kismet/KismetMathLibrary.h"
bool UD_ChanceCondition::CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const
{
if(!Super::CalculateRawConditionValue(OwnerComp, NodeMemory))
return false;
return (ChangePercentage >= UKismetMathLibrary::RandomIntegerInRange(0, 100));
}

View File

@ -0,0 +1,23 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/BTDecorator.h"
#include "D_ChanceCondition.generated.h"
/**
*
*/
UCLASS()
class D1_API UD_ChanceCondition : public UBTDecorator
{
GENERATED_BODY()
public:
virtual bool CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const override;
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(AllowPrivateAccess="true", UIMin = "0", UIMax = "100", ClampMin = "0", ClampMax = "100"))
int ChangePercentage;
};

View File

@ -1,8 +1,8 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AI/S_UpdateBehavior.h"
#include "MasterAI.h"
#include "AI/BehaviorTreeNodes/S_UpdateBehavior.h"
#include "AI/MasterAI.h"
#include "AIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "BehaviorTree/BTFunctionLibrary.h"
@ -58,13 +58,24 @@ void US_UpdateBehavior::UpdateBehavior()
CanSeeEnemy = true;
float dist = targetActor->GetDistanceTo(ControlledMasterAI);
if(dist <= AttackingRange)
if(dist <= TotalAttackingDistance)
{
SetBehavior(EAIBehavior::Attack);
if(dist <= CloseRangeAttackingDistance)
SetAttackingRangeType(EAIAttackRange::CloseRange);
else
SetAttackingRangeType(EAIAttackRange::MediumRange);
}
else
SetBehavior(EAIBehavior::Chase);
}
void US_UpdateBehavior::SetBehavior(EAIBehavior NewBehavior)
{
BlackboardComponent->SetValueAsEnum(BlackboardKey_BehaviorKey.SelectedKeyName, (uint8)NewBehavior);
BlackboardComponent->SetValueAsEnum(BlackboardKey_BehaviorKey.SelectedKeyName, static_cast<uint8>(NewBehavior));
}
void US_UpdateBehavior::SetAttackingRangeType(EAIAttackRange NewAttackRange)
{
BlackboardComponent->SetValueAsEnum(BlackboardKey_AttackingRangeType.SelectedKeyName, static_cast<uint8>(NewAttackRange));
}

View File

@ -23,13 +23,18 @@ protected:
public:
void UpdateBehavior();
void SetBehavior(EAIBehavior NewBehavior);
void SetAttackingRangeType(EAIAttackRange NewAttackRange);
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="BlackBoard", meta=(AllowPrivateAccess="true"))
FBlackboardKeySelector BlackboardKey_BehaviorKey;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="BlackBoard", meta=(AllowPrivateAccess="true"))
FBlackboardKeySelector BlackboardKey_TargetKey;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="BlackBoard", meta=(AllowPrivateAccess="true"))
float AttackingRange;
FBlackboardKeySelector BlackboardKey_AttackingRangeType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="BlackBoard", meta=(AllowPrivateAccess="true"))
float TotalAttackingDistance;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="BlackBoard", meta=(AllowPrivateAccess="true"))
float CloseRangeAttackingDistance;
private:
TObjectPtr<class UBlackboardComponent> BlackboardComponent;

View File

@ -1,9 +1,9 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AI/T_FindNextPatrolPoint.h"
#include "AI/BehaviorTreeNodes/T_FindNextPatrolPoint.h"
#include "AIController.h"
#include "MasterAI.h"
#include "AI/MasterAI.h"
#include "NavigationSystem.h"
#include "BehaviorTree/BlackboardComponent.h"

View File

@ -1,7 +1,7 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AI/T_PerformAction.h"
#include "AI/BehaviorTreeNodes/T_PerformAction.h"
#include "AIController.h"
#include "Interface/CombatInterface.h"

View File

@ -1,7 +1,7 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AI/T_PerformAttack.h"
#include "AI/BehaviorTreeNodes/T_PerformAttack.h"
#include "AIController.h"
#include "Interface/CombatInterface.h"

View File

@ -1,7 +1,7 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AI/T_SetMovementSpeed.h"
#include "AI/BehaviorTreeNodes/T_SetMovementSpeed.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "AIController.h"

View File

@ -0,0 +1,134 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AI/BossEnemy.h"
#include "Blueprint/UserWidget.h"
#include "Components/CollisionComponent.h"
#include "Components/WidgetComponent.h"
#include "Components/CombatComponent.h"
#include "DamageType/AttackDamageType.h"
#include "Kismet/GameplayStatics.h"
#include "UI/UI_BossHealth.h"
#include "UI/UI_HealthBar.h"
ABossEnemy::ABossEnemy()
{
TargetingWidgetComponent->SetRelativeLocation(FVector(0.f, 0.f, 132.f));
//Setting SocketName
AttachSocketName = TEXT("SwordHipAttachSocket");
WeaponHandSocketName = TEXT("RightWeaponSocket");
//Setting UWidgetComponent
HealthBarComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("HealthBar"));
static ConstructorHelpers::FClassFinder<UUserWidget> WidgetRef(TEXT("/Game/CombatSystem/UI/WBP_HealthBar.WBP_HealthBar_C"));
if(WidgetRef.Class)
{
HealthBarComponent->SetWidgetClass(WidgetRef.Class);
HealthBarComponent->SetWidgetSpace(EWidgetSpace::Screen);
HealthBarComponent->SetDrawSize({150.f, 10.f});
HealthBarComponent->SetupAttachment(GetMesh());
HealthBarComponent->SetRelativeLocation(FVector(0.f, 0.f, 200.f));
HealthBarComponent->SetVisibility(false);
}
//Setting WeaponMeshComponent
WeaponMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WeaponMeshComponent"));
WeaponMeshComponent->SetRelativeLocationAndRotation(FVector(0.f, 0.f, 0.f), FRotator(0.f, 0.f, 0.f));
WeaponMeshComponent->SetupAttachment(GetMesh(), AttachSocketName);
WeaponMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//Setting MainWeaponCollisionComponent
//Setting others is Parents
MainWeaponCollisionComponent->OnHitDelegate.BindUObject(this, &ABossEnemy::OnHit);
//Setting CombatComponent
//Setting others is Parents
CombatComponent->OnCombatToggled.AddUObject(this, &ABossEnemy::OnCombatToggled);
}
void ABossEnemy::BeginPlay()
{
Super::BeginPlay();
MainWeaponCollisionComponent->SetCollisionMeshComponent(WeaponMeshComponent);
MainWeaponCollisionComponent->AddActorToIgnore(this);
APlayerController* playerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
if(!playerController)
return;
UWorld* World = GetWorld();
if (World)
{
APlayerController* Contorller = World->GetFirstPlayerController();
if(Controller)
{
UUI_BossHealth* BossHealthRef = CreateWidget<UUI_BossHealth>(Contorller, UUI_BossHealth::StaticClass());
if (BossHealthRef) //ExposeOnSpawn 대용으로 사용
{
BossHealthWidget = BossHealthRef;
BossHealthWidget->InitializeWidget(StatsComponent);
BossHealthRef->AddToViewport();
}
}
}
}
void ABossEnemy::OnTargetSet(AActor* NewTarget)
{
Super::OnTargetSet(NewTarget);
SetBossHealthVisibility(IsValid(NewTarget));
}
void ABossEnemy::OnTargeted(bool bIsTargeted)
{
Super::OnTargeted(bIsTargeted);
}
void ABossEnemy::OnHit(FHitResult hitResult)
{
ICombatInterface* pActor = Cast<ICombatInterface>(hitResult.GetActor());
if (pActor)
{
if (pActor->Execute_CanReceiveDamage(hitResult.GetActor()))
UGameplayStatics::ApplyPointDamage(hitResult.GetActor(), StatsComponent->GetCurrentStatValue(EStats::Damage), this->GetActorForwardVector(), hitResult, GetController(), this, UAttackDamageType::StaticClass());
}
}
void ABossEnemy::OnCombatToggled(bool IsCombatEnabled)
{
FName SocketName;
if(IsCombatEnabled)
SocketName = WeaponHandSocketName;
else
SocketName = AttachSocketName;
FAttachmentTransformRules rules(EAttachmentRule::SnapToTarget, EAttachmentRule::SnapToTarget, EAttachmentRule::SnapToTarget, true);
WeaponMeshComponent->AttachToComponent(GetMesh(), rules, SocketName);
}
void ABossEnemy::PerformDeath()
{
//TODO : 죽었을 때 무기에 Collision이 남아있는 버그 있음
Super::PerformDeath();
SimulateWeaponPhysics();
SetBossHealthVisibility(false);
}
void ABossEnemy::SimulateWeaponPhysics()
{
WeaponMeshComponent->SetCollisionProfileName(TEXT("PhysicsActor"), true);
WeaponMeshComponent->SetSimulatePhysics(true);
}
void ABossEnemy::SetBossHealthVisibility(bool IsVisible)
{
if(!IsValid(BossHealthWidget))
return;
if(IsVisible)
BossHealthWidget->SetVisibility(ESlateVisibility::Visible);
else
BossHealthWidget->SetVisibility(ESlateVisibility::Hidden);
}

View File

@ -0,0 +1,53 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "AI/MasterAI.h"
#include "BossEnemy.generated.h"
/**
*
*/
UCLASS()
class D1_API ABossEnemy : public AMasterAI
{
GENERATED_BODY()
public:
ABossEnemy();
private:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="UI", meta=(AllowPrivateAccess="true"))
TObjectPtr<class UWidgetComponent> HealthBarComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Component", meta=(AllowPrivateAccess="true"))
TObjectPtr<class UStaticMeshComponent> WeaponMeshComponent;
protected:
virtual void BeginPlay() override;
protected:
// Inherited via AMasterAI
virtual void OnTargetSet(AActor* NewTarget) override;
// Inherited via ITargetingInterface
virtual void OnTargeted(bool bIsTargeted) override;
public: // Delegate
//UCollisionComponent
void OnHit(FHitResult hitResult);
//UCombatComponent
void OnCombatToggled(bool IsCombatEnabled);
public:
virtual void PerformDeath() override;
void SimulateWeaponPhysics();
void SetBossHealthVisibility(bool IsVisible);
private:
UPROPERTY(EditAnywhere, Blueprintable, Category="Initialization", meta=(AllowPrivateAccess="true"))
FName AttachSocketName;
UPROPERTY(EditAnywhere, Blueprintable, Category="Initialization", meta=(AllowPrivateAccess="true"))
FName WeaponHandSocketName;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(AllowPrivateAccess="true"))
TObjectPtr<class UUI_BossHealth> BossHealthWidget;
};

View File

@ -25,7 +25,7 @@ ACombatAIController::ACombatAIController()
AffiliationFilter.bDetectFriendlies = true;
AffiliationFilter.bDetectNeutrals = true;
SightConfig->DetectionByAffiliation = AffiliationFilter;
SightConfig->AutoSuccessRangeFromLastSeenLocation = 500.f;
SightConfig->AutoSuccessRangeFromLastSeenLocation = 1000.f;
PerceptionComponent->ConfigureSense(*SightConfig);
DamageConfig = CreateDefaultSubobject<UAISenseConfig_Damage>(TEXT("DamageConfig"));
@ -66,22 +66,24 @@ void ACombatAIController::OnUpdatePerception(const TArray<AActor*>& PerceivedAct
{
if(Info.WasSuccessfullySensed())
{
if(Cast<IGameplayTagAssetInterface>(SensoredActor)->HasMatchingGameplayTag(FCombatGameplayTags::Get().Character_Player))
{
Blackboard->SetValueAsObject(TEXT("Target"), SensoredActor);
}
IGameplayTagAssetInterface* CurActor = Cast<IGameplayTagAssetInterface>(SensoredActor);
if(!CurActor)
continue;
if(CurActor->HasMatchingGameplayTag(FCombatGameplayTags::Get().Character_Player))
SetTargetActor(SensoredActor);
}
else
Blackboard->SetValueAsObject(TEXT("Target"), nullptr);
SetTargetActor(SensoredActor);
}
else if(SensedClass == UAISense_Damage::StaticClass())
{
if(Info.WasSuccessfullySensed() && !Info.IsExpired()) //After DamageConfig->GetMaxAge then Expired
{
if(Cast<IGameplayTagAssetInterface>(SensoredActor)->HasMatchingGameplayTag(FCombatGameplayTags::Get().Character_Player))
{
Blackboard->SetValueAsObject(TEXT("Target"), SensoredActor);
}
IGameplayTagAssetInterface* CurActor = Cast<IGameplayTagAssetInterface>(SensoredActor);
if(!CurActor)
continue;
if(CurActor->HasMatchingGameplayTag(FCombatGameplayTags::Get().Character_Player))
SetTargetActor(SensoredActor);
}
}
}
@ -92,3 +94,10 @@ void ACombatAIController::OnCombatToggle(bool IsCombatEnabled)
{
Blackboard->SetValueAsBool(TEXT("bCombatEnabled"), IsCombatEnabled);
}
void ACombatAIController::SetTargetActor(AActor* NewTargetActor)
{
Blackboard->SetValueAsObject(TEXT("Target"), NewTargetActor);
if(IsValid(MasterAI))
MasterAI->OnTargetSet(NewTargetActor);
}

View File

@ -25,6 +25,8 @@ public: //Delegate Func
//UCombatComponent Delegate
void OnCombatToggle(bool IsCombatEnabled);
public:
void SetTargetActor(AActor* NewTargetActor);
private:
UPROPERTY()
TObjectPtr<class AMasterAI> MasterAI;

View File

@ -1,7 +1,7 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AI/HumanoidEnemy.h"
#include "AI/HeavyMobEnemy.h"
#include "Blueprint/UserWidget.h"
#include "Components/CollisionComponent.h"
@ -11,7 +11,7 @@
#include "Kismet/GameplayStatics.h"
#include "UI/UI_HealthBar.h"
AHumanoidEnemy::AHumanoidEnemy()
AHeavyMobEnemy::AHeavyMobEnemy()
{
TargetingWidgetComponent->SetRelativeLocation(FVector(0.f, 0.f, 132.f));
@ -40,14 +40,14 @@ AHumanoidEnemy::AHumanoidEnemy()
//Setting MainWeaponCollisionComponent
//Setting others is Parents
MainWeaponCollisionComponent->OnHitDelegate.BindUObject(this, &AHumanoidEnemy::OnHit);
MainWeaponCollisionComponent->OnHitDelegate.BindUObject(this, &AHeavyMobEnemy::OnHit);
//Setting CombatComponent
//Setting others is Parents
CombatComponent->OnCombatToggled.AddUObject(this, &AHumanoidEnemy::OnCombatToggled);
CombatComponent->OnCombatToggled.AddUObject(this, &AHeavyMobEnemy::OnCombatToggled);
}
void AHumanoidEnemy::BeginPlay()
void AHeavyMobEnemy::BeginPlay()
{
Super::BeginPlay();
@ -65,13 +65,13 @@ void AHumanoidEnemy::BeginPlay()
}
}
void AHumanoidEnemy::OnTargeted(bool bIsTargeted)
void AHeavyMobEnemy::OnTargeted(bool bIsTargeted)
{
Super::OnTargeted(bIsTargeted);
HealthBarComponent->SetVisibility(bIsTargeted);
}
void AHumanoidEnemy::OnHit(FHitResult hitResult)
void AHeavyMobEnemy::OnHit(FHitResult hitResult)
{
ICombatInterface* pActor = Cast<ICombatInterface>(hitResult.GetActor());
if (pActor)
@ -81,7 +81,7 @@ void AHumanoidEnemy::OnHit(FHitResult hitResult)
}
}
void AHumanoidEnemy::OnCombatToggled(bool IsCombatEnabled)
void AHeavyMobEnemy::OnCombatToggled(bool IsCombatEnabled)
{
FName SocketName;
if(IsCombatEnabled)
@ -92,14 +92,14 @@ void AHumanoidEnemy::OnCombatToggled(bool IsCombatEnabled)
WeaponMeshComponent->AttachToComponent(GetMesh(), rules, SocketName);
}
void AHumanoidEnemy::PerformDeath()
void AHeavyMobEnemy::PerformDeath()
{
//TODO : 죽었을 때 무기에 Collision이 남아있는 버그 있음
Super::PerformDeath();
SimulateWeaponPhysics();
}
void AHumanoidEnemy::SimulateWeaponPhysics()
void AHeavyMobEnemy::SimulateWeaponPhysics()
{
WeaponMeshComponent->SetCollisionProfileName(TEXT("PhysicsActor"), true);
WeaponMeshComponent->SetSimulatePhysics(true);

View File

@ -4,17 +4,17 @@
#include "CoreMinimal.h"
#include "AI/MasterAI.h"
#include "HumanoidEnemy.generated.h"
#include "HeavyMobEnemy.generated.h"
/**
*
*/
UCLASS()
class D1_API AHumanoidEnemy : public AMasterAI
class D1_API AHeavyMobEnemy : public AMasterAI
{
GENERATED_BODY()
public:
AHumanoidEnemy();
AHeavyMobEnemy();
private:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="UI", meta=(AllowPrivateAccess="true"))

View File

@ -71,6 +71,12 @@ AMasterAI::AMasterAI()
// Setting StatsComponent
StatsComponent = CreateDefaultSubobject<UStatsComponent>(TEXT("StatsComponent"));
StatsComponent->OnCurrentStatValueUpdated.AddUObject(this, &AMasterAI::CharacterCurrentStatValueUpdated);
StatsComponent->SetBaseStatValue(EStats::Health, 100.f);
StatsComponent->SetMaxStatValue(EStats::Health, 100.f);
StatsComponent->SetBaseStatValue(EStats::Armor, 0.f);
StatsComponent->SetMaxStatValue(EStats::Armor, 100.f);
StatsComponent->SetBaseStatValue(EStats::Damage, 25.f);
StatsComponent->SetMaxStatValue(EStats::Damage, 300.f);
// Setting MainWeaponCollisionComponent
// Setting OnHit Func is Child Class
@ -269,6 +275,10 @@ void AMasterAI::OnTargeted(bool bIsTargeted)
TargetingWidgetComponent->SetVisibility(bIsTargeted);
}
void AMasterAI::OnTargetSet(AActor* NewTarget)
{
}
void AMasterAI::SetMovementSpeedMode(EMovementSpeedMode NewSpeedMode)
{
if (NewSpeedMode == MovementSpeedMode)
@ -540,6 +550,10 @@ TArray<UAnimMontage*> AMasterAI::GetActionMontage(FGameplayTag characterAction)
if (FCombatGameplayTags::Get().Character_Action_Attack_CloseRange == characterAction)
outputArr = CloseRangeAttackMontage;
else if (FCombatGameplayTags::Get().Character_Action_Attack_MediumRange == characterAction)
outputArr = MediumRangeAttackMontage;
else if (FCombatGameplayTags::Get().Character_Action_Attack_RareAttack == characterAction)
outputArr = RareAttackMontage;
else if (FCombatGameplayTags::Get().Character_Action_Dodge == characterAction)
outputArr = DodgeMontage;
else if (FCombatGameplayTags::Get().Character_Action_EnterCombat == characterAction)

View File

@ -74,6 +74,8 @@ public:
// Inherited via ITargetingInterface
virtual bool CanBeTargeted() override;
virtual void OnTargeted(bool bIsTargeted) override;
public: //Using Child Class
virtual void OnTargetSet(AActor* NewTarget);
public:
void SetMovementSpeedMode(EMovementSpeedMode NewSpeedMode);
FORCEINLINE EMovementSpeedMode GetMovementSpeedMode() const { return MovementSpeedMode; }
@ -140,6 +142,10 @@ private:
TObjectPtr<UAnimMontage> KnockdownBackMontage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Montage|Attacks", meta = (AllowPrivateAccess = "true"))
TArray<TObjectPtr<UAnimMontage>> CloseRangeAttackMontage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Montage|Attacks", meta = (AllowPrivateAccess = "true"))
TArray<TObjectPtr<UAnimMontage>> MediumRangeAttackMontage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Montage|Attacks", meta = (AllowPrivateAccess = "true"))
TArray<TObjectPtr<UAnimMontage>> RareAttackMontage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Montage|Actions", meta = (AllowPrivateAccess = "true"))
TArray<TObjectPtr<UAnimMontage>> DodgeMontage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Montage|Actions", meta = (AllowPrivateAccess = "true"))

View File

@ -0,0 +1,106 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "AI/MobEnemy.h"
#include "Blueprint/UserWidget.h"
#include "Components/CollisionComponent.h"
#include "Components/WidgetComponent.h"
#include "Components/CombatComponent.h"
#include "DamageType/AttackDamageType.h"
#include "Kismet/GameplayStatics.h"
#include "UI/UI_HealthBar.h"
AMobEnemy::AMobEnemy()
{
TargetingWidgetComponent->SetRelativeLocation(FVector(0.f, 0.f, 132.f));
//Setting SocketName
AttachSocketName = TEXT("SwordHipAttachSocket");
WeaponHandSocketName = TEXT("RightWeaponSocket");
//Setting UWidgetComponent
HealthBarComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("HealthBar"));
static ConstructorHelpers::FClassFinder<UUserWidget> WidgetRef(TEXT("/Game/CombatSystem/UI/WBP_HealthBar.WBP_HealthBar_C"));
if(WidgetRef.Class)
{
HealthBarComponent->SetWidgetClass(WidgetRef.Class);
HealthBarComponent->SetWidgetSpace(EWidgetSpace::Screen);
HealthBarComponent->SetDrawSize({150.f, 10.f});
HealthBarComponent->SetupAttachment(GetMesh());
HealthBarComponent->SetRelativeLocation(FVector(0.f, 0.f, 200.f));
HealthBarComponent->SetVisibility(false);
}
//Setting WeaponMeshComponent
WeaponMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WeaponMeshComponent"));
WeaponMeshComponent->SetRelativeLocationAndRotation(FVector(0.f, 0.f, 0.f), FRotator(0.f, 0.f, 0.f));
WeaponMeshComponent->SetupAttachment(GetMesh(), AttachSocketName);
WeaponMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//Setting MainWeaponCollisionComponent
//Setting others is Parents
MainWeaponCollisionComponent->OnHitDelegate.BindUObject(this, &AMobEnemy::OnHit);
//Setting CombatComponent
//Setting others is Parents
CombatComponent->OnCombatToggled.AddUObject(this, &AMobEnemy::OnCombatToggled);
}
void AMobEnemy::BeginPlay()
{
Super::BeginPlay();
MainWeaponCollisionComponent->SetCollisionMeshComponent(WeaponMeshComponent);
MainWeaponCollisionComponent->AddActorToIgnore(this);
if(APlayerController* playerController = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
UUI_HealthBar* HealthBarRef = Cast<UUI_HealthBar>(HealthBarComponent->GetWidget());
if(HealthBarRef) //ExposeOnSpawn 대용으로 사용
{
HealthBarRef->InitializeHealthBar(this->StatsComponent, EStats::Health);
HealthBarComponent->SetWidget(HealthBarRef);
}
}
}
void AMobEnemy::OnTargeted(bool bIsTargeted)
{
Super::OnTargeted(bIsTargeted);
HealthBarComponent->SetVisibility(bIsTargeted);
}
void AMobEnemy::OnHit(FHitResult hitResult)
{
ICombatInterface* pActor = Cast<ICombatInterface>(hitResult.GetActor());
if (pActor)
{
if (pActor->Execute_CanReceiveDamage(hitResult.GetActor()))
UGameplayStatics::ApplyPointDamage(hitResult.GetActor(), StatsComponent->GetCurrentStatValue(EStats::Damage), this->GetActorForwardVector(), hitResult, GetController(), this, UAttackDamageType::StaticClass());
}
}
void AMobEnemy::OnCombatToggled(bool IsCombatEnabled)
{
FName SocketName;
if(IsCombatEnabled)
SocketName = WeaponHandSocketName;
else
SocketName = AttachSocketName;
FAttachmentTransformRules rules(EAttachmentRule::SnapToTarget, EAttachmentRule::SnapToTarget, EAttachmentRule::SnapToTarget, true);
WeaponMeshComponent->AttachToComponent(GetMesh(), rules, SocketName);
}
void AMobEnemy::PerformDeath()
{
//TODO : 죽었을 때 무기에 Collision이 남아있는 버그 있음
Super::PerformDeath();
SimulateWeaponPhysics();
}
void AMobEnemy::SimulateWeaponPhysics()
{
WeaponMeshComponent->SetCollisionProfileName(TEXT("PhysicsActor"), true);
WeaponMeshComponent->SetSimulatePhysics(true);
}

View File

@ -0,0 +1,46 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "AI/MasterAI.h"
#include "MobEnemy.generated.h"
/**
*
*/
UCLASS()
class D1_API AMobEnemy : public AMasterAI
{
GENERATED_BODY()
public:
AMobEnemy();
private:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="UI", meta=(AllowPrivateAccess="true"))
TObjectPtr<class UWidgetComponent> HealthBarComponent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Component", meta=(AllowPrivateAccess="true"))
TObjectPtr<class UStaticMeshComponent> WeaponMeshComponent;
protected:
virtual void BeginPlay() override;
protected:
// Inherited via ITargetingInterface
virtual void OnTargeted(bool bIsTargeted) override;
public: // Delegate
//UCollisionComponent
void OnHit(FHitResult hitResult);
//UCombatComponent
void OnCombatToggled(bool IsCombatEnabled);
public:
virtual void PerformDeath() override;
void SimulateWeaponPhysics();
private:
UPROPERTY(EditAnywhere, Blueprintable, Category="Initialization", meta=(AllowPrivateAccess="true"))
FName AttachSocketName;
UPROPERTY(EditAnywhere, Blueprintable, Category="Initialization", meta=(AllowPrivateAccess="true"))
FName WeaponHandSocketName;
};

View File

@ -12,7 +12,6 @@
#include "Components/StatsComponent.h"
#include "Components/TargetingComponent.h"
#include "Definitions/GameEnums.h"
#include "Interface/CombatGameplayTag.h"
#include "CombatCharacter.generated.h"

View File

@ -4,7 +4,6 @@
#include "Components/StatsComponent.h"
#include "Components/StateManagerComponent.h"
#include "Math/UnrealMathUtility.h"
#include "Kismet/KismetSystemLibrary.h"
// Sets default values for this component's properties
UStatsComponent::UStatsComponent()
@ -153,11 +152,23 @@ void UStatsComponent::SetBaseStatValue(EStats stat, float value)
{
if (BaseStats.Contains(stat))
BaseStats.Find(stat)->BaseValue = value;
else
{
FBaseStat fStat;
fStat.BaseValue = value;
BaseStats.Add(stat, fStat);
}
}
void UStatsComponent::SetMaxStatValue(EStats stat, float value)
{
if (BaseStats.Contains(stat))
BaseStats.Find(stat)->MaxValue = value;
else
{
FBaseStat fStat;
fStat.MaxValue = value;
BaseStats.Add(stat, fStat);
}
}

View File

@ -99,4 +99,14 @@ void FCombatGameplayTags::InitializeNativeGameplayTags()
FName("Character.Action.Attack.CloseRange"),
FString("Action Attack CloseRange")
);
GameplayTags.Character_Action_Attack_MediumRange = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Character.Action.Attack.MediumRange"),
FString("Action Attack MediumRange")
);
GameplayTags.Character_Action_Attack_RareAttack = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Character.Action.Attack.RareAttack"),
FString("Action Attack RareAttack")
);
}

View File

@ -33,6 +33,8 @@ public:
FGameplayTag Character_Action_Attack_LightAttack;
FGameplayTag Character_Action_Attack_SprintAttack;
FGameplayTag Character_Action_Attack_CloseRange;
FGameplayTag Character_Action_Attack_MediumRange;
FGameplayTag Character_Action_Attack_RareAttack;
private:
static FCombatGameplayTags GameplayTags;

View File

@ -45,4 +45,11 @@ enum class EAIBehavior : uint8
Chase UMETA(DisplayName = "Chase"),
Patrol UMETA(DisplayName = "Patrol"),
Hit UMETA(DisplayName = "Hit"),
};
UENUM(BlueprintType)
enum class EAIAttackRange : uint8
{
CloseRange UMETA(DisplayName = "CloseRange"),
MediumRange UMETA(DisplayName = "MediumRange"),
};

View File

@ -0,0 +1,17 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "UI/UI_BossHealth.h"
#include "UI_HealthBar.h"
#include "Components/StatsComponent.h"
UUI_BossHealth::UUI_BossHealth()
{
}
void UUI_BossHealth::InitializeWidget(UStatsComponent* InputStatsComponent)
{
HealthBar->InitializeHealthBar(InputStatsComponent, EStats::Health);
}

View File

@ -0,0 +1,28 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "UI_BossHealth.generated.h"
/**
*
*/
UCLASS()
class D1_API UUI_BossHealth : public UUserWidget
{
GENERATED_BODY()
public:
UUI_BossHealth();
void InitializeWidget(class UStatsComponent* InputStatsComponent);
private:
/*
* TODO :
* Blueprint Widget
* UUI_HealthBar C++ .
*
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(BindWidget, AllowPrivateAccess="true"))
TSubclassOf<class UUI_HealthBar> HealthBar;
};