201 lines
5.1 KiB
C++
201 lines
5.1 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
#include "ScreenFadeComponent.h"
|
|
|
|
#include "Blueprint/UserWidget.h"
|
|
#include "Camera/PlayerCameraManager.h"
|
|
#include "GameFramework/PlayerController.h"
|
|
|
|
namespace
|
|
{
|
|
// Le voile doit passer devant absolument tout, y compris les widgets qu'on
|
|
// ajouterait plus tard sans y penser.
|
|
constexpr int32 ZOrderFade = 1000;
|
|
}
|
|
|
|
UScreenFadeComponent::UScreenFadeComponent()
|
|
{
|
|
// Le composant ne tourne QUE pendant un fondu : on allume le tick dans
|
|
// FadeIn/FadeOut et on l'eteint des la cible atteinte. Ticker en permanence
|
|
// pour une valeur qui ne bouge qu'une seconde par mort serait du gaspillage.
|
|
PrimaryComponentTick.bCanEverTick = true;
|
|
PrimaryComponentTick.bStartWithTickEnabled = false;
|
|
|
|
// Le fondu doit continuer d'avancer quand le monde est fige : c'est le seul
|
|
// moyen de partir au noir depuis le menu de pause. Sans ce drapeau, l'ecran
|
|
// resterait bloque a mi-chemin et le delegue ne se declencherait jamais.
|
|
PrimaryComponentTick.bTickEvenWhenPaused = true;
|
|
}
|
|
|
|
void UScreenFadeComponent::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
|
|
// Cree des maintenant pour que le voile puisse couvrir des la premiere
|
|
// frame, avant meme que le reste du HUD existe.
|
|
EnsureWidget();
|
|
}
|
|
|
|
APlayerController* UScreenFadeComponent::GetOwningController() const
|
|
{
|
|
return Cast<APlayerController>(GetOwner());
|
|
}
|
|
|
|
void UScreenFadeComponent::EnsureWidget()
|
|
{
|
|
if (FadeWidget)
|
|
{
|
|
return;
|
|
}
|
|
|
|
APlayerController* Controller = GetOwningController();
|
|
if (!Controller)
|
|
{
|
|
UE_LOG(LogTemp, Error, TEXT("UScreenFadeComponent : doit etre pose sur un PlayerController, pas sur %s."),
|
|
*GetNameSafe(GetOwner()));
|
|
return;
|
|
}
|
|
|
|
// Un widget n'existe que sur la machine du joueur local : inutile et
|
|
// incorrect d'en creer un sur un serveur dedie.
|
|
// ATTENTION : chez un client, ce test est FAUX au BeginPlay du controller --
|
|
// son ULocalPlayer ne lui est attache qu'ensuite, dans SetPlayer(). Un
|
|
// SnapToBlack() fait trop tot noircit donc un voile inexistant, en silence.
|
|
if (!Controller->IsLocalController())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!FadeWidgetClass)
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("UScreenFadeComponent : FadeWidgetClass n'est pas assignee, aucun fondu ne s'affichera."));
|
|
return;
|
|
}
|
|
|
|
FadeWidget = CreateWidget<UUserWidget>(Controller, FadeWidgetClass);
|
|
if (FadeWidget)
|
|
{
|
|
FadeWidget->AddToViewport(ZOrderFade);
|
|
SetCoverage(1.f - Alpha);
|
|
}
|
|
}
|
|
|
|
void UScreenFadeComponent::SetCoverage(float Coverage)
|
|
{
|
|
if (!FadeWidget)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const float Clamped = FMath::Clamp(Coverage, 0.f, 1.f);
|
|
FadeWidget->SetRenderOpacity(Clamped);
|
|
|
|
// HitTestInvisible et jamais Visible : un voile qui capture la souris
|
|
// bloquerait les boutons du menu meme completement transparent.
|
|
FadeWidget->SetVisibility(FMath::IsNearlyZero(Clamped)
|
|
? ESlateVisibility::Collapsed
|
|
: ESlateVisibility::HitTestInvisible);
|
|
}
|
|
|
|
void UScreenFadeComponent::FadeIn(float Duration)
|
|
{
|
|
EnsureWidget();
|
|
|
|
if (APlayerController* Controller = GetOwningController())
|
|
{
|
|
if (Controller->PlayerCameraManager)
|
|
{
|
|
Controller->PlayerCameraManager->StartCameraFade(
|
|
/*FromAlpha=*/1.f, /*ToAlpha=*/0.f,
|
|
Duration, FadeColor,
|
|
/*bShouldFadeAudio=*/true);
|
|
}
|
|
}
|
|
|
|
CurrentDuration = FMath::Max(Duration, 0.01f);
|
|
Alpha = 0.f;
|
|
Target = 1.f;
|
|
bFading = true;
|
|
SetCoverage(1.f);
|
|
SetComponentTickEnabled(true);
|
|
}
|
|
|
|
void UScreenFadeComponent::FadeOut(float Duration)
|
|
{
|
|
EnsureWidget();
|
|
|
|
if (APlayerController* Controller = GetOwningController())
|
|
{
|
|
if (Controller->PlayerCameraManager)
|
|
{
|
|
// bHoldWhenFinished : l'ecran reste noir au lieu de revenir tout seul.
|
|
Controller->PlayerCameraManager->StartCameraFade(
|
|
/*FromAlpha=*/0.f, /*ToAlpha=*/1.f,
|
|
Duration, FadeColor,
|
|
/*bShouldFadeAudio=*/true, /*bHoldWhenFinished=*/true);
|
|
}
|
|
}
|
|
|
|
CurrentDuration = FMath::Max(Duration, 0.01f);
|
|
Target = 0.f;
|
|
bFading = true;
|
|
SetComponentTickEnabled(true);
|
|
}
|
|
|
|
void UScreenFadeComponent::SnapToBlack()
|
|
{
|
|
EnsureWidget();
|
|
|
|
if (APlayerController* Controller = GetOwningController())
|
|
{
|
|
if (Controller->PlayerCameraManager)
|
|
{
|
|
Controller->PlayerCameraManager->SetManualCameraFade(1.f, FadeColor, /*bFadeAudio=*/true);
|
|
}
|
|
}
|
|
|
|
Alpha = 0.f;
|
|
Target = 0.f;
|
|
bFading = false;
|
|
SetCoverage(1.f);
|
|
SetComponentTickEnabled(false);
|
|
}
|
|
|
|
void UScreenFadeComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
|
{
|
|
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
|
|
|
if (!bFading)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const float Step = DeltaTime / CurrentDuration;
|
|
Alpha = FMath::Clamp(Alpha + Step * FMath::Sign(Target - Alpha), 0.f, 1.f);
|
|
|
|
// Alpha va de 0 (ecran couvert) a 1 (jeu visible) : le voile suit l'inverse.
|
|
SetCoverage(1.f - Alpha);
|
|
|
|
if (FMath::IsNearlyEqual(Alpha, Target))
|
|
{
|
|
bFading = false;
|
|
|
|
// On eteint le tick AVANT de prevenir : un abonne qui relance un fondu
|
|
// dans son handler doit pouvoir le rallumer.
|
|
SetComponentTickEnabled(false);
|
|
OnFadeFinished.Broadcast();
|
|
}
|
|
}
|
|
|
|
void UScreenFadeComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
|
{
|
|
if (FadeWidget)
|
|
{
|
|
FadeWidget->RemoveFromParent();
|
|
FadeWidget = nullptr;
|
|
}
|
|
|
|
Super::EndPlay(EndPlayReason);
|
|
}
|