// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "FpsPlayer.generated.h" class APickupItem; class UCameraComponent; class UInputAction; class UInputMappingContext; class UInteractionComponent; class UInventoryComponent; class USurvivalStatsComponent; struct FInputActionValue; /** * Personnage joueur en vue première personne. * Les assets d'input (Input Mapping Context + Input Actions) se branchent * dans le Blueprint enfant (BP_FpsPlayer), catégorie "Input". */ UCLASS() class SURVIVAL_PROJET_API AFpsPlayer : public ACharacter { GENERATED_BODY() public: // Sets default values for this character's properties AFpsPlayer(); // Called every frame virtual void Tick(float DeltaTime) override; // Called to bind functionality to input virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; /** Vrai tant que le joueur sprinte (utile pour l'anim ou la stamina plus tard). */ UFUNCTION(BlueprintPure, Category = "Mouvement") bool IsSprinting() const { return bIsSprinting; } UFUNCTION(BlueprintPure, Category = "Camera") UCameraComponent* GetFirstPersonCamera() const { return FirstPersonCamera; } UFUNCTION(BlueprintPure, Category = "Interaction") UInteractionComponent* GetInteractionComponent() const { return InteractionComponent; } UFUNCTION(BlueprintPure, Category = "Inventaire") UInventoryComponent* GetInventoryComponent() const { return InventoryComponent; } UFUNCTION(BlueprintPure, Category = "Survie") USurvivalStatsComponent* GetSurvivalStats() const { return SurvivalStats; } /** Sert a l'UI pour afficher la vraie touche mappee, plutot qu'un "E" ecrit en dur. */ UFUNCTION(BlueprintPure, Category = "Input") const UInputAction* GetInteractAction() const { return InteractAction; } /** * Coupe les etats maintenus avant de desactiver les inputs du pawn. * * Sprint et saut sont declenches par Started et arretes par Completed. * Si on desactive l'input pendant que la touche est enfoncee, le Completed * n'a plus personne pour l'ecouter et l'etat reste bloque : on rouvrirait * le jeu en sprintant sans toucher a Maj. */ UFUNCTION(BlueprintCallable, Category = "Input") void ClearTransientInputStates(); /** * Retire des objets d'un slot et les fait apparaitre au sol devant le joueur. * @param Quantity nombre d'exemplaires ; passe un grand nombre pour tout jeter. * @return true si quelque chose est reellement sorti de l'inventaire. */ UFUNCTION(BlueprintCallable, Category = "Inventaire") bool DropSlot(int32 SlotIndex, int32 Quantity); /** Vide l'inventaire entier en un tas autour du personnage. */ UFUNCTION(BlueprintCallable, Category = "Inventaire") void DropAllItems(); UFUNCTION(BlueprintPure, Category = "Survie") bool IsDead() const { return bIsDead; } /** * Secoue la caméra verticalement. Strength est la vitesse initiale en cm/s * donnée à la caméra ; positif = vers le haut, négatif = vers le bas. * Réutilisable pour une explosion, un recul d'arme, un coup reçu. */ UFUNCTION(BlueprintCallable, Category = "Camera") void AddCameraPunch(float Strength); /** * Recopie les reglages du joueur dans le pawn. * * Appelee au BeginPlay ET a chaque fois que USurvivalUserSettings diffuse : * apres un respawn le pawn est un NOUVEL acteur, une valeur poussee une * seule fois serait perdue avec le cadavre. UFUNCTION obligatoire, c'est ce * qui permet le AddDynamic sur le delegue. */ UFUNCTION() void ApplyUserSettings(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; // Appelés par le CharacterMovement quand la capsule change de taille (accroupi) virtual void OnStartCrouch(float HalfHeightAdjust, float ScaledHalfHeightAdjust) override; virtual void OnEndCrouch(float HalfHeightAdjust, float ScaledHalfHeightAdjust) override; // Réception au sol et décollage virtual void Landed(const FHitResult& Hit) override; virtual void OnJumped_Implementation() override; // ------------------------------------------------------------------ // Composants // ------------------------------------------------------------------ /** Caméra placée à hauteur des yeux, suit la rotation du controller. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera") TObjectPtr FirstPersonCamera; /** Détecte et déclenche les interactions avec le monde. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Interaction") TObjectPtr InteractionComponent; /** * Inventaire du joueur. Sur le pawn et non sur le controller : * un cadavre qui garde son butin fait partie du gameplay de survie. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Inventaire") TObjectPtr InventoryComponent; /** Vie, faim, soif. Sur le pawn : c'est ce corps qui a faim. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Survie") TObjectPtr SurvivalStats; // ------------------------------------------------------------------ // Enhanced Input : assets à assigner dans le Blueprint // ------------------------------------------------------------------ /** Contexte ajouté au joueur au BeginPlay (IMC_Default). */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input") TObjectPtr DefaultMappingContext; /** Déplacement, valeur Axis2D (X = droite/gauche, Y = avant/arrière). */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input") TObjectPtr MoveAction; /** Regard souris / stick droit, valeur Axis2D. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input") TObjectPtr LookAction; /** Saut, valeur Digital (bool). */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input") TObjectPtr JumpAction; /** Sprint, valeur Digital (bool) — maintenu. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input") TObjectPtr SprintAction; /** Accroupi, valeur Digital (bool) — maintenu. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input") TObjectPtr CrouchAction; /** Interaction, valeur Digital (bool). */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input") TObjectPtr InteractAction; /** * Utilise l'objet actif de la barre rapide, valeur Digital (bool). * A mapper sur le clic gauche. * * Bindee sur le PAWN volontairement : quand l'inventaire est ouvert, les * inputs du pawn sont coupes, donc le clic gauche sert au glisser-deposer * de l'UI sans qu'on ait le moindre test a ecrire. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input") TObjectPtr UseItemAction; // ------------------------------------------------------------------ // Réglages : mouvement // ------------------------------------------------------------------ /** Vitesse de marche normale (cm/s). */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mouvement", meta = (ClampMin = "0")) float WalkSpeed = 400.f; /** Vitesse en sprint (cm/s). */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mouvement", meta = (ClampMin = "0")) float SprintSpeed = 650.f; /** Vitesse accroupi (cm/s). */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mouvement", meta = (ClampMin = "0")) float CrouchSpeed = 200.f; // ------------------------------------------------------------------ // Réglages : objets jetés au sol // ------------------------------------------------------------------ /** * Classe engendrée quand on jette un objet. Assigne ton BP_Pickup_Test : * son ItemData est écrasé au spawn, un seul Blueprint suffit pour tout. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Inventaire|Drop") TSubclassOf DroppedPickupClass; /** Distance devant les yeux où l'objet est déposé (cm). */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventaire|Drop", meta = (ClampMin = "10")) float DropDistance = 120.f; /** Hauteur au-dessus du sol trouvé, pour éviter que l'objet s'y encastre. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventaire|Drop") float DropGroundOffset = 5.f; // ------------------------------------------------------------------ // Réglages : regard // ------------------------------------------------------------------ /** * Sensibilité horizontale : degrés de rotation par unité de souris. * 1.0 = brut (beaucoup trop rapide), ~0.4 est un bon point de départ. * * ATTENTION : ces trois valeurs, comme BaseFOV, sont ECRASEES au BeginPlay * par USurvivalUserSettings. Elles ne servent plus que de repli si l'objet * de réglages est absent ; pour changer la sensibilité, passe par le menu. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera", meta = (ClampMin = "0.01")) float LookSensitivityX = 0.4f; /** Sensibilité verticale. Souvent réglée un peu plus basse que l'horizontale. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera", meta = (ClampMin = "0.01")) float LookSensitivityY = 0.4f; /** Inverse l'axe vertical de la souris. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera") bool bInvertLookY = false; /** * Hauteur de l'oeil AU-DESSUS DES PIEDS, debout (cm). * 160 cm correspond a un personnage d'environ 1m76. * Mesure depuis le sol et non depuis la capsule : c'est ce qui permet * d'annuler le saut instantane de la capsule quand elle retrecit. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera") float EyeHeightStanding = 160.f; /** Hauteur de l'oeil au-dessus des pieds, accroupi (cm). */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera") float EyeHeightCrouched = 104.f; // ------------------------------------------------------------------ // Réglages : animation d'accroupissement // ------------------------------------------------------------------ /** Durée en secondes de la transition debout <-> accroupi. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Accroupi", meta = (ClampMin = "0.01")) float CrouchTransitionDuration = 0.4f; /** Tangage (degrés) au pic de la transition. Positif = le regard plonge. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Accroupi") float CrouchTiltPitch = 3.f; /** * Roulis (degrés) au pic de la transition : bascule sur le côté. * A 0 par defaut, le mouvement reste purement vertical. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Accroupi") float CrouchTiltRoll = 0.f; // ------------------------------------------------------------------ // Réglages : impacts caméra (saut / atterrissage) // ------------------------------------------------------------------ /** * Fréquence du ressort de caméra en Hz : à quelle vitesse elle revient * en place après un choc. Plus haut = plus sec. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Impact", meta = (ClampMin = "0.1")) float PunchFrequency = 3.f; /** * Amortissement du ressort. 1.0 = retour net sans rebond, * 0.5 = un rebond visible, en dessous ça oscille longtemps. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Impact", meta = (ClampMin = "0.05", ClampMax = "2.0")) float PunchDamping = 0.85f; /** * Durée (s) sur laquelle une impulsion est injectée dans le ressort. * A 0 elle est appliquée d'un coup : la caméra part à pleine vitesse en * une frame, ce qui se lit comme un a-coup. Quelques centiemes suffisent * a rendre l'entree en mouvement progressive. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Impact", meta = (ClampMin = "0")) float PunchImpulseRampTime = 0.06f; /** Degrés de tangage ajoutés par cm de déplacement vertical de la caméra. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Impact") float PunchPitchPerCm = 0.35f; /** Amplitude maximale du déplacement vertical (cm), garde-fou. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Impact", meta = (ClampMin = "0")) float PunchMaxOffset = 50.f; /** * Impulsion (cm/s) à l'atterrissage, quand l'impact est au maximum. * Ordre de grandeur : le deplacement en cm de la camera vaut environ * cette valeur x 0.018 (avec les reglages de ressort par defaut). */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Impact", meta = (ClampMin = "0")) float LandPunchStrength = 2000.f; /** En dessous de cette vitesse de chute (cm/s), aucun effet à l'atterrissage. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Impact", meta = (ClampMin = "0")) float LandPunchMinFallSpeed = 150.f; /** * Vitesse de chute (cm/s) à partir de laquelle l'effet est au maximum. * Un saut sur place retombe a peu pres a JumpZVelocity (450), donc cette * valeur doit rester proche pour qu'un saut normal se sente deja bien. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Impact", meta = (ClampMin = "1")) float LandPunchMaxFallSpeed = 900.f; /** * Impulsion (cm/s) au décollage du saut. Positif = la caméra s'enfonce * un instant (compression des jambes) ; mets une valeur négative pour * qu'elle parte vers le haut à la place. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Impact") float JumpPunchStrength = 550.f; // ------------------------------------------------------------------ // Réglages : champ de vision // ------------------------------------------------------------------ /** FOV au repos, en degrés. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|FOV", meta = (ClampMin = "30", ClampMax = "150")) float BaseFOV = 90.f; /** Degrés de FOV ajoutés en sprint. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|FOV") float SprintFOVOffset = 8.f; /** Vitesse de transition du FOV. Plus haut = plus brusque. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|FOV", meta = (ClampMin = "0.1")) float FOVInterpSpeed = 8.f; // ------------------------------------------------------------------ // Handlers d'input // ------------------------------------------------------------------ void Move(const FInputActionValue& Value); void Look(const FInputActionValue& Value); void StartSprint(); void StopSprint(); void StartCrouch(); void StopCrouch(); void Interact(); /** * Relachement de la touche de sprint / d'accroupissement. * * Separes de StopSprint et StopCrouch, qui restent des ordres inconditionnels : * en mode bascule le relachement ne doit rien faire, alors que la mort ou * l'ouverture de l'inventaire doivent bel et bien couper le sprint. */ void HandleSprintReleased(); void HandleCrouchReleased(); /** * Clic gauche : agit avec l'objet actif de la barre rapide. * Aujourd'hui seuls les consommables font quelque chose ; c'est ici que * viendront les outils et les armes. */ void UseSelectedItem(); private: /** Fait avancer toutes les animations de caméra et les applique. */ void UpdateCameraEffects(float DeltaTime); /** Branche sur OnDied du composant de survie. */ UFUNCTION() void HandleDeath(); /** Fait apparaitre un pickup deja configure a un endroit donne. */ APickupItem* SpawnPickup(const struct FInventorySlot& Slot, const FVector& Location); /** Descend une position jusqu'au sol, pour ne pas laisser d'objet en l'air. */ FVector PlaceOnGround(const FVector& Start) const; bool bIsDead = false; /** Progression de l'animation d'accroupissement : 0 = debout, 1 = accroupi. */ float CrouchAlpha = 0.f; /** Valeur visée par CrouchAlpha. */ float CrouchTargetAlpha = 0.f; /** +1 quand on s'accroupit, -1 quand on se relève : inverse le sens du tilt. */ float CrouchTiltDirection = 1.f; /** Décalage vertical courant de la caméra (cm), état du ressort d'impact. */ float PunchOffset = 0.f; /** Vitesse du ressort d'impact (cm/s). */ float PunchVelocity = 0.f; /** Impulsion restant à injecter dans le ressort, étalée sur PunchImpulseRampTime. */ float PendingPunch = 0.f; /** Vitesse verticale mémorisée pendant la chute, pour calibrer l'atterrissage. */ float LastFallSpeed = 0.f; bool bIsSprinting = false; /** Évite de spammer le log si IA_Look est mal configurée. */ bool bLoggedLookTypeWarning = false; // ------------------------------------------------------------------ // Copies locales des réglages joueur, rafraîchies par ApplyUserSettings // ------------------------------------------------------------------ /** 0 = caméra parfaitement fixe, 1 = amplitude d'origine. */ float CameraShakeMultiplier = 1.f; bool bSprintToggleMode = false; bool bCrouchToggleMode = false; };