Section 15: AI and Behavior Trees - Lecture 284
Stunned Blackboard Decorator
This commit is contained in:
parent
860e2d43cd
commit
d005e4543f
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.
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/Maps/DefaultMap.umap (Stored with Git LFS)
BIN
Content/_Game/Maps/DefaultMap.umap (Stored with Git LFS)
Binary file not shown.
|
@ -11,6 +11,8 @@
|
||||||
#include "DrawDebugHelpers.h"
|
#include "DrawDebugHelpers.h"
|
||||||
#include "EnemyController.h"
|
#include "EnemyController.h"
|
||||||
#include "BehaviorTree/BlackboardComponent.h"
|
#include "BehaviorTree/BlackboardComponent.h"
|
||||||
|
#include "Components/SphereComponent.h"
|
||||||
|
#include "ShooterCharacter.h"
|
||||||
|
|
||||||
// Sets default values
|
// Sets default values
|
||||||
AEnemy::AEnemy() :
|
AEnemy::AEnemy() :
|
||||||
|
@ -20,10 +22,16 @@ AEnemy::AEnemy() :
|
||||||
HitReactTimeMin(.5f),
|
HitReactTimeMin(.5f),
|
||||||
HitReactTimeMax(1.f),
|
HitReactTimeMax(1.f),
|
||||||
bCanHitReact(true),
|
bCanHitReact(true),
|
||||||
HitNumberDestroyTime(1.5f)
|
HitNumberDestroyTime(1.5f),
|
||||||
|
bStunned(false),
|
||||||
|
StunChance(.5f)
|
||||||
{
|
{
|
||||||
// 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;
|
||||||
|
|
||||||
|
// Create the Agro Sphere
|
||||||
|
AgroSphere = CreateDefaultSubobject<USphereComponent>(TEXT("AgroSphere"));
|
||||||
|
AgroSphere->SetupAttachment(GetRootComponent());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the game starts or when spawned
|
// Called when the game starts or when spawned
|
||||||
|
@ -31,6 +39,8 @@ void AEnemy::BeginPlay()
|
||||||
{
|
{
|
||||||
Super::BeginPlay();
|
Super::BeginPlay();
|
||||||
|
|
||||||
|
AgroSphere->OnComponentBeginOverlap.AddDynamic(this, &AEnemy::AgroSphereOverlap);
|
||||||
|
|
||||||
GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block);
|
GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block);
|
||||||
|
|
||||||
// Get the AI Controller
|
// Get the AI Controller
|
||||||
|
@ -39,12 +49,15 @@ void AEnemy::BeginPlay()
|
||||||
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);
|
||||||
|
DrawDebugSphere(GetWorld(), WorldPatrolPoint2, 25.f, 12, FColor::Blue, true);
|
||||||
|
|
||||||
if (EnemyController)
|
if (EnemyController)
|
||||||
{
|
{
|
||||||
EnemyController->GetBlackboardComponent()->SetValueAsVector("PatrolPoint", WorldPatrolPoint);
|
EnemyController->GetBlackboardComponent()->SetValueAsVector("PatrolPoint", WorldPatrolPoint);
|
||||||
|
EnemyController->GetBlackboardComponent()->SetValueAsVector("PatrolPoint2", WorldPatrolPoint2);
|
||||||
EnemyController->RunBehaviorTree(BehaviorTree);
|
EnemyController->RunBehaviorTree(BehaviorTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEnemy::ShowHealthBar_Implementation()
|
void AEnemy::ShowHealthBar_Implementation()
|
||||||
|
@ -108,6 +121,25 @@ void AEnemy::UpdateHitNumbers()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AEnemy::AgroSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
|
||||||
|
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
|
||||||
|
{
|
||||||
|
if (!OtherActor) return;
|
||||||
|
auto Character = Cast<AShooterCharacter>(OtherActor);
|
||||||
|
if (!Character) return;
|
||||||
|
|
||||||
|
// Set the value of the Target blackboard key
|
||||||
|
EnemyController->GetBlackboardComponent()->SetValueAsObject(TEXT("Target"), Character);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AEnemy::SetStunned(bool Stunned)
|
||||||
|
{
|
||||||
|
bStunned = Stunned;
|
||||||
|
|
||||||
|
if (!EnemyController) return;
|
||||||
|
EnemyController->GetBlackboardComponent()->SetValueAsBool(TEXT("Stunned"), Stunned);
|
||||||
|
}
|
||||||
|
|
||||||
// Called every frame
|
// Called every frame
|
||||||
void AEnemy::Tick(float DeltaTime)
|
void AEnemy::Tick(float DeltaTime)
|
||||||
{
|
{
|
||||||
|
@ -137,7 +169,14 @@ void AEnemy::BulletHit_Implementation(FHitResult HitResult)
|
||||||
|
|
||||||
ShowHealthBar();
|
ShowHealthBar();
|
||||||
|
|
||||||
PlayHitMontage(FName("HitReactFront"));
|
// Determine whether bullet hit stuns
|
||||||
|
const float Stunned = FMath::FRandRange(0.f, 1.f);
|
||||||
|
if (Stunned <= StunChance)
|
||||||
|
{
|
||||||
|
// Stun the Enemy
|
||||||
|
PlayHitMontage(FName("HitReactFront"));
|
||||||
|
SetStunned(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator,
|
float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator,
|
||||||
|
|
|
@ -12,6 +12,7 @@ class USoundCue;
|
||||||
class UAnimMontage;
|
class UAnimMontage;
|
||||||
class UBehaviorTree;
|
class UBehaviorTree;
|
||||||
class AEnemyController;
|
class AEnemyController;
|
||||||
|
class USphereComponent;
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class SHOOTER_API AEnemy : public ACharacter, public IBulletHitInterface
|
class SHOOTER_API AEnemy : public ACharacter, public IBulletHitInterface
|
||||||
|
@ -46,6 +47,15 @@ protected:
|
||||||
void DestroyHitNumber(UUserWidget* HitNumber);
|
void DestroyHitNumber(UUserWidget* HitNumber);
|
||||||
|
|
||||||
void UpdateHitNumbers();
|
void UpdateHitNumbers();
|
||||||
|
|
||||||
|
/** Called when something overlaps with the agro sphere */
|
||||||
|
UFUNCTION()
|
||||||
|
void AgroSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
|
||||||
|
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
|
||||||
|
const FHitResult& SweepResult);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
void SetStunned(bool Stunned);
|
||||||
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))
|
||||||
|
@ -102,7 +112,23 @@ private:
|
||||||
UPROPERTY(EditAnywhere, Category = "Behavior Tree", meta = (AllowPrivateAccess = true, MakeEditWidget = true))
|
UPROPERTY(EditAnywhere, Category = "Behavior Tree", meta = (AllowPrivateAccess = true, MakeEditWidget = true))
|
||||||
FVector PatrolPoint;
|
FVector PatrolPoint;
|
||||||
|
|
||||||
|
/** 2nd Point for the enemy to move to */
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Behavior Tree", meta = (AllowPrivateAccess = true, MakeEditWidget = true))
|
||||||
|
FVector PatrolPoint2;
|
||||||
|
|
||||||
AEnemyController* EnemyController;
|
AEnemyController* EnemyController;
|
||||||
|
|
||||||
|
/** Overlap sphere for when the enemy becomes hostile */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Behavior Tree", meta = (AllowPrivateAccess = true))
|
||||||
|
USphereComponent* AgroSphere;
|
||||||
|
|
||||||
|
/** True when playing the get hit animation */
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
bool bStunned;
|
||||||
|
|
||||||
|
/** Chance of being stunned. 0: no stun chance, 1: 100% stun chance */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
|
||||||
|
float StunChance;
|
||||||
public:
|
public:
|
||||||
// Called every frame
|
// Called every frame
|
||||||
virtual void Tick(float DeltaTime) override;
|
virtual void Tick(float DeltaTime) override;
|
||||||
|
|
|
@ -3,3 +3,17 @@
|
||||||
|
|
||||||
#include "GruxAnimInstance.h"
|
#include "GruxAnimInstance.h"
|
||||||
|
|
||||||
|
#include "Enemy.h"
|
||||||
|
|
||||||
|
void UGruxAnimInstance::UpdateAnimationProperties(float DeltaTime)
|
||||||
|
{
|
||||||
|
if (!Enemy)
|
||||||
|
{
|
||||||
|
Enemy = Cast<AEnemy>(TryGetPawnOwner());
|
||||||
|
if (!Enemy) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FVector Velocity { Enemy->GetVelocity() };
|
||||||
|
Velocity.Z = 0.f;
|
||||||
|
Speed = Velocity.Size();
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include "Animation/AnimInstance.h"
|
#include "Animation/AnimInstance.h"
|
||||||
#include "GruxAnimInstance.generated.h"
|
#include "GruxAnimInstance.generated.h"
|
||||||
|
|
||||||
|
class AEnemy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -14,4 +16,15 @@ class SHOOTER_API UGruxAnimInstance : public UAnimInstance
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
void UpdateAnimationProperties(float DeltaTime);
|
||||||
|
private:
|
||||||
|
/** Lateral Movement Speed */
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Movement, meta = (AllowPrivateAccess = true))
|
||||||
|
float Speed;
|
||||||
|
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = true))
|
||||||
|
AEnemy* Enemy;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue