LifePlay-Revival/Source/LifePlay/LPSecondScreenSubsystem.cpp

113 lines
3.3 KiB
C++
Raw Normal View History

// Portage UE 5.5 - voir LPSecondScreenSubsystem.h
#include "LPSecondScreenSubsystem.h"
#include "Components/CapsuleComponent.h"
#include "Components/SceneCaptureComponent2D.h"
#include "Components/SkeletalMeshComponent.h"
#include "Engine/GameInstance.h"
#include "Engine/SceneCapture2D.h"
#include "Engine/World.h"
#include "EngineUtils.h"
#include "GameFramework/Character.h"
#include "LifePlay.h"
#include "UObject/UnrealType.h"
namespace
{
// Cadrage du visage : distance camera-tete (cm) et champ horizontal (degres).
constexpr float FaceDistance = 80.f;
constexpr float FaceFOV = 30.f;
const FName CaptureActorName(TEXT("SecondScreen"));
const FName PersonPropertyName(TEXT("SecondScreenPerson"));
const FName HeadSocket(TEXT("head"));
/** Position de la tete : os "head" du premier maillage qui le porte, sinon haut de la capsule. */
FVector HeadLocation(const AActor* Person)
{
TInlineComponentArray<USkeletalMeshComponent*> Meshes(Person);
for (const USkeletalMeshComponent* Mesh : Meshes)
{
if (Mesh && Mesh->GetSkinnedAsset() && Mesh->DoesSocketExist(HeadSocket))
{
return Mesh->GetSocketLocation(HeadSocket);
}
}
if (const ACharacter* Character = Cast<ACharacter>(Person))
{
if (const UCapsuleComponent* Capsule = Character->GetCapsuleComponent())
{
return Capsule->GetComponentLocation() + FVector(0.f, 0.f, Capsule->GetScaledCapsuleHalfHeight() * 0.8f);
}
}
return Person->GetActorLocation();
}
}
void ULPSecondScreenSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
TickHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateUObject(this, &ULPSecondScreenSubsystem::Tick));
}
void ULPSecondScreenSubsystem::Deinitialize()
{
FTSTicker::GetCoreTicker().RemoveTicker(TickHandle);
Super::Deinitialize();
}
bool ULPSecondScreenSubsystem::Tick(float DeltaTime)
{
const UGameInstance* GI = GetGameInstance();
UWorld* World = GI ? GI->GetWorld() : nullptr;
if (!World)
{
return true;
}
// La camera est recherchee une fois par monde (par nom d'objet : l'etiquette n'existe pas en Shipping).
if (CaptureWorld.Get() != World)
{
CaptureWorld = World;
Capture.Reset();
for (TActorIterator<ASceneCapture2D> It(World); It; ++It)
{
if (It->GetFName() == CaptureActorName)
{
Capture = *It;
break;
}
}
}
ASceneCapture2D* CaptureActor = Capture.Get();
USceneCaptureComponent2D* CaptureComp = CaptureActor ? CaptureActor->GetCaptureComponent2D() : nullptr;
if (!CaptureComp)
{
return true;
}
const FObjectPropertyBase* Prop = CastField<FObjectPropertyBase>(GI->GetClass()->FindPropertyByName(PersonPropertyName));
const AActor* Person = Prop ? Cast<AActor>(Prop->GetObjectPropertyValue_InContainer(GI)) : nullptr;
if (!IsValid(Person))
{
return true;
}
const FVector Head = HeadLocation(Person);
FVector Forward = Person->GetActorForwardVector();
Forward.Z = 0.f;
if (!Forward.Normalize())
{
Forward = FVector::ForwardVector;
}
const FVector CameraLocation = Head + Forward * FaceDistance;
if (CaptureComp->Mobility != EComponentMobility::Movable)
{
// Composant pose dans la carte : un composant statique refuse d'etre deplace en jeu.
CaptureComp->SetMobility(EComponentMobility::Movable);
}
CaptureComp->SetWorldLocationAndRotation(CameraLocation, (Head - CameraLocation).Rotation());
CaptureComp->FOVAngle = FaceFOV;
return true;
}