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.
215 lines
7.0 KiB
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;
|
|
}
|
|
|
|
|