201 lines
6.6 KiB
C++
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);
|
|
}
|
|
|