Protptype of a wave based, first person shooter game made in Unreal Engine 4
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
MechDefence/Private/MAICharacterBase.cpp

181 lines
5.5 KiB

#include "MAICharacterBase.h"
#include "MCharacter.h"
#include "Components/CapsuleComponent.h"
#include "Components/ShapeComponent.h"
#include "Components/WidgetComponent.h"
#include "MGameplayActor.h"
#include "MHealthComponent.h"
#include "Misc/OutputDeviceDebug.h"
AMAICharacterBase::AMAICharacterBase()
{
PrimaryActorTick.bCanEverTick = true;
HealthComponent = CreateDefaultSubobject<UMHealthComponent>(TEXT("HealthComponent"));
HealthComponent->OnActorDeath.AddDynamic(this, &AMAICharacterBase::HandleCharacterDeath);
static ConstructorHelpers::FClassFinder<AMGameplayActor> SafeZoneClassFinder(TEXT("/Game/MechDefence/Blueprints/Buildings/BP_Beacon"));
SafeZoneClass = SafeZoneClassFinder.Class;
SafeZoneTags.AddTag(FGameplayTag::RequestGameplayTag("PlayerTeam.Beacon"));
StatusIndicatorWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("Status Indicator"));
StatusIndicatorWidget->SetupAttachment(RootComponent);
bIsInSafeZone = true;
}
void AMAICharacterBase::BeginPlay()
{
Super::BeginPlay();
UShapeComponent* OverlappingShape = GetSafeZoneOverlappingShape();
if(OverlappingShape)
{
OverlappingShape->OnComponentBeginOverlap.AddDynamic(this, &AMAICharacterBase::HandleSafeZoneBeginOverlap);
OverlappingShape->OnComponentEndOverlap.AddDynamic(this, &AMAICharacterBase::HandleSafeZoneEndOverlap);
}
// Perform these in the next tick to make sure everything is spawned and assigned before we go further
GetWorldTimerManager().SetTimerForNextTick(this, &AMAICharacterBase::CheckSafeZone);
GetWorldTimerManager().SetTimerForNextTick(this, &AMAICharacterBase::SetWidgetHealthComponentProperty);
}
void AMAICharacterBase::SetWidgetHealthComponentProperty()
{
UUserWidget* IndicatorWidget = StatusIndicatorWidget->GetWidget();
if(IndicatorWidget)
{
FObjectProperty* ObjProp = FindFProperty<FObjectProperty>(IndicatorWidget->GetClass(), TEXT("HealthComponent"));
if(ObjProp)
{
ObjProp->SetObjectPropertyValue_InContainer(IndicatorWidget, HealthComponent, 0);
//ObjProp->SetPropertyValue_InContainer(IndicatorWidget, HealthComponent, 0);
}
const FString Command = FString::Printf(TEXT("SetupHealthChangeAnims"));
FOutputDeviceDebug DebugOutputDevice;
if(!IndicatorWidget->CallFunctionByNameWithArguments(*Command, DebugOutputDevice, IndicatorWidget, true))
{
UE_LOG(LogTemp, Log, TEXT("Failed to setup health change anims"));
}
}
}
UShapeComponent* AMAICharacterBase::GetSafeZoneOverlappingShape()
{
return GetCapsuleComponent();
}
void AMAICharacterBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AMAICharacterBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void AMAICharacterBase::GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const
{
TagContainer = ActorTags;
}
void AMAICharacterBase::HandleSafeZoneBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
IGameplayTagAssetInterface* GameplayTagAsset = Cast<IGameplayTagAssetInterface>(OtherActor);
if(GameplayTagAsset && GameplayTagAsset->HasAnyMatchingGameplayTags(SafeZoneTags) && !bIsInSafeZone)
{
EnterSafeZone(OtherActor);
}
}
void AMAICharacterBase::HandleSafeZoneEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
IGameplayTagAssetInterface* GameplayTagAsset = Cast<IGameplayTagAssetInterface>(OtherActor);
if(GameplayTagAsset && GameplayTagAsset->HasAnyMatchingGameplayTags(SafeZoneTags) && bIsInSafeZone)
{
// Check again just to make sure
CheckSafeZone();
}
}
void AMAICharacterBase::HandleCharacterDeath(UMHealthComponent* ActorHealthComponent, AActor* DeadActor, AActor* KillerActor)
{
UShapeComponent* ShapeMesh = GetSafeZoneOverlappingShape();
ShapeMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
DeadActor->SetActorEnableCollision(false);
}
void AMAICharacterBase::AddGameplayTags(const FGameplayTagContainer& TagContainer)
{
ActorTags.AppendTags(TagContainer);
}
void AMAICharacterBase::AddGameplayTag(const FGameplayTag& Tag)
{
ActorTags.AddTag(Tag);
}
void AMAICharacterBase::LeaveSafeZone()
{
bIsInSafeZone = false;
OnAILeaveSafeZone.Broadcast(this);
if(StatusIndicatorWidget)
{
StatusIndicatorWidget->SetVisibility(false, true);
}
}
void AMAICharacterBase::EnterSafeZone(AActor* SafeZoneActor)
{
OnAIEnterSafeZone.Broadcast(this, SafeZoneActor);
bIsInSafeZone = true;
if(StatusIndicatorWidget)
{
StatusIndicatorWidget->SetVisibility(true, true);
}
}
void AMAICharacterBase::CheckSafeZone()
{
TArray<AActor*> OverlappingActors;
UShapeComponent* SafeZoneOverlappingShape = GetSafeZoneOverlappingShape();
if(SafeZoneOverlappingShape)
{
SafeZoneOverlappingShape->GetOverlappingActors(OverlappingActors, SafeZoneClass);
if(OverlappingActors.Num() == 0)
{
if(bIsInSafeZone)
LeaveSafeZone();
}
else if(OverlappingActors.Num() > 0)
{
IGameplayTagAssetInterface* GameplayTagAsset = Cast<IGameplayTagAssetInterface>(OverlappingActors[0]);
if(GameplayTagAsset && GameplayTagAsset->HasAnyMatchingGameplayTags(SafeZoneTags))
{
if(!bIsInSafeZone) // If we're not in safe zone yet, enter it
{
EnterSafeZone(OverlappingActors[0]);
}
else
{
// If we're already in safe zone, check if we need healing
}
}
}
}
}