Files
MosisUnreal/Plugins/MosisSDK/Source/MosisSDK/Private/MosisPhoneActor.cpp

147 lines
4.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MosisPhoneActor.h"
#include "Components/StaticMeshComponent.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Engine/StaticMesh.h"
#include "UObject/ConstructorHelpers.h"
DEFINE_LOG_CATEGORY_STATIC(LogMosisPhoneActor, Log, All);
AMosisPhoneActor::AMosisPhoneActor()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bStartWithTickEnabled = true;
// Create phone mesh component
PhoneMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PhoneMesh"));
RootComponent = PhoneMesh;
// Load the default plane mesh
static ConstructorHelpers::FObjectFinder<UStaticMesh> PlaneMeshFinder(
TEXT("/Engine/BasicShapes/Plane.Plane"));
if (PlaneMeshFinder.Succeeded())
{
PhoneMesh->SetStaticMesh(PlaneMeshFinder.Object);
}
// Load the phone screen material
static ConstructorHelpers::FObjectFinder<UMaterialInterface> PhoneMaterialFinder(
TEXT("/Game/Mosis/Materials/M_PhoneScreen.M_PhoneScreen"));
if (PhoneMaterialFinder.Succeeded())
{
BaseMaterial = PhoneMaterialFinder.Object;
}
// Create phone component
PhoneComponent = CreateDefaultSubobject<UMosisPhoneComponent>(TEXT("PhoneComponent"));
}
void AMosisPhoneActor::BeginPlay()
{
Super::BeginPlay();
UE_LOG(LogMosisPhoneActor, Log, TEXT("BeginPlay"));
// Scale mesh to match phone screen size
// The default plane is 100x100 units, so scale accordingly
if (PhoneMesh)
{
float ScaleX = ScreenSizeWorld.X / 100.0f;
float ScaleY = ScreenSizeWorld.Y / 100.0f;
PhoneMesh->SetRelativeScale3D(FVector(ScaleX, ScaleY, 1.0f));
// Update screen bounds based on scaled size
float HalfWidth = ScreenSizeWorld.X / 2.0f;
float HalfHeight = ScreenSizeWorld.Y / 2.0f;
ScreenBoundsLocal = FVector4(-HalfWidth, -HalfHeight, HalfWidth, HalfHeight);
}
// Create dynamic material for the screen
if (PhoneMesh)
{
UMaterialInterface* MaterialToUse = BaseMaterial;
// If no base material set, use the mesh's existing material
if (!MaterialToUse)
{
MaterialToUse = PhoneMesh->GetMaterial(0);
}
if (MaterialToUse)
{
ScreenMaterial = UMaterialInstanceDynamic::Create(MaterialToUse, this);
PhoneMesh->SetMaterial(0, ScreenMaterial);
// Set it on the phone component
if (PhoneComponent)
{
PhoneComponent->PhoneMaterial = ScreenMaterial;
}
UE_LOG(LogMosisPhoneActor, Log, TEXT("BeginPlay: Created dynamic material"));
}
else
{
UE_LOG(LogMosisPhoneActor, Warning, TEXT("BeginPlay: No base material available"));
}
}
}
void AMosisPhoneActor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
// Update material texture if phone component has a new texture
if (ScreenMaterial && PhoneComponent)
{
UTexture* PhoneTexture = PhoneComponent->GetPhoneTexture();
if (PhoneTexture)
{
ScreenMaterial->SetTextureParameterValue(PhoneComponent->TextureParameterName, PhoneTexture);
}
}
}
bool AMosisPhoneActor::SendTouchAtWorldLocation(FVector HitLocation, EMosisTouchType TouchType)
{
FVector2D UV;
if (!WorldToPhoneUV(HitLocation, UV))
{
return false;
}
if (PhoneComponent)
{
PhoneComponent->SendTouch(UV, TouchType);
return true;
}
return false;
}
bool AMosisPhoneActor::WorldToPhoneUV(FVector WorldLocation, FVector2D& OutUV) const
{
// Convert world location to local space
FVector LocalLocation = GetActorTransform().InverseTransformPosition(WorldLocation);
// Get bounds
float MinX = ScreenBoundsLocal.X;
float MinY = ScreenBoundsLocal.Y;
float MaxX = ScreenBoundsLocal.Z;
float MaxY = ScreenBoundsLocal.W;
// Check if within bounds
if (LocalLocation.X < MinX || LocalLocation.X > MaxX ||
LocalLocation.Y < MinY || LocalLocation.Y > MaxY)
{
return false;
}
// Calculate UV (0-1 range)
OutUV.X = (LocalLocation.X - MinX) / (MaxX - MinX);
OutUV.Y = (LocalLocation.Y - MinY) / (MaxY - MinY);
return true;
}