(Feat) Add MainMenu

This commit is contained in:
2026-07-28 14:10:17 +02:00
parent ed7c7fd991
commit 175bef228c
33 changed files with 2331 additions and 12 deletions
+99 -3
View File
@@ -17,6 +17,7 @@
#include "ItemDataAsset.h"
#include "PickupItem.h"
#include "SurvivalStatsComponent.h"
#include "SurvivalUserSettings.h"
// Sets default values
AFpsPlayer::AFpsPlayer()
@@ -72,6 +73,21 @@ void AFpsPlayer::BeginPlay()
SurvivalStats->OnDied.AddDynamic(this, &AFpsPlayer::HandleDeath);
// Les reglages d'abord : le pawn est recree a chaque respawn et repart des
// valeurs de son CDO, il doit donc les relire lui-meme. L'abonnement couvre
// ensuite les changements faits en cours de partie depuis le menu de pause.
ApplyUserSettings();
if (USurvivalUserSettings* Settings = USurvivalUserSettings::Get())
{
Settings->OnSurvivalSettingsApplied.AddDynamic(this, &AFpsPlayer::ApplyUserSettings);
}
// Le FOV est interpole chaque frame vers BaseFOV : sans ce calage initial on
// verrait la camera s'ouvrir lentement jusqu'a la valeur reglee a chaque
// apparition.
FirstPersonCamera->SetFieldOfView(BaseFOV);
// On enregistre le mapping context aupres du sous-systeme Enhanced Input
// du joueur local. Sans ca, aucune touche n'est lue.
if (const APlayerController* PlayerController = Cast<APlayerController>(GetController()))
@@ -91,6 +107,45 @@ void AFpsPlayer::BeginPlay()
}
}
void AFpsPlayer::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
// Le singleton de reglages survit au monde : sans ce desabonnement, chaque
// cadavre laisserait derriere lui un abonne mort de plus.
if (USurvivalUserSettings* Settings = USurvivalUserSettings::Get())
{
Settings->OnSurvivalSettingsApplied.RemoveDynamic(this, &AFpsPlayer::ApplyUserSettings);
}
Super::EndPlay(EndPlayReason);
}
void AFpsPlayer::ApplyUserSettings()
{
USurvivalUserSettings* Settings = USurvivalUserSettings::Get();
if (!Settings)
{
// Pas de reglages : on garde les valeurs du Blueprint. Le jeu reste
// jouable, il n'est simplement pas configurable.
UE_LOG(LogTemp, Warning, TEXT("AFpsPlayer : USurvivalUserSettings introuvable, les valeurs du Blueprint sont conservees."));
return;
}
LookSensitivityX = Settings->GetLookMultiplierX();
LookSensitivityY = Settings->GetLookMultiplierY();
bInvertLookY = Settings->GetInvertLookY();
BaseFOV = Settings->GetFieldOfView();
CameraShakeMultiplier = Settings->GetCameraShakeMultiplier();
bSprintToggleMode = Settings->GetSprintToggle();
bCrouchToggleMode = Settings->GetCrouchToggle();
// Repasser en maintien alors que la touche n'est plus enfoncee laisserait le
// personnage bloque en sprint : on repart d'un etat propre.
if (!bSprintToggleMode && bIsSprinting)
{
StopSprint();
}
}
// Called every frame
void AFpsPlayer::Tick(float DeltaTime)
{
@@ -193,9 +248,12 @@ void AFpsPlayer::UpdateCameraEffects(float DeltaTime)
void AFpsPlayer::AddCameraPunch(float Strength)
{
// Le reglage s'applique ICI et pas sur chaque source d'impact : tout ce qui
// secoue la camera passe par cette porte, y compris les explosions et les
// reculs d'arme a venir. A 0, la camera ne bouge plus du tout.
// Mis en attente plutot qu'applique directement : c'est UpdateCameraEffects
// qui l'injecte progressivement dans le ressort.
PendingPunch += Strength;
PendingPunch += Strength * CameraShakeMultiplier;
}
void AFpsPlayer::Landed(const FHitResult& Hit)
@@ -263,14 +321,17 @@ void AFpsPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent
if (SprintAction)
{
// Le mode maintien / bascule se decide dans les handlers et non ici :
// rebrancher les bindings a chaud demanderait de reconstruire l'input
// component a chaque changement de reglage.
Input->BindAction(SprintAction, ETriggerEvent::Started, this, &AFpsPlayer::StartSprint);
Input->BindAction(SprintAction, ETriggerEvent::Completed, this, &AFpsPlayer::StopSprint);
Input->BindAction(SprintAction, ETriggerEvent::Completed, this, &AFpsPlayer::HandleSprintReleased);
}
if (CrouchAction)
{
Input->BindAction(CrouchAction, ETriggerEvent::Started, this, &AFpsPlayer::StartCrouch);
Input->BindAction(CrouchAction, ETriggerEvent::Completed, this, &AFpsPlayer::StopCrouch);
Input->BindAction(CrouchAction, ETriggerEvent::Completed, this, &AFpsPlayer::HandleCrouchReleased);
}
if (InteractAction)
@@ -330,6 +391,13 @@ void AFpsPlayer::StartSprint()
return;
}
// En mode bascule, la meme touche coupe le sprint.
if (bSprintToggleMode && bIsSprinting)
{
StopSprint();
return;
}
bIsSprinting = true;
GetCharacterMovement()->MaxWalkSpeed = SprintSpeed;
}
@@ -340,6 +408,17 @@ void AFpsPlayer::StopSprint()
GetCharacterMovement()->MaxWalkSpeed = WalkSpeed;
}
void AFpsPlayer::HandleSprintReleased()
{
// En bascule, relacher la touche ne doit rien faire.
if (bSprintToggleMode)
{
return;
}
StopSprint();
}
void AFpsPlayer::UseSelectedItem()
{
const FInventorySlot Selected = InventoryComponent->GetSelectedSlot();
@@ -514,10 +593,27 @@ void AFpsPlayer::ClearTransientInputStates()
void AFpsPlayer::StartCrouch()
{
// En mode bascule, la meme touche releve le personnage.
if (bCrouchToggleMode && bIsCrouched)
{
StopCrouch();
return;
}
StopSprint();
Crouch();
}
void AFpsPlayer::HandleCrouchReleased()
{
if (bCrouchToggleMode)
{
return;
}
StopCrouch();
}
void AFpsPlayer::StopCrouch()
{
// UnCrouch() echoue silencieusement s'il y a un plafond : le perso