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/MConstructableBuilding.cpp

215 lines
7.0 KiB

#include "MConstructableBuilding.h"
#include "MHealthComponent.h"
#include "Components/BoxComponent.h"
#include "Components/ShapeComponent.h"
#include "../MechDefence.h"
#include "Blueprint/UserWidget.h"
#include "Components/ArrowComponent.h"
#include "Components/WidgetComponent.h"
#include "Misc/OutputDeviceDebug.h"
AMConstructableBuilding::AMConstructableBuilding()
{
PrimaryActorTick.bCanEverTick = true;
BaseBuildingMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Base Mesh"));
RootComponent = BaseBuildingMesh;
BaseBuildingMesh->SetCollisionResponseToChannel(TRACE_CHANNEL_ConstructedBuilding, ECR_Block);
BaseBuildingMesh->SetCollisionResponseToChannel(TRACE_CHANNEL_Weapon, ECR_Ignore);
BaseBuildingMesh->SetCollisionResponseToChannel(COLLISION_OBJECT_UIEnablingVolume, ECR_Overlap);
BaseBuildingMesh->OnComponentBeginOverlap.AddDynamic(this, &AMConstructableBuilding::HandleMeshComponentBeginOverlap);
BaseBuildingMesh->OnComponentEndOverlap.AddDynamic(this, &AMConstructableBuilding::HandleMeshComponentEndOverlap);
BaseBuildingMesh->SetGenerateOverlapEvents(true);
PlacementOverlapChecker = CreateDefaultSubobject<UBoxComponent>(TEXT("PlacementOverlapChecker"));
PlacementOverlapChecker->SetupAttachment(RootComponent);
PlacementOverlapChecker->SetCollisionResponseToAllChannels(ECR_Overlap);
PlacementOverlapChecker->SetCollisionResponseToChannel(TRACE_CHANNEL_Weapon, ECR_Ignore);
ArrowMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ArrowMesh"));
ArrowMesh->SetupAttachment(RootComponent);
ArrowMesh->SetHiddenInGame(false);
ArrowMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
InvalidActorsFilter.AddUnique(GetClass());
HealthComponent = CreateDefaultSubobject<UMHealthComponent>(TEXT("HealthComp"));
StatusIndicatorWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("Health Indicator"));
StatusIndicatorWidget->SetupAttachment(RootComponent);
StatusIndicatorWidget->SetHiddenInGame(true);
BuildingState = EBuildingState::UnderConstruction;
}
void AMConstructableBuilding::HandleMeshComponentEndOverlap(UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if(OtherComp->GetCollisionObjectType() == COLLISION_OBJECT_UIEnablingVolume)
{
StatusIndicatorWidget->SetHiddenInGame(true);
}
}
void AMConstructableBuilding::HandleMeshComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult)
{
if(OtherComp->GetCollisionObjectType() == COLLISION_OBJECT_UIEnablingVolume)
{
StatusIndicatorWidget->SetHiddenInGame(false);
}
}
void AMConstructableBuilding::SetupHealthIndicator()
{
UUserWidget* IndicatorWidget = StatusIndicatorWidget->GetWidget();
if(IndicatorWidget)
{
FObjectProperty* ObjProp = FindFProperty<FObjectProperty>(IndicatorWidget->GetClass(), TEXT("HealthComponent"));
if(ObjProp)
{
ObjProp->SetObjectPropertyValue_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"));
}
}
}
void AMConstructableBuilding::BeginPlay()
{
Super::BeginPlay();
DefaultMaterials = BaseBuildingMesh->GetMaterials();
if(bNetStartup)
SetBuildingState(EBuildingState::Constructed);
GetWorldTimerManager().SetTimerForNextTick(this, &AMConstructableBuilding::SetupHealthIndicator);
HealthComponent->Deactivate();
}
void AMConstructableBuilding::ConstructionCompleted()
{
SetBuildingState(EBuildingState::Constructed);
}
void AMConstructableBuilding::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AMConstructableBuilding::SetBuildingState(TEnumAsByte<EBuildingState> NewState)
{
// if(NewState == BuildingState)
// return;
const EBuildingState PreviousState = BuildingState;
BuildingState = NewState;
if(NewState != EBuildingState::Constructed)
{
CurrentBuildingStateMaterial = UMaterialInstanceDynamic::Create(BuildingDynamicStateMaterial, this);
//Set instance color param according to the building state
FLinearColor ColorValue;
switch(NewState)
{
case EBuildingState::Constructable: ColorValue = ConstructableColor; break;
case EBuildingState::UnConstructable: ColorValue = UnConstructableColor; break;
case EBuildingState::UnderConstruction: ColorValue = UnderConstructionColor; break;
default: ColorValue = FLinearColor(0, 0, 0); break;
}
CurrentBuildingStateMaterial->SetVectorParameterValue("Color", ColorValue);
for(int i = 0; i < DefaultMaterials.Num(); i++)
BaseBuildingMesh->SetMaterial(i, CurrentBuildingStateMaterial);
}
if(BuildingState == EBuildingState::Constructed)
{
for(int i = 0; i < DefaultMaterials.Num(); i++)
BaseBuildingMesh->SetMaterial(i, DefaultMaterials[i]);
BaseBuildingMesh->SetCollisionResponseToChannel(TRACE_CHANNEL_Weapon, ECR_Block);
HealthComponent->Activate();
ArrowMesh->SetHiddenInGame(true);
}
BuildingStateSet(NewState, PreviousState);
OnBuildingStateChanged.Broadcast(this, NewState, PreviousState);
}
void AMConstructableBuilding::StartBuildingConstruction(float TimeToConstruct)
{
GetWorldTimerManager().SetTimer(TimerHandle_UnderConstructionTimer, this, &AMConstructableBuilding::ConstructionCompleted, TimeToConstruct);
}
void AMConstructableBuilding::SetHighlighted_Implementation(bool Highlighted)
{
BaseBuildingMesh->SetRenderCustomDepth(Highlighted);
}
bool AMConstructableBuilding::IsAtValidLocation_Implementation()
{
bool PositionIsValid = true;
if(BaseBuildingMesh)
{
TArray<AActor*> OverlappingActors;
for(const TSubclassOf<AActor> FilteredActorClass : InvalidActorsFilter)
{
PlacementOverlapChecker->GetOverlappingActors(OverlappingActors, FilteredActorClass);
if(FilteredActorClass == GetClass())
{
// Check overlapping against ourselves
for(const AActor* OverlappingActor : OverlappingActors)
{
if(OverlappingActor != this)
{
PositionIsValid = false;
break;
}
}
}
else if(OverlappingActors.Num() != 0)
{
PositionIsValid = false;
}
if(!PositionIsValid)
break;
}
// We are not overlapping with any unwanted actors, now to check if we are overlapping against
// required actors
if(PositionIsValid)
{
for(const TSubclassOf<AActor> RequiredActorClass : RequiredOverlappingActorsFilter)
{
PlacementOverlapChecker->GetOverlappingActors(OverlappingActors, RequiredActorClass);
if(OverlappingActors.Num() == 0)
{
PositionIsValid = false;
break;
}
}
}
}
return PositionIsValid;
}