// Fill out your copyright notice in the Description page of Project Settings. #include "CharacterPreviewActor.h" #include "Camera/CameraComponent.h" #include "CharacterAppearanceComponent.h" #include "Components/SkeletalMeshComponent.h" ACharacterPreviewActor::ACharacterPreviewActor() { // Allume par SetFraming et eteint des que la camera est arrivee. Un // mannequin immobile dans un menu n'a aucune raison de couter une frame. PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bStartWithTickEnabled = false; USceneComponent* SceneRoot = CreateDefaultSubobject(TEXT("Root")); SetRootComponent(SceneRoot); TurntablePivot = CreateDefaultSubobject(TEXT("TurntablePivot")); TurntablePivot->SetupAttachment(SceneRoot); BodyMesh = CreateDefaultSubobject(TEXT("BodyMesh")); BodyMesh->SetupAttachment(TurntablePivot); // Aucune collision : c'est un decor de menu, rien ne doit le heurter ni le // tracer. BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision); // Les reperes de cadrage sont filles de la RACINE et pas du pivot : ils ne // doivent surtout pas tourner avec le personnage, sinon la camera suivrait // le clic-glisser au lieu de le montrer. FullBodyViewSpot = CreateDefaultSubobject(TEXT("FullBodyViewSpot")); FullBodyViewSpot->SetupAttachment(SceneRoot); FullBodyViewSpot->SetRelativeLocation(FVector(260.f, 60.f, 95.f)); FullBodyViewSpot->SetRelativeRotation(FRotator(0.f, 180.f, 0.f)); FaceViewSpot = CreateDefaultSubobject(TEXT("FaceViewSpot")); FaceViewSpot->SetupAttachment(SceneRoot); FaceViewSpot->SetRelativeLocation(FVector(90.f, 25.f, 165.f)); FaceViewSpot->SetRelativeRotation(FRotator(0.f, 180.f, 0.f)); PreviewCamera = CreateDefaultSubobject(TEXT("PreviewCamera")); PreviewCamera->SetupAttachment(SceneRoot); AppearanceComponent = CreateDefaultSubobject(TEXT("AppearanceComponent")); } void ACharacterPreviewActor::BeginPlay() { Super::BeginPlay(); // Le composant cherche le mesh d'un ACharacter par defaut ; ici il n'y en a // pas, on lui designe le notre. if (AppearanceComponent) { AppearanceComponent->SetTargetMesh(BodyMesh); } // Pose la camera sur le cadrage de depart sans interpolation : glisser // depuis l'origine de l'acteur au premier affichage montrerait un travelling // que personne n'a demande. if (const USceneComponent* Spot = GetSpotForFraming(CurrentFraming)) { PreviewCamera->SetRelativeLocationAndRotation(Spot->GetRelativeLocation(), Spot->GetRelativeRotation()); } } void ACharacterPreviewActor::Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); UpdateFramingInterpolation(DeltaSeconds); } void ACharacterPreviewActor::ApplyAppearance(const FCharacterAppearance& InAppearance) { if (AppearanceComponent) { AppearanceComponent->ApplyAppearance(InAppearance); } } void ACharacterPreviewActor::SetFraming(ECharacterPreviewFraming NewFraming) { if (CurrentFraming == NewFraming) { return; } CurrentFraming = NewFraming; SetActorTickEnabled(true); } void ACharacterPreviewActor::AddPreviewYaw(float DeltaDegrees) { TurntableYaw = FRotator::NormalizeAxis(TurntableYaw + DeltaDegrees); if (TurntablePivot) { TurntablePivot->SetRelativeRotation(FRotator(0.f, TurntableYaw, 0.f)); } } void ACharacterPreviewActor::ResetPreviewYaw() { TurntableYaw = 0.f; if (TurntablePivot) { TurntablePivot->SetRelativeRotation(FRotator::ZeroRotator); } } USceneComponent* ACharacterPreviewActor::GetSpotForFraming(ECharacterPreviewFraming InFraming) const { return (InFraming == ECharacterPreviewFraming::Face) ? FaceViewSpot : FullBodyViewSpot; } void ACharacterPreviewActor::UpdateFramingInterpolation(float DeltaSeconds) { const USceneComponent* Spot = GetSpotForFraming(CurrentFraming); if (!Spot || !PreviewCamera) { SetActorTickEnabled(false); return; } const FVector TargetLocation = Spot->GetRelativeLocation(); const FRotator TargetRotation = Spot->GetRelativeRotation(); const FVector NewLocation = FMath::VInterpTo( PreviewCamera->GetRelativeLocation(), TargetLocation, DeltaSeconds, FramingInterpSpeed); const FRotator NewRotation = FMath::RInterpTo( PreviewCamera->GetRelativeRotation(), TargetRotation, DeltaSeconds, FramingInterpSpeed); PreviewCamera->SetRelativeLocationAndRotation(NewLocation, NewRotation); // Un interpolateur exponentiel n'atteint jamais sa cible exactement : sans // ce seuil, le Tick ne s'eteindrait plus jamais. On termine le dernier // millimetre d'un coup, il ne se voit pas. const bool bLocationReached = NewLocation.Equals(TargetLocation, 0.5f); const bool bRotationReached = NewRotation.Equals(TargetRotation, 0.5f); if (bLocationReached && bRotationReached) { PreviewCamera->SetRelativeLocationAndRotation(TargetLocation, TargetRotation); SetActorTickEnabled(false); } }