(Feat) Add Animation Fps Charater
This commit is contained in:
@@ -0,0 +1,897 @@
|
||||
// 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 UAnimMontage;
|
||||
class UCameraComponent;
|
||||
class UCharacterAppearanceComponent;
|
||||
class UCraftingComponent;
|
||||
class UFootstepComponent;
|
||||
class UHeadBobComponent;
|
||||
class UHeldItemComponent;
|
||||
class UInputAction;
|
||||
class UInputMappingContext;
|
||||
class UInteractionComponent;
|
||||
class UInventoryComponent;
|
||||
class UItemDataAsset;
|
||||
class USurvivalStatsComponent;
|
||||
struct FInputActionValue;
|
||||
|
||||
/**
|
||||
* Ce que vaut la réception qui vient d'avoir lieu.
|
||||
*
|
||||
* Produit par le PAWN, qui est le seul à connaître les deux seuils, et republié
|
||||
* tel quel par UFpsArmsAnimInstance. Un enum plutôt que deux booléens parce que
|
||||
* les trois cas s'excluent par construction : la machine à états compare, elle
|
||||
* n'a aucune condition à recomposer, et il n'existe aucune combinaison où deux
|
||||
* transitions seraient valides en même temps — c'est-à-dire prises au hasard.
|
||||
*
|
||||
* Remis à None dès l'entrée en chute (voir Tick), donc il vaut None pendant tout
|
||||
* le vol : une transition n'a jamais à vérifier bIsFalling en plus.
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class ELandingImpact : uint8
|
||||
{
|
||||
/** En l'air, ou chute trop faible pour mériter une animation. */
|
||||
None,
|
||||
|
||||
/** Réception normale (JumpLanding). */
|
||||
Soft,
|
||||
|
||||
/**
|
||||
* Réception encaissée (HardLanding) — c'est-à-dire, très exactement, une
|
||||
* chute qui a coûté de la vie. Le seuil n'est pas un réglage d'animation,
|
||||
* c'est `FallDamageMinSpeed`.
|
||||
*/
|
||||
Hard
|
||||
};
|
||||
|
||||
/**
|
||||
* Ressort amorti à une dimension, partagé par les effets de caméra.
|
||||
*
|
||||
* Pourquoi un ressort plutôt qu'une courbe paramétrée par le temps : un ressort
|
||||
* n'a pas d'animation « en cours » qu'il faudrait annuler pour en jouer une
|
||||
* autre. Une nouvelle impulsion s'ajoute simplement à l'état courant, position
|
||||
* et vitesse restent continues, donc le mouvement est interruptible à n'importe
|
||||
* quel instant sans jamais produire de saut. C'est exactement ce que le crouch
|
||||
* demande quand le joueur martèle la touche.
|
||||
*/
|
||||
struct FCameraSpring
|
||||
{
|
||||
/** Déplacement courant, dans l'unité de ce que le ressort pilote. */
|
||||
float Offset = 0.f;
|
||||
|
||||
/** Vitesse courante, par seconde. */
|
||||
float Velocity = 0.f;
|
||||
|
||||
/** Impulsion pas encore versée, étalée sur RampTime pour éviter l'à-coup. */
|
||||
float PendingImpulse = 0.f;
|
||||
|
||||
void AddImpulse(float Strength) { PendingImpulse += Strength; }
|
||||
|
||||
/** Remet le ressort au repos, sans transition (respawn, téléportation). */
|
||||
void Reset()
|
||||
{
|
||||
Offset = 0.f;
|
||||
Velocity = 0.f;
|
||||
PendingImpulse = 0.f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intègre le ressort d'un pas de temps et renvoie le nouvel Offset.
|
||||
*
|
||||
* @param Frequency fréquence propre en Hz : vitesse de retour au repos.
|
||||
* @param Damping 1 = retour net sans rebond, en dessous ça oscille.
|
||||
* @param RampTime durée sur laquelle une impulsion est versée (0 = d'un coup).
|
||||
* @param MaxOffset garde-fou d'amplitude.
|
||||
*/
|
||||
float Update(float Step, float Frequency, float Damping, float RampTime, float MaxOffset);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 EMBERWILD_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;
|
||||
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const 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 = "Camera")
|
||||
UHeadBobComponent* GetHeadBob() const { return HeadBob; }
|
||||
|
||||
/** Les bras vus par le joueur local. C'est ici que viendra l'objet en main. */
|
||||
UFUNCTION(BlueprintPure, Category = "Animation")
|
||||
USkeletalMeshComponent* GetFirstPersonArms() const { return FirstPersonArms; }
|
||||
|
||||
/** La réception en cours, ou None en l'air. Lue par les AnimInstance. */
|
||||
UFUNCTION(BlueprintPure, Category = "Animation")
|
||||
ELandingImpact GetLandingImpact() const { return LandingImpact; }
|
||||
|
||||
/**
|
||||
* Joue un montage sur les bras du joueur LOCAL, et seulement lui.
|
||||
*
|
||||
* Rien n'est replique et c'est voulu : les bras sont en OnlyOwnerSee, donc
|
||||
* les animer chez le serveur ou chez un ami ferait tourner un squelette que
|
||||
* personne ne rend. Le geste vu par les autres joueurs viendra du mesh 3e
|
||||
* personne, avec ses propres animations, le jour ou l'animateur les livrera.
|
||||
*
|
||||
* @return la duree du montage en secondes, 0 s'il n'a pas pu etre joue.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Animation")
|
||||
float PlayArmsMontage(UAnimMontage* Montage, float PlayRate = 1.f);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Interaction")
|
||||
UInteractionComponent* GetInteractionComponent() const { return InteractionComponent; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Inventaire")
|
||||
UInventoryComponent* GetInventoryComponent() const { return InventoryComponent; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Crafting")
|
||||
UCraftingComponent* GetCraftingComponent() const { return CraftingComponent; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Survie")
|
||||
USurvivalStatsComponent* GetSurvivalStats() const { return SurvivalStats; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Apparence")
|
||||
UCharacterAppearanceComponent* GetAppearanceComponent() const { return AppearanceComponent; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Inventaire")
|
||||
UHeldItemComponent* GetHeldItemComponent() const { return HeldItemComponent; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Audio")
|
||||
UFootstepComponent* GetFootstepComponent() const { return FootstepComponent; }
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Commandes console d'apparence
|
||||
//
|
||||
// Elles vivent ICI et non sur UCharacterAppearanceComponent, ou leur place
|
||||
// serait pourtant plus naturelle : la chaine de routage des commandes
|
||||
// (UPlayer::Exec, dans Player.cpp) interroge le monde, le PlayerInput, le
|
||||
// controller, le PAWN, le HUD, le GameMode, le CheatManager, le GameState
|
||||
// et le camera manager -- jamais les composants, AActor ne surchargeant pas
|
||||
// ProcessConsoleExec pour les parcourir. Une UFUNCTION(Exec) posee sur un
|
||||
// composant est silencieusement ignoree, sans le moindre message.
|
||||
//
|
||||
// Le pawn est le maillon le plus proche du composant dans cette chaine,
|
||||
// d'ou ces trois delegations d'une ligne. Elles disparaitront le jour ou
|
||||
// l'ecran de customisation existera.
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/** `EmberPart hair 3` -- body, head, hair, eyebrows, beard, mustache, eyes. */
|
||||
UFUNCTION(Exec, Category = "Apparence")
|
||||
void EmberPart(const FString& Part, int32 Index);
|
||||
|
||||
/** `EmberColor skin 2` -- skin, hair, eye, underwear. Index dans la palette. */
|
||||
UFUNCTION(Exec, Category = "Apparence")
|
||||
void EmberColor(const FString& Part, int32 ColorIndex);
|
||||
|
||||
/** Ecrit l'apparence courante et le nombre d'options de chaque categorie. */
|
||||
UFUNCTION(Exec, Category = "Apparence")
|
||||
void EmberAppearanceDump();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Persiste l'apparence du composant et l'annonce au serveur, via le
|
||||
* controller. Appelee apres chaque commande console, pour que le
|
||||
* changement se voie chez les autres et survive au relancement.
|
||||
*/
|
||||
void SubmitCurrentAppearance();
|
||||
|
||||
public:
|
||||
|
||||
/** 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);
|
||||
|
||||
/**
|
||||
* Meme chose, depuis un inventaire quelconque : celui d'un coffre ouvert,
|
||||
* typiquement.
|
||||
*
|
||||
* C'est le PAWN qui pose au sol et pas le composant, pour la meme raison
|
||||
* que le surplus de fabrication : un UInventoryComponent ne sait pas
|
||||
* engendrer un acteur, et un coffre qui deposerait lui-meme laisserait le
|
||||
* butin dans sa propre caisse. L'objet part donc toujours devant les yeux
|
||||
* du joueur, quel que soit le contenant d'ou il sort.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventaire")
|
||||
bool DropFromInventory(UInventoryComponent* Inventory, 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();
|
||||
|
||||
/**
|
||||
* Pose la transform de la camera juste avant que la vue soit lue.
|
||||
*
|
||||
* Le gestionnaire de camera passe par ici pour construire le point de vue :
|
||||
* c'est le seul endroit ou l'on est certain de lire la position de l'acteur
|
||||
* et la demi-hauteur de la capsule au MEME instant. Le Tick du pawn, lui,
|
||||
* n'a aucune dependance de tick vis-a-vis du CharacterMovement (verifie dans
|
||||
* Character.cpp : seul le Mesh en recoit une), donc la frame ou la capsule
|
||||
* change de taille pouvait etre calculee avec l'ancienne demi-hauteur --
|
||||
* soit un decalage de 28 cm sur une frame, a chaque accroupissement.
|
||||
* Bonus : le regard n'a plus une frame de retard sur la souris.
|
||||
*/
|
||||
virtual void CalcCamera(float DeltaTime, FMinimalViewInfo& OutResult) override;
|
||||
|
||||
/**
|
||||
* L'autre cote de la course avec le PlayerState.
|
||||
*
|
||||
* Chez un client, le pawn et le PlayerState arrivent par deux chemins de
|
||||
* replication independants : tantot l'apparence est la avant le corps --
|
||||
* ASurvivalPlayerState::OnRep_CharacterAppearance la pose alors lui-meme --
|
||||
* tantot c'est l'inverse, et c'est ici qu'on va la chercher. Ni l'un ni
|
||||
* l'autre ne peut supposer avoir gagne, donc les deux appellent la meme
|
||||
* fonction idempotente.
|
||||
*/
|
||||
virtual void OnRep_PlayerState() override;
|
||||
|
||||
/**
|
||||
* Les deux moities de « le controller est arrive ».
|
||||
*
|
||||
* UHeldItemComponent ne peut lire la case active QUE chez le joueur local,
|
||||
* et son BeginPlay peut tomber avant que le pawn soit possede -- chez un
|
||||
* client, le pawn et son controller arrivent par deux chemins independants,
|
||||
* exactement comme le PlayerState. Un joueur qui reapparait avec une hache
|
||||
* deja en case 1 aurait alors la main vide jusqu'a ce qu'il touche a son
|
||||
* inventaire. PossessedBy couvre le serveur, OnRep_Controller le client, et
|
||||
* RefreshFromInventory() est idempotente.
|
||||
*/
|
||||
virtual void PossessedBy(AController* NewController) override;
|
||||
virtual void OnRep_Controller() override;
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
/** Lit l'apparence sur le PlayerState et la monte, s'il est deja arrive. */
|
||||
void RefreshAppearanceFromPlayerState();
|
||||
|
||||
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<UCameraComponent> FirstPersonCamera;
|
||||
|
||||
/**
|
||||
* Bras vue première personne, visibles du seul propriétaire.
|
||||
*
|
||||
* Attachés à la CAMÉRA et non à la capsule : ils doivent suivre le tangage du
|
||||
* regard, sinon lever les yeux les laisserait à l'horizontale. Bénéfice
|
||||
* gratuit au passage — ils héritent du ressort d'impact et de la bascule
|
||||
* d'accroupissement, donc les bras encaissent l'atterrissage avec la caméra
|
||||
* sans une ligne de code de plus.
|
||||
*
|
||||
* Sa transform relative se règle À L'ŒIL dans BP_FpsPlayer : les valeurs du
|
||||
* constructeur ne sont qu'un point de départ, elles dépendent entièrement de
|
||||
* l'origine du FBX livré par l'animateur.
|
||||
*/
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation")
|
||||
TObjectPtr<USkeletalMeshComponent> FirstPersonArms;
|
||||
|
||||
/**
|
||||
* Montage joué sur les bras au ramassage d'un objet (MTG_GrabItem).
|
||||
* Vide = aucun geste, le ramassage fonctionne quand même.
|
||||
*/
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Animation")
|
||||
TObjectPtr<UAnimMontage> GrabMontage;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Dégâts de chute
|
||||
//
|
||||
// C'est ce bloc qui définit la réception encaissée, et pas l'inverse :
|
||||
// `ELandingImpact::Hard` signifie exactement « cet atterrissage a coûté de la
|
||||
// vie ». Un seuil d'animation réglé de son côté finirait forcément par
|
||||
// diverger de celui des dégâts, et le joueur verrait son personnage encaisser
|
||||
// sans rien perdre — ou pire, perdre de la vie en se réceptionnant
|
||||
// souplement. Une animation qui ment sur l'état du jeu est pire que pas
|
||||
// d'animation du tout.
|
||||
//
|
||||
// L'atterrissage est un ÉTAT de la machine et non un montage : les trois
|
||||
// animations livrées (JumpStart, JumpFallLoop, JumpLanding) forment une
|
||||
// chaîne dont le milieu est une BOUCLE, et une boucle ne se joue pas en
|
||||
// montage.
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Vitesse de chute (cm/s) à partir de laquelle on prend des dégâts.
|
||||
*
|
||||
* Doit rester nettement au-dessus de la retombée d'un saut sur place
|
||||
* (~JumpZVelocity, 450 par défaut), sinon sauter coûte de la vie et le
|
||||
* déplacement devient une punition.
|
||||
*
|
||||
* À 800 cm/s, c'est une chute d'environ 3,2 m (v = racine(2·g·h), g = 980).
|
||||
* Ne pas raisonner en hauteur pour régler cette valeur : la hauteur ne se
|
||||
* mesure nulle part dans le moteur, alors que la vitesse d'impact est
|
||||
* exactement ce que le CharacterMovement a sous la main — et elle tient
|
||||
* compte, gratuitement, d'un saut fait en tombant.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Fall Damage", meta = (ClampMin = "0"))
|
||||
float FallDamageMinSpeed = 800.f;
|
||||
|
||||
/** Vitesse (cm/s) au-delà de laquelle les dégâts plafonnent (~20 m de chute). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Fall Damage", meta = (ClampMin = "1"))
|
||||
float FallDamageMaxSpeed = 2000.f;
|
||||
|
||||
/**
|
||||
* Dégâts pris pile au seuil. Volontairement non nul : franchir la limite
|
||||
* doit se sentir, sinon le seuil n'existe que dans le code.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Fall Damage", meta = (ClampMin = "0"))
|
||||
float FallDamageMin = 15.f;
|
||||
|
||||
/** Dégâts pris à FallDamageMaxSpeed et au-delà. À 100, la chute est mortelle. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Fall Damage", meta = (ClampMin = "0"))
|
||||
float FallDamageMax = 100.f;
|
||||
|
||||
/** Les dégâts de la chute qui vient d'avoir lieu, 0 sous le seuil. */
|
||||
UFUNCTION(BlueprintPure, Category = "Fall Damage")
|
||||
float ComputeFallDamage(float FallSpeed) const;
|
||||
|
||||
/**
|
||||
* Balancement de tête procédural : respiration à l'arrêt, pas à la marche,
|
||||
* foulée au sprint. Tous ses réglages sont dans le Details panel du composant,
|
||||
* pas ici : cinq profils de cinq valeurs noieraient la catégorie "Camera".
|
||||
*
|
||||
* Il ne touche pas la caméra lui-même, il expose deux décalages que
|
||||
* ApplyCameraTransform additionne — cette fonction reste le seul écrivain.
|
||||
*/
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
|
||||
TObjectPtr<UHeadBobComponent> HeadBob;
|
||||
|
||||
/** Détecte et déclenche les interactions avec le monde. */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Interaction")
|
||||
TObjectPtr<UInteractionComponent> 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<UInventoryComponent> InventoryComponent;
|
||||
|
||||
/**
|
||||
* Fabrication. Sur le pawn comme l'inventaire : c'est ce corps qui fabrique,
|
||||
* et il lit l'inventaire du meme acteur.
|
||||
*/
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Crafting")
|
||||
TObjectPtr<UCraftingComponent> CraftingComponent;
|
||||
|
||||
/** Vie, faim, soif. Sur le pawn : c'est ce corps qui a faim. */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Survie")
|
||||
TObjectPtr<USurvivalStatsComponent> SurvivalStats;
|
||||
|
||||
/**
|
||||
* Monte la tete, les cheveux, la barbe et les couleurs sur le mesh 3e
|
||||
* personne.
|
||||
*
|
||||
* Sur le pawn et non sur le controller, alors que l'apparence, elle, vivra
|
||||
* sur le PlayerState : ce composant ne STOCKE rien, il assemble un corps.
|
||||
* Or c'est le corps qui meurt et reapparait, et un nouveau pawn doit se
|
||||
* remonter tout seul.
|
||||
*/
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Apparence")
|
||||
TObjectPtr<UCharacterAppearanceComponent> AppearanceComponent;
|
||||
|
||||
/**
|
||||
* Montre dans la main l'objet de la case active de la barre rapide.
|
||||
*
|
||||
* Sur le pawn : ce sont ces bras-la et ce corps-la qui tiennent l'objet, et
|
||||
* un cadavre ne tient plus rien. Il lit l'inventaire du meme acteur.
|
||||
*/
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Inventaire")
|
||||
TObjectPtr<UHeldItemComponent> HeldItemComponent;
|
||||
|
||||
/**
|
||||
* Bruits de pas.
|
||||
*
|
||||
* Sur le pawn et sur TOUS les pawns, pas seulement celui du joueur local :
|
||||
* le composant ne replique rien, chaque machine calcule les pas de tous les
|
||||
* corps qu'elle connait a partir de leur vitesse deja synchronisee. Le
|
||||
* mettre sur le controller n'aurait donc donne les pas que d'un joueur.
|
||||
*/
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Audio")
|
||||
TObjectPtr<UFootstepComponent> FootstepComponent;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Enhanced Input : assets à assigner dans le Blueprint
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/** Contexte ajouté au joueur au BeginPlay (IMC_Default). */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
TObjectPtr<UInputMappingContext> DefaultMappingContext;
|
||||
|
||||
/** Déplacement, valeur Axis2D (X = droite/gauche, Y = avant/arrière). */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
TObjectPtr<UInputAction> MoveAction;
|
||||
|
||||
/** Regard souris / stick droit, valeur Axis2D. */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
TObjectPtr<UInputAction> LookAction;
|
||||
|
||||
/** Saut, valeur Digital (bool). */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
TObjectPtr<UInputAction> JumpAction;
|
||||
|
||||
/** Sprint, valeur Digital (bool) — maintenu. */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
TObjectPtr<UInputAction> SprintAction;
|
||||
|
||||
/** Accroupi, valeur Digital (bool) — maintenu. */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
TObjectPtr<UInputAction> CrouchAction;
|
||||
|
||||
/** Interaction, valeur Digital (bool). */
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
||||
TObjectPtr<UInputAction> 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<UInputAction> 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<APickupItem> 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 bascule. Positif = le regard plonge.
|
||||
*
|
||||
* Le tilt n'est plus une courbe indexée sur l'avancement de la transition
|
||||
* mais un ressort relancé à chaque changement d'état : c'est ce qui permet
|
||||
* de s'accroupir et de se relever coup sur coup sans que la caméra saute.
|
||||
* L'impulsion est normalisée pour que le pic tombe bien sur cette valeur.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Accroupi")
|
||||
float CrouchTiltPitch = 3.f;
|
||||
|
||||
/**
|
||||
* Roulis (degrés) au pic de la bascule : bascule sur le côté.
|
||||
* A 0 par defaut, le mouvement reste purement vertical.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Accroupi")
|
||||
float CrouchTiltRoll = 0.f;
|
||||
|
||||
/**
|
||||
* Fréquence du ressort de bascule (Hz). Le pic est atteint après environ
|
||||
* 1/(2*PI*f) secondes : 0.9 Hz place le sommet vers 0.18 s, soit à peu près
|
||||
* au milieu d'une transition de 0.4 s. Plus haut = plus sec et plus court.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Accroupi", meta = (ClampMin = "0.1"))
|
||||
float CrouchTiltFrequency = 0.9f;
|
||||
|
||||
/** Amortissement de la bascule. 1 = aucun rebond ; en dessous, la tête oscille. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Accroupi", meta = (ClampMin = "0.05", ClampMax = "2.0"))
|
||||
float CrouchTiltDamping = 1.f;
|
||||
|
||||
/**
|
||||
* Durée (s) sur laquelle l'impulsion de bascule est versée dans le ressort.
|
||||
* A 0 la rotation démarre à pleine vitesse angulaire en une frame, ce qui
|
||||
* se lit comme un claquement ; quelques centièmes suffisent à l'adoucir.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Accroupi", meta = (ClampMin = "0"))
|
||||
float CrouchTiltRampTime = 0.05f;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 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 : lance le GESTE de l'objet actif de la barre rapide.
|
||||
*
|
||||
* Elle ne produit plus l'effet elle-même — c'est le marqueur
|
||||
* `UAnimNotify_ItemAction` posé dans le montage qui le fait, au moment où le
|
||||
* geste frappe. Sans montage à jouer, elle retombe sur l'effet immédiat :
|
||||
* un objet qui n'a pas d'animation n'aura jamais de marqueur, et le priver
|
||||
* d'effet serait un objet cassé plutôt qu'un objet sans animation.
|
||||
*/
|
||||
void UseSelectedItem();
|
||||
|
||||
public:
|
||||
/**
|
||||
* L'objet en main agit MAINTENANT. Appelée par l'AnimNotify du montage.
|
||||
*
|
||||
* Publique et `BlueprintCallable` pour cette seule raison : c'est le point
|
||||
* d'entrée de l'animation vers le gameplay, y compris depuis un notify
|
||||
* Blueprint. Elle ne fait rien d'autre que ce que faisait la seconde moitié
|
||||
* de `UseSelectedItem` : router vers l'autorité.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Items")
|
||||
void TriggerHeldItemAction();
|
||||
|
||||
private:
|
||||
/**
|
||||
* La case visée par le clic, retenue jusqu'à l'impact.
|
||||
*
|
||||
* Relire la case active au moment du marqueur serait faux : trois dixièmes
|
||||
* de seconde séparent l'appui de l'impact, et la molette peut passer sur un
|
||||
* autre objet entre-temps — le coup de hache partirait alors avec la pomme
|
||||
* qu'on vient de sélectionner. Changer d'objet coupe bien le montage en
|
||||
* cours (`PlayEquipMontage` ne saute pas), mais seulement quand le nouvel
|
||||
* objet a un montage d'équipement : ce n'est pas une garantie sur laquelle
|
||||
* s'appuyer.
|
||||
*/
|
||||
int32 PendingUseSlotIndex = INDEX_NONE;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Réseau
|
||||
//
|
||||
// Jeter et utiliser engendrent ou détruisent des choses dans le monde :
|
||||
// ce sont des actions d'autorité. Le routage vit dans les fonctions
|
||||
// publiques elles-mêmes, pour que ni l'UI ni l'input n'aient à savoir
|
||||
// s'ils tournent chez l'hôte ou chez un client.
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
UFUNCTION(Server, Reliable)
|
||||
void Server_DropFromInventory(UInventoryComponent* Inventory, int32 SlotIndex, int32 Quantity);
|
||||
|
||||
/**
|
||||
* Le slot est passé explicitement : SelectedHotbarIndex n'est PAS répliqué,
|
||||
* c'est une intention purement locale. Le serveur ne peut donc pas deviner
|
||||
* ce que le joueur avait en main.
|
||||
*/
|
||||
UFUNCTION(Server, Reliable)
|
||||
void Server_UseItem(int32 SlotIndex);
|
||||
|
||||
/** L'utilisation réelle, côté autorité. */
|
||||
void PerformUseItem(int32 SlotIndex);
|
||||
|
||||
/**
|
||||
* Point d'entrée unique du sprint : applique en local ET prévient le serveur.
|
||||
*
|
||||
* Sans le second, le serveur croirait le client à `WalkSpeed` et corrigerait
|
||||
* sa position à chaque pas — c'est le rubber-banding classique, et il ne se
|
||||
* voit que sur une machine distante, jamais chez l'hôte.
|
||||
*/
|
||||
void SetSprinting(bool bNewSprinting);
|
||||
|
||||
UFUNCTION(Server, Reliable)
|
||||
void Server_SetSprinting(bool bNewSprinting);
|
||||
|
||||
/** La vitesse suit l'état, y compris sur les pawns des autres joueurs. */
|
||||
UFUNCTION()
|
||||
void OnRep_IsSprinting();
|
||||
|
||||
void ApplySprintSpeed();
|
||||
|
||||
/** Fait avancer toutes les animations de caméra (intégration uniquement). */
|
||||
void UpdateCameraEffects(float DeltaTime);
|
||||
|
||||
/**
|
||||
* Recopie l'état des animations dans la transform de la caméra.
|
||||
* Séparée de l'intégration : appelée à la fois en fin de Tick et depuis
|
||||
* CalcCamera, elle doit rester idempotente et sans notion de temps.
|
||||
*/
|
||||
void ApplyCameraTransform();
|
||||
|
||||
/** Relance la bascule de tête. Direction : +1 on s'accroupit, -1 on se relève. */
|
||||
void AddCrouchTilt(float Direction);
|
||||
|
||||
/** Branche sur OnDied du composant de survie. */
|
||||
UFUNCTION()
|
||||
void HandleDeath();
|
||||
|
||||
/**
|
||||
* Le resultat d'une fabrication n'est pas entre dans l'inventaire : on le
|
||||
* pose aux pieds du joueur plutot que de le laisser disparaitre.
|
||||
*
|
||||
* C'est le pawn qui fait ca et non UCraftingComponent : le composant n'a pas
|
||||
* a savoir comment on engendre un objet dans le monde, et un etabli qui
|
||||
* porterait le meme composant deposerait son surplus sur sa propre table.
|
||||
*/
|
||||
UFUNCTION()
|
||||
void HandleCraftOverflow(UItemDataAsset* Item, int32 Quantity, int32 RemainingUses);
|
||||
|
||||
/** 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;
|
||||
|
||||
/** Déplacement vertical de la caméra (cm) : sauts, atterrissages, explosions. */
|
||||
FCameraSpring PunchSpring;
|
||||
|
||||
/**
|
||||
* Bascule de tête pendant l'accroupissement, en unités normalisées :
|
||||
* son pic vaut 1, ce sont CrouchTiltPitch et CrouchTiltRoll qui le
|
||||
* convertissent en degrés.
|
||||
*/
|
||||
FCameraSpring CrouchTiltSpring;
|
||||
|
||||
/** Vitesse verticale mémorisée pendant la chute, pour calibrer l'atterrissage. */
|
||||
float LastFallSpeed = 0.f;
|
||||
|
||||
/**
|
||||
* La réception en cours, lue par les AnimInstance.
|
||||
*
|
||||
* Écrite à deux endroits et deux seulement : remise à None dans Tick tant
|
||||
* qu'on est en l'air, posée à sa vraie valeur dans Landed(). C'est ce qui
|
||||
* garantit qu'elle vaut None pendant tout le vol — sans quoi la machine à
|
||||
* états prendrait sa transition de réception avec la valeur du saut
|
||||
* précédent, dès la première image de chute.
|
||||
*/
|
||||
ELandingImpact LandingImpact = ELandingImpact::None;
|
||||
|
||||
/** Répliqué pour que les autres joueurs voient la bonne vitesse et la bonne anim. */
|
||||
UPROPERTY(ReplicatedUsing = OnRep_IsSprinting)
|
||||
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;
|
||||
};
|
||||
Reference in New Issue
Block a user