Section 15: AI and Behavior Trees - Lecture 310
Retargeting New Montages
This commit is contained in:
parent
a1ec63742e
commit
700f9ab66f
BIN
Content/FXVillesBloodVFXPack/MaterialFunctions/MF_SmoothStep.uasset (Stored with Git LFS)
Normal file
BIN
Content/FXVillesBloodVFXPack/MaterialFunctions/MF_SmoothStep.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/FXVillesBloodVFXPack/Materials/MAT_BloodClip_Master.uasset (Stored with Git LFS)
Normal file
BIN
Content/FXVillesBloodVFXPack/Materials/MAT_BloodClip_Master.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/FXVillesBloodVFXPack/Materials/MIC_BloodClip_Splat_2x2.uasset (Stored with Git LFS)
Normal file
BIN
Content/FXVillesBloodVFXPack/Materials/MIC_BloodClip_Splat_2x2.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/FXVillesBloodVFXPack/Particles/PS_Blood_Spurt_02.uasset (Stored with Git LFS)
Normal file
BIN
Content/FXVillesBloodVFXPack/Particles/PS_Blood_Spurt_02.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/FXVillesBloodVFXPack/Textures/T_Blood_Reflection.uasset (Stored with Git LFS)
Normal file
BIN
Content/FXVillesBloodVFXPack/Textures/T_Blood_Reflection.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/FXVillesBloodVFXPack/Textures/T_Blood_SubUV_2x2_01.uasset (Stored with Git LFS)
Normal file
BIN
Content/FXVillesBloodVFXPack/Textures/T_Blood_SubUV_2x2_01.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/FXVillesBloodVFXPack/Textures/T_Blood_SubUV_2x2_01_N.uasset (Stored with Git LFS)
Normal file
BIN
Content/FXVillesBloodVFXPack/Textures/T_Blood_SubUV_2x2_01_N.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/ParagonGrux/Characters/Heroes/Grux/Meshes/Grux_Skeleton.uasset (Stored with Git LFS)
BIN
Content/ParagonGrux/Characters/Heroes/Grux/Meshes/Grux_Skeleton.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/ParagonLtBelica/Characters/Heroes/Belica/Meshes/Belica_Skeleton.uasset (Stored with Git LFS)
BIN
Content/ParagonLtBelica/Characters/Heroes/Belica/Meshes/Belica_Skeleton.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Character/Belica/BelicaAnimBP.uasset (Stored with Git LFS)
BIN
Content/_Game/Character/Belica/BelicaAnimBP.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Character/Belica/BelicaCharacterBP.uasset (Stored with Git LFS)
BIN
Content/_Game/Character/Belica/BelicaCharacterBP.uasset (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/_Game/Character/Belica/HitReact/HitReactMontage.uasset (Stored with Git LFS)
Normal file
BIN
Content/_Game/Character/Belica/HitReact/HitReactMontage.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/_Game/Character/Revenant/HitReact/HitReactMontage.uasset (Stored with Git LFS)
Normal file
BIN
Content/_Game/Character/Revenant/HitReact/HitReactMontage.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/_Game/Character/Revenant/HitReact/HitReact_Front.uasset (Stored with Git LFS)
Normal file
BIN
Content/_Game/Character/Revenant/HitReact/HitReact_Front.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/_Game/Character/Revenant/Idle/Idle_Zero_Pose.uasset (Stored with Git LFS)
BIN
Content/_Game/Character/Revenant/Idle/Idle_Zero_Pose.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Character/Revenant/RevenantAnimBP.uasset (Stored with Git LFS)
BIN
Content/_Game/Character/Revenant/RevenantAnimBP.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Character/Revenant/RevenantCharacterBP.uasset (Stored with Git LFS)
BIN
Content/_Game/Character/Revenant/RevenantCharacterBP.uasset (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/_Game/Character/TwinBlast/HitReact/HitReactMontage.uasset (Stored with Git LFS)
Normal file
BIN
Content/_Game/Character/TwinBlast/HitReact/HitReactMontage.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/_Game/Character/TwinBlast/HitReact/HitReact_Front.uasset (Stored with Git LFS)
Normal file
BIN
Content/_Game/Character/TwinBlast/HitReact/HitReact_Front.uasset (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/_Game/Character/TwinBlast/Idle/Idle_Zero_Pose.uasset (Stored with Git LFS)
BIN
Content/_Game/Character/TwinBlast/Idle/Idle_Zero_Pose.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Character/TwinBlast/TwinBlastAnimBP.uasset (Stored with Git LFS)
BIN
Content/_Game/Character/TwinBlast/TwinBlastAnimBP.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Character/TwinBlast/TwinBlastCharacterBP.uasset (Stored with Git LFS)
BIN
Content/_Game/Character/TwinBlast/TwinBlastCharacterBP.uasset (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/_Game/Enemies/Animations/EnemyHit.uasset (Stored with Git LFS)
BIN
Content/_Game/Enemies/Animations/EnemyHit.uasset (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/_Game/Enemies/EnemyBP.uasset (Stored with Git LFS)
BIN
Content/_Game/Enemies/EnemyBP.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Enemies/GruxAnimBP.uasset (Stored with Git LFS)
BIN
Content/_Game/Enemies/GruxAnimBP.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/EnemyController/EnemyBehaviorTree.uasset (Stored with Git LFS)
BIN
Content/_Game/EnemyController/EnemyBehaviorTree.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/EnemyController/EnemyBlackboard.uasset (Stored with Git LFS)
BIN
Content/_Game/EnemyController/EnemyBlackboard.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/GameMode/ShooterGameModeBaseBP.uasset (Stored with Git LFS)
BIN
Content/_Game/GameMode/ShooterGameModeBaseBP.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Maps/DefaultMap.umap (Stored with Git LFS)
BIN
Content/_Game/Maps/DefaultMap.umap (Stored with Git LFS)
Binary file not shown.
|
@ -15,6 +15,7 @@
|
||||||
#include "ShooterCharacter.h"
|
#include "ShooterCharacter.h"
|
||||||
#include "Components/BoxComponent.h"
|
#include "Components/BoxComponent.h"
|
||||||
#include "Components/CapsuleComponent.h"
|
#include "Components/CapsuleComponent.h"
|
||||||
|
#include "Engine/SkeletalMeshSocket.h"
|
||||||
|
|
||||||
// Sets default values
|
// Sets default values
|
||||||
AEnemy::AEnemy() :
|
AEnemy::AEnemy() :
|
||||||
|
@ -31,7 +32,13 @@ AEnemy::AEnemy() :
|
||||||
AttackRFast(TEXT("AttackRFast")),
|
AttackRFast(TEXT("AttackRFast")),
|
||||||
AttackL(TEXT("AttackL")),
|
AttackL(TEXT("AttackL")),
|
||||||
AttackR(TEXT("AttackR")),
|
AttackR(TEXT("AttackR")),
|
||||||
BaseDamage(20.f)
|
BaseDamage(20.f),
|
||||||
|
LeftWeaponSocket(TEXT("FX_Trail_L_02")),
|
||||||
|
RightWeaponSocket(TEXT("FX_Trail_R_02")),
|
||||||
|
bCanAttack(true),
|
||||||
|
AttackWaitTime(1.f),
|
||||||
|
bDying(false),
|
||||||
|
DeathTime(4.f)
|
||||||
{
|
{
|
||||||
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||||
PrimaryActorTick.bCanEverTick = true;
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
|
@ -82,12 +89,17 @@ void AEnemy::BeginPlay()
|
||||||
|
|
||||||
// Get the AI Controller
|
// Get the AI Controller
|
||||||
EnemyController = Cast<AEnemyController>(GetController());
|
EnemyController = Cast<AEnemyController>(GetController());
|
||||||
|
|
||||||
|
if (EnemyController)
|
||||||
|
{
|
||||||
|
EnemyController->GetBlackboardComponent()->SetValueAsBool(TEXT("CanAttack"), true);
|
||||||
|
}
|
||||||
|
|
||||||
const FVector WorldPatrolPoint = UKismetMathLibrary::TransformLocation(GetActorTransform(), PatrolPoint);
|
const FVector WorldPatrolPoint = UKismetMathLibrary::TransformLocation(GetActorTransform(), PatrolPoint);
|
||||||
DrawDebugSphere(GetWorld(), WorldPatrolPoint, 25.f, 12, FColor::Red, true);
|
//DrawDebugSphere(GetWorld(), WorldPatrolPoint, 25.f, 12, FColor::Red, true);
|
||||||
|
|
||||||
const FVector WorldPatrolPoint2 = UKismetMathLibrary::TransformLocation(GetActorTransform(), PatrolPoint2);
|
const FVector WorldPatrolPoint2 = UKismetMathLibrary::TransformLocation(GetActorTransform(), PatrolPoint2);
|
||||||
DrawDebugSphere(GetWorld(), WorldPatrolPoint2, 25.f, 12, FColor::Blue, true);
|
//DrawDebugSphere(GetWorld(), WorldPatrolPoint2, 25.f, 12, FColor::Blue, true);
|
||||||
|
|
||||||
if (EnemyController)
|
if (EnemyController)
|
||||||
{
|
{
|
||||||
|
@ -105,7 +117,34 @@ void AEnemy::ShowHealthBar_Implementation()
|
||||||
|
|
||||||
void AEnemy::Die()
|
void AEnemy::Die()
|
||||||
{
|
{
|
||||||
|
if (bDying) return;
|
||||||
|
bDying = true;
|
||||||
|
|
||||||
HideHealthBar();
|
HideHealthBar();
|
||||||
|
|
||||||
|
if (EnemyController)
|
||||||
|
{
|
||||||
|
EnemyController->GetBlackboardComponent()->SetValueAsBool("Dead", true);
|
||||||
|
EnemyController->StopMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DeathMontage) return;
|
||||||
|
|
||||||
|
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||||
|
if (!AnimInstance) return;
|
||||||
|
|
||||||
|
AnimInstance->Montage_Play(DeathMontage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEnemy::FinishDeath()
|
||||||
|
{
|
||||||
|
GetMesh()->bPauseAnims = true;
|
||||||
|
GetWorldTimerManager().SetTimer(DeathTimer, this, &AEnemy::DestroyEnemy, DeathTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEnemy::DestroyEnemy()
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEnemy::PlayHitMontage(FName Section, float PlayRate)
|
void AEnemy::PlayHitMontage(FName Section, float PlayRate)
|
||||||
|
@ -188,7 +227,7 @@ void AEnemy::CombatRangeOverlap(UPrimitiveComponent* OverlappedComponent, AActor
|
||||||
|
|
||||||
if (!EnemyController) return;
|
if (!EnemyController) return;
|
||||||
EnemyController->GetBlackboardComponent()->SetValueAsBool(TEXT("InAttackRange"), true);
|
EnemyController->GetBlackboardComponent()->SetValueAsBool(TEXT("InAttackRange"), true);
|
||||||
UE_LOG(LogTemp, Warning, TEXT("overlap player"));
|
//UE_LOG(LogTemp, Warning, TEXT("overlap player"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEnemy::CombatRangeEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
|
void AEnemy::CombatRangeEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
|
||||||
|
@ -201,7 +240,7 @@ void AEnemy::CombatRangeEndOverlap(UPrimitiveComponent* OverlappedComponent, AAc
|
||||||
|
|
||||||
if (!EnemyController) return;
|
if (!EnemyController) return;
|
||||||
EnemyController->GetBlackboardComponent()->SetValueAsBool(TEXT("InAttackRange"), false);
|
EnemyController->GetBlackboardComponent()->SetValueAsBool(TEXT("InAttackRange"), false);
|
||||||
UE_LOG(LogTemp, Warning, TEXT("end overlap player"));
|
//UE_LOG(LogTemp, Warning, TEXT("end overlap player"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEnemy::PlayAttackMontage(FName Section, float PlayRate)
|
void AEnemy::PlayAttackMontage(FName Section, float PlayRate)
|
||||||
|
@ -212,6 +251,12 @@ void AEnemy::PlayAttackMontage(FName Section, float PlayRate)
|
||||||
AnimInstance->Montage_Play(AttackMontage, PlayRate);
|
AnimInstance->Montage_Play(AttackMontage, PlayRate);
|
||||||
AnimInstance->Montage_JumpToSection(Section, AttackMontage);
|
AnimInstance->Montage_JumpToSection(Section, AttackMontage);
|
||||||
}
|
}
|
||||||
|
bCanAttack = false;
|
||||||
|
GetWorldTimerManager().SetTimer(AttackWaitTimer, this, &AEnemy::ResetCanAttack, AttackWaitTime);
|
||||||
|
if (EnemyController)
|
||||||
|
{
|
||||||
|
EnemyController->GetBlackboardComponent()->SetValueAsBool(TEXT("CanAttack"), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FName AEnemy::GetAttackSectionName() const
|
FName AEnemy::GetAttackSectionName() const
|
||||||
|
@ -231,29 +276,73 @@ FName AEnemy::GetAttackSectionName() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEnemy::DoDamage(AActor* Victim)
|
void AEnemy::DoDamage(AShooterCharacter* Victim)
|
||||||
{
|
{
|
||||||
if (!Victim) return;
|
if (!Victim) return;
|
||||||
if (auto const Character = Cast<AShooterCharacter>(Victim))
|
|
||||||
|
UGameplayStatics::ApplyDamage(Victim, BaseDamage, EnemyController, this, UDamageType::StaticClass());
|
||||||
|
if (USoundCue* MeleeImpactSound = Victim->GetMeleeImpactSound())
|
||||||
{
|
{
|
||||||
UGameplayStatics::ApplyDamage(Character, BaseDamage, EnemyController, this, UDamageType::StaticClass());
|
UGameplayStatics::PlaySoundAtLocation(this, MeleeImpactSound, GetActorLocation());
|
||||||
if (USoundCue* MeleeImpactSound = Character->GetMeleeImpactSound())
|
|
||||||
{
|
|
||||||
UGameplayStatics::PlaySoundAtLocation(this, MeleeImpactSound, GetActorLocation());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEnemy::OnLeftWeaponOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
|
void AEnemy::SpawnBlood(AShooterCharacter* Victim, FName WeaponSocket)
|
||||||
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
|
|
||||||
{
|
{
|
||||||
DoDamage(OtherActor);
|
if (!Victim) return;
|
||||||
|
|
||||||
|
UParticleSystem* Particles = Victim->GetBloodParticles();
|
||||||
|
if (!Particles) return;
|
||||||
|
|
||||||
|
const USkeletalMeshSocket* TipSocket{ GetMesh()->GetSocketByName(WeaponSocket) };
|
||||||
|
if (!TipSocket) return;
|
||||||
|
|
||||||
|
const FTransform SocketTransform{ TipSocket->GetSocketTransform(GetMesh()) };
|
||||||
|
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), Particles, SocketTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEnemy::StunCharacter(AShooterCharacter* Victim)
|
||||||
|
{
|
||||||
|
if (!Victim) return;
|
||||||
|
|
||||||
|
const float Stun{ FMath::RandRange(0.f,1.f) };
|
||||||
|
|
||||||
|
if (Stun <= Victim->GetStunChance())
|
||||||
|
{
|
||||||
|
Victim->Stun();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEnemy::ResetCanAttack()
|
||||||
|
{
|
||||||
|
bCanAttack = true;
|
||||||
|
|
||||||
|
if (!EnemyController) return;
|
||||||
|
EnemyController->GetBlackboardComponent()->SetValueAsBool(TEXT("CanAttack"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEnemy::OnLeftWeaponOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
|
||||||
|
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
|
||||||
|
{
|
||||||
|
auto const Character = Cast<AShooterCharacter>(OtherActor);
|
||||||
|
if (Character)
|
||||||
|
{
|
||||||
|
DoDamage(Character);
|
||||||
|
SpawnBlood(Character, LeftWeaponSocket);
|
||||||
|
StunCharacter(Character);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEnemy::OnRightWeaponOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
|
void AEnemy::OnRightWeaponOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
|
||||||
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
|
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
|
||||||
{
|
{
|
||||||
DoDamage(OtherActor);
|
auto const Character = Cast<AShooterCharacter>(OtherActor);
|
||||||
|
if (Character)
|
||||||
|
{
|
||||||
|
DoDamage(Character);
|
||||||
|
SpawnBlood(Character, RightWeaponSocket);
|
||||||
|
StunCharacter(Character);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEnemy::ActivateLeftWeapon()
|
void AEnemy::ActivateLeftWeapon()
|
||||||
|
@ -302,6 +391,8 @@ void AEnemy::BulletHit_Implementation(FHitResult HitResult)
|
||||||
{
|
{
|
||||||
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactParticles, HitResult.Location, FRotator(0.f), true);
|
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactParticles, HitResult.Location, FRotator(0.f), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bDying) return;
|
||||||
|
|
||||||
ShowHealthBar();
|
ShowHealthBar();
|
||||||
|
|
||||||
|
@ -318,6 +409,12 @@ void AEnemy::BulletHit_Implementation(FHitResult HitResult)
|
||||||
float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator,
|
float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator,
|
||||||
AActor* DamageCauser)
|
AActor* DamageCauser)
|
||||||
{
|
{
|
||||||
|
// Set the Target blackboard key to aggro the character
|
||||||
|
if (EnemyController)
|
||||||
|
{
|
||||||
|
EnemyController->GetBlackboardComponent()->SetValueAsObject(FName("Target"), DamageCauser);
|
||||||
|
}
|
||||||
|
|
||||||
float DamageInflicted = DamageAmount;
|
float DamageInflicted = DamageAmount;
|
||||||
if (Health - DamageAmount <= 0.f)
|
if (Health - DamageAmount <= 0.f)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,7 @@ class UBehaviorTree;
|
||||||
class AEnemyController;
|
class AEnemyController;
|
||||||
class USphereComponent;
|
class USphereComponent;
|
||||||
class UBoxComponent;
|
class UBoxComponent;
|
||||||
|
class AShooterCharacter;
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class SHOOTER_API AEnemy : public ACharacter, public IBulletHitInterface
|
class SHOOTER_API AEnemy : public ACharacter, public IBulletHitInterface
|
||||||
|
@ -99,7 +100,18 @@ protected:
|
||||||
UFUNCTION(BlueprintCallable)
|
UFUNCTION(BlueprintCallable)
|
||||||
void DeactivateRightWeapon();
|
void DeactivateRightWeapon();
|
||||||
|
|
||||||
void DoDamage(AActor* Victim);
|
void DoDamage(AShooterCharacter* Victim);
|
||||||
|
void SpawnBlood(AShooterCharacter* Victim, FName WeaponSocket);
|
||||||
|
|
||||||
|
// Attemp to stun character
|
||||||
|
void StunCharacter(AShooterCharacter* Victim);
|
||||||
|
|
||||||
|
void ResetCanAttack();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
void FinishDeath();
|
||||||
|
|
||||||
|
void DestroyEnemy();
|
||||||
private:
|
private:
|
||||||
/** Particles to spawn when hit by bullets */
|
/** Particles to spawn when hit by bullets */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
@ -202,6 +214,34 @@ private:
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
float BaseDamage;
|
float BaseDamage;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
FName LeftWeaponSocket;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
FName RightWeaponSocket;
|
||||||
|
|
||||||
|
/** True when Enemy can attack */
|
||||||
|
UPROPERTY(VisibleAnywhere, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
bool bCanAttack;
|
||||||
|
|
||||||
|
FTimerHandle AttackWaitTimer;
|
||||||
|
|
||||||
|
/** Min wait time between attacks */
|
||||||
|
UPROPERTY(EditAnywhere, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
float AttackWaitTime;
|
||||||
|
|
||||||
|
/** Death anim montage */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
UAnimMontage* DeathMontage;
|
||||||
|
|
||||||
|
bool bDying;
|
||||||
|
|
||||||
|
FTimerHandle DeathTimer;
|
||||||
|
|
||||||
|
/** Time after death until Destroy */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
float DeathTime;
|
||||||
public:
|
public:
|
||||||
// Called every frame
|
// Called every frame
|
||||||
virtual void Tick(float DeltaTime) override;
|
virtual void Tick(float DeltaTime) override;
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include "BulletHitInterface.h"
|
#include "BulletHitInterface.h"
|
||||||
#include "Enemy.h"
|
#include "Enemy.h"
|
||||||
#include "PhysicalMaterials/PhysicalMaterial.h"
|
#include "PhysicalMaterials/PhysicalMaterial.h"
|
||||||
|
#include "EnemyController.h"
|
||||||
|
#include "BehaviorTree/BlackboardComponent.h"
|
||||||
|
|
||||||
// Sets default values
|
// Sets default values
|
||||||
AShooterCharacter::AShooterCharacter() :
|
AShooterCharacter::AShooterCharacter() :
|
||||||
|
@ -79,7 +81,8 @@ AShooterCharacter::AShooterCharacter() :
|
||||||
// Icon animation property
|
// Icon animation property
|
||||||
HighlightedSlot(-1),
|
HighlightedSlot(-1),
|
||||||
Health(100.f),
|
Health(100.f),
|
||||||
MaxHealth(100.f)
|
MaxHealth(100.f),
|
||||||
|
StunChance(.25f)
|
||||||
{
|
{
|
||||||
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||||
PrimaryActorTick.bCanEverTick = true;
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
|
@ -212,7 +215,13 @@ float AShooterCharacter::TakeDamage(float DamageAmount, FDamageEvent const& Dama
|
||||||
{
|
{
|
||||||
DamageInflicted = Health;
|
DamageInflicted = Health;
|
||||||
Health = 0.f;
|
Health = 0.f;
|
||||||
//Die();
|
Die();
|
||||||
|
|
||||||
|
auto EnemyController = Cast<AEnemyController>(EventInstigator);
|
||||||
|
if (EnemyController)
|
||||||
|
{
|
||||||
|
EnemyController->GetBlackboardComponent()->SetValueAsBool(FName("CharacterDead"), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -221,6 +230,26 @@ float AShooterCharacter::TakeDamage(float DamageAmount, FDamageEvent const& Dama
|
||||||
return DamageInflicted;
|
return DamageInflicted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AShooterCharacter::Die()
|
||||||
|
{
|
||||||
|
if (!DeathMontage) return;
|
||||||
|
|
||||||
|
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||||
|
if (!AnimInstance) return;
|
||||||
|
|
||||||
|
AnimInstance->Montage_Play(DeathMontage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AShooterCharacter::FinishDeath()
|
||||||
|
{
|
||||||
|
GetMesh()->bPauseAnims = true;
|
||||||
|
APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
|
||||||
|
if (PC)
|
||||||
|
{
|
||||||
|
DisableInput(PC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Called every frame
|
// Called every frame
|
||||||
void AShooterCharacter::Tick(float DeltaTime)
|
void AShooterCharacter::Tick(float DeltaTime)
|
||||||
{
|
{
|
||||||
|
@ -309,7 +338,9 @@ void AShooterCharacter::LookUp(float Value)
|
||||||
void AShooterCharacter::AimingButtonPressed()
|
void AShooterCharacter::AimingButtonPressed()
|
||||||
{
|
{
|
||||||
bAimingButtonPressed = true;
|
bAimingButtonPressed = true;
|
||||||
if (CombatState != ECombatState::ECS_Reloading && CombatState != ECombatState::ECS_Equipping)
|
if (CombatState != ECombatState::ECS_Reloading &&
|
||||||
|
CombatState != ECombatState::ECS_Equipping &&
|
||||||
|
CombatState != ECombatState::ECS_Stunned)
|
||||||
{
|
{
|
||||||
Aim();
|
Aim();
|
||||||
}
|
}
|
||||||
|
@ -504,6 +535,16 @@ EPhysicalSurface AShooterCharacter::GetSurfaceType()
|
||||||
return UPhysicalMaterial::DetermineSurfaceType(HitResult.PhysMaterial.Get());
|
return UPhysicalMaterial::DetermineSurfaceType(HitResult.PhysMaterial.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AShooterCharacter::EndStun()
|
||||||
|
{
|
||||||
|
CombatState = ECombatState::ECS_Unoccupied;
|
||||||
|
|
||||||
|
if (bAimingButtonPressed)
|
||||||
|
{
|
||||||
|
Aim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AShooterCharacter::UnhighlightInventorySlot()
|
void AShooterCharacter::UnhighlightInventorySlot()
|
||||||
{
|
{
|
||||||
if (HighlightedSlot != -1)
|
if (HighlightedSlot != -1)
|
||||||
|
@ -513,6 +554,19 @@ void AShooterCharacter::UnhighlightInventorySlot()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AShooterCharacter::Stun()
|
||||||
|
{
|
||||||
|
if (Health <= 0.f) return;
|
||||||
|
if (!HitReactMontage) return;
|
||||||
|
|
||||||
|
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
|
||||||
|
if (!AnimInstance) return;
|
||||||
|
|
||||||
|
CombatState = ECombatState::ECS_Stunned;
|
||||||
|
|
||||||
|
AnimInstance->Montage_Play(HitReactMontage);
|
||||||
|
}
|
||||||
|
|
||||||
int32 AShooterCharacter::GetInterpLocationIndex()
|
int32 AShooterCharacter::GetInterpLocationIndex()
|
||||||
{
|
{
|
||||||
int32 LowestIndex = 1;
|
int32 LowestIndex = 1;
|
||||||
|
@ -632,7 +686,8 @@ void AShooterCharacter::StartFireTimer()
|
||||||
void AShooterCharacter::AutoFireReset()
|
void AShooterCharacter::AutoFireReset()
|
||||||
{
|
{
|
||||||
if (!EquippedWeapon) return;
|
if (!EquippedWeapon) return;
|
||||||
|
if (CombatState == ECombatState::ECS_Stunned) return;
|
||||||
|
|
||||||
CombatState = ECombatState::ECS_Unoccupied;
|
CombatState = ECombatState::ECS_Unoccupied;
|
||||||
|
|
||||||
if (WeaponHasAmmo())
|
if (WeaponHasAmmo())
|
||||||
|
@ -1135,6 +1190,7 @@ void AShooterCharacter::ReloadWeapon()
|
||||||
void AShooterCharacter::FinishReloading()
|
void AShooterCharacter::FinishReloading()
|
||||||
{
|
{
|
||||||
if (!EquippedWeapon) return;
|
if (!EquippedWeapon) return;
|
||||||
|
if (CombatState == ECombatState::ECS_Stunned) return;
|
||||||
|
|
||||||
CombatState = ECombatState::ECS_Unoccupied;
|
CombatState = ECombatState::ECS_Unoccupied;
|
||||||
|
|
||||||
|
@ -1175,6 +1231,8 @@ void AShooterCharacter::FinishReloading()
|
||||||
|
|
||||||
void AShooterCharacter::FinishEquipping()
|
void AShooterCharacter::FinishEquipping()
|
||||||
{
|
{
|
||||||
|
if (CombatState == ECombatState::ECS_Stunned) return;
|
||||||
|
|
||||||
CombatState = ECombatState::ECS_Unoccupied;
|
CombatState = ECombatState::ECS_Unoccupied;
|
||||||
|
|
||||||
if (bAimingButtonPressed)
|
if (bAimingButtonPressed)
|
||||||
|
|
|
@ -21,12 +21,13 @@ class AAmmo;
|
||||||
UENUM(BlueprintType)
|
UENUM(BlueprintType)
|
||||||
enum class ECombatState : uint8
|
enum class ECombatState : uint8
|
||||||
{
|
{
|
||||||
ECS_Unoccupied UMETA(DisplayName = "Unoccupied"),
|
ECS_Unoccupied UMETA(DisplayName = "Unoccupied"),
|
||||||
ECS_FireTimerInProgress UMETA(DisplayName = "FireTimerInProgress"),
|
ECS_FireTimerInProgress UMETA(DisplayName = "FireTimerInProgress"),
|
||||||
ECS_Reloading UMETA(DisplayName = "Reloading"),
|
ECS_Reloading UMETA(DisplayName = "Reloading"),
|
||||||
ECS_Equipping UMETA(DisplayName = "Equipping"),
|
ECS_Equipping UMETA(DisplayName = "Equipping"),
|
||||||
|
ECS_Stunned UMETA(DisplayName = "Stunned"),
|
||||||
|
|
||||||
ECS_MAX UMETA(DisplayName = "DefaultMax")
|
ECS_MAX UMETA(DisplayName = "DefaultMax")
|
||||||
};
|
};
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
|
@ -221,6 +222,13 @@ protected:
|
||||||
UFUNCTION(BlueprintCallable)
|
UFUNCTION(BlueprintCallable)
|
||||||
EPhysicalSurface GetSurfaceType();
|
EPhysicalSurface GetSurfaceType();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
void EndStun();
|
||||||
|
|
||||||
|
void Die();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
void FinishDeath();
|
||||||
private:
|
private:
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = true))
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = true))
|
||||||
USpringArmComponent* CameraBoom;
|
USpringArmComponent* CameraBoom;
|
||||||
|
@ -500,6 +508,22 @@ private:
|
||||||
/** Sound made when character gets hit by a melee attack */
|
/** Sound made when character gets hit by a melee attack */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
USoundCue* MeleeImpactSound;
|
USoundCue* MeleeImpactSound;
|
||||||
|
|
||||||
|
/** Blood splatter particles for melee hit */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
UParticleSystem* BloodParticles;
|
||||||
|
|
||||||
|
/** Hit react anim montage; for when the character is stunned */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
UAnimMontage* HitReactMontage;
|
||||||
|
|
||||||
|
/** Chance of being stunned when hit by an enemy */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
float StunChance;
|
||||||
|
|
||||||
|
/** Character death anim montage */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
UAnimMontage* DeathMontage;
|
||||||
public:
|
public:
|
||||||
/* Returns CameraBoom SubObject */
|
/* Returns CameraBoom SubObject */
|
||||||
FORCEINLINE USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
|
FORCEINLINE USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
|
||||||
|
@ -557,4 +581,8 @@ public:
|
||||||
float GetMaxHealth() const { return MaxHealth; }
|
float GetMaxHealth() const { return MaxHealth; }
|
||||||
|
|
||||||
FORCEINLINE USoundCue* GetMeleeImpactSound() const { return MeleeImpactSound; }
|
FORCEINLINE USoundCue* GetMeleeImpactSound() const { return MeleeImpactSound; }
|
||||||
|
FORCEINLINE UParticleSystem* GetBloodParticles() const { return BloodParticles; }
|
||||||
|
|
||||||
|
void Stun();
|
||||||
|
FORCEINLINE float GetStunChance() const { return StunChance; }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue