Files
ProjectEleri/Source/ProjectEleri/GameObjects/RemovableStaticMeshActor.cpp

201 lines
6.6 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "RemovableStaticMeshActor.h"
#include "Kismet/KismetMathLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "../Public/MyCharacter.h"
#include "Engine/StaticMeshActor.h"
#include "../System/Subsystem/ObjectPersistenceSubsystem.h"
#include "../System/MainBlueprintFunctionLibrary.h"
#include "../Components/MoveActorsComponent.h"
ARemovableStaticMeshActor::ARemovableStaticMeshActor()
{
PrimaryActorTick.bCanEverTick = true;
WidgetComponent = CreateDefaultSubobject<UInteractionWidgetComponent>(TEXT("WidgetComponent"));
WidgetComponent->SetupAttachment(RootComponent);
OverlapBoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("OverlapBoxComponent"));
OverlapBoxComponent->SetupAttachment(RootComponent);
// Detection only: the box never blocks anything, it only reports overlaps.
OverlapBoxComponent->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
OverlapBoxComponent->SetCollisionObjectType(OverlapBoxObjectType);
OverlapBoxComponent->SetCollisionResponseToAllChannels(ECR_Overlap);
OverlapBoxComponent->SetCollisionResponseToChannel(ECC_Visibility, ECR_Ignore);
OverlapBoxComponent->SetGenerateOverlapEvents(true);
OverlapBoxComponent->SetCanEverAffectNavigation(false);
}
void ARemovableStaticMeshActor::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);
UpdateOverlapBoxExtent();
}
void ARemovableStaticMeshActor::UpdateOverlapBoxExtent()
{
if (!OverlapBoxComponent)
{
return;
}
OverlapBoxComponent->SetCollisionObjectType(OverlapBoxObjectType);
UStaticMeshComponent* MeshComponent = GetStaticMeshComponent();
if (!MeshComponent || !MeshComponent->GetStaticMesh())
{
OverlapBoxComponent->SetBoxExtent(FVector::ZeroVector);
return;
}
// GetLocalBounds returns the mesh' bounding box in its own local space.
FVector BoundsMin, BoundsMax;
MeshComponent->GetLocalBounds(BoundsMin, BoundsMax);
OverlapBoxComponent->SetRelativeLocation((BoundsMin + BoundsMax) * 0.5f);
OverlapBoxComponent->SetBoxExtent(!BoxExtentOverride.IsNearlyZero()
? BoxExtentOverride
: (BoundsMax - BoundsMin) * 0.5f);
}
void ARemovableStaticMeshActor::BeginPlay()
{
Super::BeginPlay();
// Keep the detection box in sync with the mesh that is actually assigned at runtime.
UpdateOverlapBoxExtent();
PlayerRef = UGameplayStatics::GetActorOfClass(GetWorld(), AMyCharacter::StaticClass());
if (PlayerRef) {
MoveableComponent = PlayerRef->GetComponentByClass<UMoveActorsComponent>();
}
DistanceFromActor *= GetActorScale().X;
MeshMaterials = GetStaticMeshComponent()->GetMaterials();
CurrentMemorizedTransform = GetActorTransform();
}
void ARemovableStaticMeshActor::ToggleInteractableUI_Implementation(bool bActive)
{
if (bActive && !IInteractableActorInterface::Execute_IsInteractable(this))
{
return;
}
IInteractableActorInterface::ToggleInteractableUI_Implementation(bActive);
if (WidgetComponent)
{
WidgetComponent->ToggleWidget(bActive);
}
}
bool ARemovableStaticMeshActor::IsInteractable_Implementation() const
{
return true;
}
void ARemovableStaticMeshActor::Initialize(UStaticMesh* StaticMesh, UItemDataAsset* InItemDataAsset)
{
GetStaticMeshComponent()->SetStaticMesh(StaticMesh);
GetStaticMeshComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
MeshMaterials = GetStaticMeshComponent()->GetMaterials();
ItemDataAsset = InItemDataAsset;
DataAssetId = ItemDataAsset->GetPrimaryAssetId();
}
void ARemovableStaticMeshActor::BindToItem(UInventoryComponent* InInventory)
{
bFromInventory = true;
}
void ARemovableStaticMeshActor::PickUp()
{
bPlaced = false;
if (!bPlaced)
{
if (AStaticMeshActor* StaticMeshActor = Cast<AStaticMeshActor>(this))
{
StaticMeshActor->SetMobility(EComponentMobility::Movable);
}
CurrentMemorizedTransform = GetActorTransform();
OnPickup.Broadcast();
}
}
void ARemovableStaticMeshActor::Place(bool ReturnToOldLocation, bool bForce)
{
bPlaced = true;
if (bPlaced)
{
//Reset this because we've placed the item in the world
bFromInventory = false;
if (ReturnToOldLocation)
{
SetActorTransform(CurrentMemorizedTransform);
}
if (AStaticMeshActor* StaticMeshActor = Cast<AStaticMeshActor>(this))
{
StaticMeshActor->SetMobility(EComponentMobility::Static);
}
if (UGameInstance* GI = UGameplayStatics::GetGameInstance(GetWorld()))
{
if (UObjectPersistenceSubsystem* ObjectPersistenceSubsystem = GI->GetSubsystem<UObjectPersistenceSubsystem>())
{
ObjectPersistenceSubsystem->PlacebleActorMoved(this);
}
}
CurrentMemorizedTransform = GetActorTransform();
GetStaticMeshComponent()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
OnPlaced.Broadcast();
}
}
void ARemovableStaticMeshActor::Rotate(bool bPositive)
{
FRotator CurrentRotation = this->GetActorRotation();
CurrentRotation.Yaw += bPositive ? 90.f : -90.f;
this->SetActorRotation(CurrentRotation);
}
void ARemovableStaticMeshActor::ReportGridFootprint()
{
// The base cell size is a property of the Move Actors component, which only exists at runtime. While
// editing a placed actor the component is missing, so the class default is used, which is the value
// the placement uses unless the level overrides it.
const double BaseGridSnapSize = MoveableComponent ? MoveableComponent->GridSnapSize : UMoveActorsComponent::DefaultGridSnapSize;
const double Pitch = UMoveActorsComponent::GetGridPitch(this, BaseGridSnapSize);
if (Pitch <= 0.0)
{
UE_LOG(LogTemp, Warning, TEXT("%s: no grid pitch to report against. Set GridSnapSize on the Move Actors component."), *GetName());
return;
}
const UStaticMeshComponent* MeshComponent = GetStaticMeshComponent();
if (!MeshComponent || !MeshComponent->GetStaticMesh())
{
UE_LOG(LogTemp, Warning, TEXT("%s: no static mesh assigned."), *GetName());
return;
}
const FBoxSphereBounds MeshBounds = MeshComponent->CalcBounds(MeshComponent->GetComponentTransform());
const FVector Size = MeshBounds.BoxExtent * 2.0;
// The same cell rule that the placement uses, so the reported margin is the margin that the object
// will actually keep on the grid.
const double CellsX = UMoveActorsComponent::GetGridCellCount(Size.X, Pitch);
const double CellsY = UMoveActorsComponent::GetGridCellCount(Size.Y, Pitch);
const double FillScale = FMath::Max((CellsX * Pitch) / FMath::Max(Size.X, 1.0), (CellsY * Pitch) / FMath::Max(Size.Y, 1.0));
UE_LOG(LogTemp, Display, TEXT("%s: mesh %.1f x %.1f on a %.1f grid (%d x %.1f base) -> %.0f x %.0f cells (margin %.1f x %.1f, fill scale %.2f)"),
*GetName(), Size.X, Size.Y, Pitch, GetGridSizeMultiplier(), BaseGridSnapSize, CellsX, CellsY,
CellsX * Pitch - Size.X, CellsY * Pitch - Size.Y, FillScale);
}