// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/PlayerController.h" #include "MainMenuPlayerController.generated.h" class AMenuCameraSpot; class UConfirmDialogWidget; class UMainMenuWidget; class UScreenFadeComponent; class USettingsMenuWidget; /** * Ce qu'on fait une fois l'ecran devenu noir. * * Quitter n'y figure pas : la sortie est seche, sans fondu, une fois la * confirmation obtenue. */ enum class EMenuPendingAction : uint8 { None, /** * Le fondu part AVANT la creation de la session, qui est asynchrone. La map * n'est donc chargee qu'a la reponse du service en ligne -- ou tout de suite * si celui-ci refuse, puisqu'un echec reseau ne doit pas empecher de jouer. */ StartGame }; /** * Controller du menu principal. Il ne possede aucun pawn : il pose simplement * sa vue sur une AMenuCameraSpot tiree au hasard et affiche le menu par-dessus. * * Comme dans le jeu, l'UI vit sur le controller et pas sur un acteur du monde. */ UCLASS() class SURVIVAL_PROJET_API AMainMenuPlayerController : public APlayerController { GENERATED_BODY() public: AMainMenuPlayerController(); /** * Fondu au noir, creation de la session, puis ouverture de la map en * serveur d'ecoute. * * Il n'existe qu'UN seul bouton pour lancer une partie : toute partie est * une partie en ligne, meme jouee seul. Distinguer "solo" et "heberger" * obligerait le joueur a decider avant de savoir si un ami se connectera, * et surtout a relancer sa partie pour changer d'avis. * * On ne rejoint jamais depuis ce menu : l'arrivee se fait uniquement par * invitation Steam, geree par USessionSubsystem quelle que soit la map * affichee a cet instant. */ UFUNCTION(BlueprintCallable, Category = "Menu") void StartGame(); /** Ouvre la demande de confirmation. Ne quitte rien par elle-meme. */ UFUNCTION(BlueprintCallable, Category = "Menu") void QuitGame(); /** Ouvre l'ecran de reglages par-dessus le menu. */ UFUNCTION(BlueprintCallable, Category = "Menu") void OpenSettings(); protected: virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; /** * Ta map de jeu. * * TSoftObjectPtr et non une reference dure : une reference dure ferait * charger la map de jeu EN MEME TEMPS que le menu, alors qu'on ne la veut * qu'au clic sur Jouer. C'est l'equivalent d'une Addressable en Unity, par * opposition a un champ public qui tire tout l'asset avec lui. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Menu") TSoftObjectPtr GameLevel; /** Ton WBP_MainMenu. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Menu") TSubclassOf MainMenuClass; /** * Ton WBP_ConfirmDialog. Si tu le laisses vide, le bouton Quitter ferme le * jeu directement -- pratique pour tester, mais laisse-le assigne. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Menu") TSubclassOf QuitDialogClass; /** La question posee avant de fermer le jeu. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Menu") FText QuitDialogMessage; /** Ton WBP_Settings, exactement le meme que celui du menu de pause. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Menu") TSubclassOf SettingsMenuClass; /** Fondu d'arrivee sur le menu, au lancement du jeu. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Menu", meta = (ClampMin = "0.1")) float OpeningFadeDuration = 1.5f; /** Fondu de depart, quand on quitte le menu pour la partie. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Menu", meta = (ClampMin = "0.1")) float LeaveFadeDuration = 1.f; /** Le fondu, partage avec AFpsPlayerController. Assigne-lui ton WBP_Fade. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Menu") TObjectPtr ScreenFade; UPROPERTY(Transient, BlueprintReadOnly, Category = "Menu") TObjectPtr MainMenu; UPROPERTY(Transient, BlueprintReadOnly, Category = "Menu") TObjectPtr QuitDialog; UPROPERTY(Transient, BlueprintReadOnly, Category = "Menu") TObjectPtr SettingsMenu; private: /** Tire un angle de vue au hasard, en evitant celui du dernier passage. */ AMenuCameraSpot* PickCameraSpot(); /** L'eclaircissement lui-meme, apres la chauffe du decor. */ void StartOpeningFade(); /** Le fondu vient de se terminer : on execute l'action mise de cote. */ UFUNCTION() void HandleFadeFinished(); /** Oui : on ferme le jeu, immediatement. */ UFUNCTION() void HandleQuitConfirmed(); /** Non : on referme la boite et on rend la main au menu. */ UFUNCTION() void HandleQuitCancelled(); /** L'ecran de reglages demande a se fermer : on rend la main au menu. */ UFUNCTION() void HandleSettingsCloseRequested(); /** * La session n'a pas pu etre creee -- Steam eteint, hors ligne, service en * panne. On charge la map QUAND MEME. * * C'est un choix delibere : un joueur qui clique Jouer veut jouer. Le rendre * a son menu avec un message d'erreur reseau alors que rien ne l'empeche de * jouer seul serait une punition pour une panne qui n'est pas la sienne. Il * perd seulement la possibilite d'inviter, et le bouton Inviter le dira. */ UFUNCTION() void HandleHostFailed(FText Reason); /** * Echec de connexion sur invitation : on remonte le fondu et on rend le menu. * Ici pas de repli possible, la partie visee est celle d'un ami. */ UFUNCTION() void HandleJoinFailed(FText Reason); /** * Une invitation vient d'aboutir : on fond au noir avant que le voyage * parte. C'est le seul chemin d'entree en partie qui ne passait pas par le * bouton Jouer, et donc le seul qui coupait l'image d'un coup. */ UFUNCTION() void HandleTravelPending(); /** Ferme le jeu sans rien demander. */ void CloseGame(); EMenuPendingAction PendingAction = EMenuPendingAction::None; };