(Feat) Player name tag

This commit is contained in:
2026-08-03 11:44:01 +02:00
parent a4cc59a411
commit 7595df6862
4 changed files with 120 additions and 64 deletions
@@ -17,10 +17,16 @@ class APlayerState;
* reorienter soi-meme a chaque image, et elle serait occultee par le decor --
* un pseudo qui disparait derriere un caillou n'aide personne.
*
* Contrepartie assumee de l'espace ecran : la taille ne diminue pas avec la
* distance. C'est le comportement des jeux coop du genre, et c'est justement
* pourquoi une distance de disparition est indispensable -- sans elle, quatre
* pseudos resteraient lisibles a l'autre bout de la carte.
* L'espace ecran n'applique AUCUNE echelle de distance -- verifie dans
* SWorldWidgetScreenLayer::Tick, qui ne fait que projeter la position. Le
* pseudo garderait donc une taille en pixels constante pendant que le
* personnage, lui, retrecit : l'oeil lit ca comme une etiquette qui GROSSIT en
* s'eloignant. C'est pourquoi l'echelle est calculee ici, a la main, en 1/d
* comme le ferait une vraie perspective.
*
* L'opacite suit le meme chemin : une etiquette qui s'eteint d'un coup a la
* distance limite se remarque bien plus qu'un fondu, alors qu'elle est censee
* ne pas se faire remarquer du tout.
*
* Le composant ne replique RIEN : le pseudo vit deja sur le PlayerState, qui
* est replique par le moteur. Ajouter une propriete ici enverrait deux fois la
@@ -35,7 +41,20 @@ public:
UPlayerNameplateComponent();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
/**
* Un Tick ici, contrairement au reste du projet.
*
* La regle "jamais de Tick pour lire un etat" vise les widgets qui
* interrogent une valeur au lieu de s'abonner a un delegue. Ce n'est pas le
* cas : on interpole en continu deux grandeurs geometriques -- echelle et
* opacite -- qui changent a chaque pas du joueur. Sur un timer a 0,25 s
* l'etiquette grossirait par paliers visibles.
*
* Le cout est nul en pratique : UWidgetComponent tick deja en espace ecran
* pour se projeter, on ajoute une distance et deux setters.
*/
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
protected:
/**
@@ -47,15 +66,34 @@ protected:
float MaxDrawDistance = 2500.f;
/**
* Periode de reevaluation, en secondes.
*
* Un timer et pas un Tick : la distance a la camera n'a aucune raison
* d'etre recalculee 120 fois par seconde pour une etiquette qui apparait ou
* disparait une fois toutes les dix secondes. Quatre joueurs a 120 ips
* feraient 480 calculs de distance par seconde pour rien.
* Distance a laquelle l'etiquette est a sa taille de reference, c'est-a-dire
* exactement celle dessinee dans le WBP. Plus pres elle grossit, plus loin
* elle retrecit -- en 1/d, comme une vraie perspective.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Nameplate", meta = (ClampMin = "0.05", Units = "s"))
float RefreshInterval = 0.25f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Nameplate|Echelle", meta = (ClampMin = "50", Units = "cm"))
float ReferenceDistance = 600.f;
/**
* Bornes de l'echelle. Le minimum evite un pseudo reduit a une bouillie de
* deux pixels ; le maximum evite qu'un coequipier colle a la camera ne
* remplisse l'ecran de son nom.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Nameplate|Echelle", meta = (ClampMin = "0.05"))
float MinScale = 0.4f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Nameplate|Echelle", meta = (ClampMin = "0.1"))
float MaxScale = 1.4f;
/**
* Longueur du fondu, comptee EN DECA de MaxDrawDistance : l'opacite passe de
* 1 a 0 sur cette bande, puis l'etiquette est carrement eteinte.
*
* Exprimee comme une longueur et non comme une distance de depart : une
* distance de depart superieure a MaxDrawDistance serait un reglage invalide
* silencieux, alors qu'une longueur se borne toute seule.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Nameplate|Fondu", meta = (ClampMin = "0", Units = "cm"))
float FadeLength = 700.f;
/**
* Cacher l'etiquette de son PROPRE personnage.
@@ -68,13 +106,11 @@ protected:
bool bHideOnOwningPlayer = true;
private:
/** Distance a la camera locale, puis mise a jour du texte si besoin. */
void Refresh();
/** Le PlayerState du pawn porteur, ou nullptr tant qu'il n'est pas arrive. */
APlayerState* GetOwnerPlayerState() const;
FTimerHandle RefreshTimer;
/** Recopie le pseudo dans le widget, uniquement s'il a change. */
void RefreshName();
/**
* Dernier pseudo reellement ecrit dans le widget.