Section 13: The Enemy Class - Lecture 266

Remove Hit Number
This commit is contained in:
charnet3d 2024-03-03 13:21:33 +01:00
parent 09827265de
commit e70a5a290b
14 changed files with 134 additions and 15 deletions

Binary file not shown.

Binary file not shown.

BIN
Content/_Game/Enemies/Animations/EnemyHit.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/_Game/Enemies/EnemyBP.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/_Game/Enemies/GruxAnimBP.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/_Game/HUD/EnemyHealthBarBP.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/_Game/HUD/HitNumber.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/_Game/Maps/DefaultMap.umap (Stored with Git LFS)

Binary file not shown.

View File

@ -2,6 +2,8 @@
#include "Enemy.h"
#include "Blueprint/UserWidget.h"
#include "Kismet/GameplayStatics.h"
#include "Sound/SoundCue.h"
#include "Particles/ParticleSystemComponent.h"
@ -10,7 +12,11 @@
AEnemy::AEnemy() :
Health(100.f),
MaxHealth(100.f),
HealthBarDisplayTime(4.f)
HealthBarDisplayTime(4.f),
HitReactTimeMin(.5f),
HitReactTimeMax(1.f),
bCanHitReact(true),
HitNumberDestroyTime(1.5f)
{
// 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;
@ -31,6 +37,47 @@ void AEnemy::ShowHealthBar_Implementation()
GetWorldTimerManager().SetTimer(HealthBarTimer, this, &AEnemy::HideHealthBar, HealthBarDisplayTime);
}
void AEnemy::Die()
{
HideHealthBar();
}
void AEnemy::PlayHitMontage(FName Section, float PlayRate)
{
if (!bCanHitReact) return;
if (UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance())
{
AnimInstance->Montage_Play(HitMontage, PlayRate);
AnimInstance->Montage_JumpToSection(Section, HitMontage);
bCanHitReact = false;
const float HitReactTime{ FMath::FRandRange(HitReactTimeMin, HitReactTimeMax) };
GetWorldTimerManager().SetTimer(HitReactTimer, this, &AEnemy::ResetHitReactTimer, HitReactTime);
}
}
void AEnemy::ResetHitReactTimer()
{
bCanHitReact = true;
}
void AEnemy::StoreHitNumber(UUserWidget* HitNumber, FVector Location)
{
HitNumbers.Add(HitNumber, Location);
FTimerHandle HitNumberTimer;
FTimerDelegate HitNumberDelegate;
HitNumberDelegate.BindUFunction(this, FName("DestroyHitNumber"), HitNumber);
GetWorldTimerManager().SetTimer(HitNumberTimer, HitNumberDelegate, HitNumberDestroyTime, false);
}
void AEnemy::DestroyHitNumber(UUserWidget* HitNumber)
{
HitNumbers.Remove(HitNumber);
HitNumber->RemoveFromParent();
}
// Called every frame
void AEnemy::Tick(float DeltaTime)
{
@ -58,6 +105,8 @@ void AEnemy::BulletHit_Implementation(FHitResult HitResult)
}
ShowHealthBar();
PlayHitMontage(FName("HitReactFront"));
}
float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator,
@ -68,6 +117,7 @@ float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AC
{
DamageInflicted = Health;
Health = 0.f;
Die();
}
else
{

View File

@ -9,6 +9,7 @@
class UParticleSystem;
class USoundCue;
class UAnimMontage;
UCLASS()
class SHOOTER_API AEnemy : public ACharacter, public IBulletHitInterface
@ -29,7 +30,18 @@ protected:
UFUNCTION(BlueprintImplementableEvent)
void HideHealthBar();
void Die();
void PlayHitMontage(FName Section, float PlayRate = 1.0f);
void ResetHitReactTimer();
UFUNCTION(BlueprintCallable)
void StoreHitNumber(UUserWidget* HitNumber, FVector Location);
UFUNCTION()
void DestroyHitNumber(UUserWidget* HitNumber);
private:
/** Particles to spawn when hit by bullets */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
@ -55,6 +67,28 @@ private:
float HealthBarDisplayTime;
FTimerHandle HealthBarTimer;
/** Montage containing Hit and Death animations */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
UAnimMontage* HitMontage;
FTimerHandle HitReactTimer;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
float HitReactTimeMin;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
float HitReactTimeMax;
bool bCanHitReact;
/** Map to store HitNumber widgets and their hit locations */
UPROPERTY(VisibleAnywhere, Category = Combat, meta = (AllowPrivateAccess = true))
TMap<UUserWidget*, FVector> HitNumbers;
/** Time before a hit number is removed from the screen */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true))
float HitNumberDestroyTime;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
@ -67,4 +101,7 @@ public:
virtual float TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
FORCEINLINE FString GetHeadBone() const { return HeadBone; }
UFUNCTION(BlueprintImplementableEvent)
void ShowHitNumber(int32 Damage, FVector HitLocation);
};

View File

@ -0,0 +1,5 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "GruxAnimInstance.h"

View File

@ -0,0 +1,17 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "GruxAnimInstance.generated.h"
/**
*
*/
UCLASS()
class SHOOTER_API UGruxAnimInstance : public UAnimInstance
{
GENERATED_BODY()
};

View File

@ -688,7 +688,8 @@ void AShooterCharacter::SendBullet()
damageToApply,
GetController(), this,
UDamageType::StaticClass());
UE_LOG(LogTemp, Warning, TEXT("Hit Component: %s"), *BeamHitResult.BoneName.ToString());
HitEnemy->ShowHitNumber(damageToApply, BeamHitResult.Location);
}
}
else