Aller au contenu

Gameplay Tag Flags

Les LBRGameplayTagFlags transforment un conteneur de gameplay tags en une propriété unique qui se présente comme un ensemble de cases à cocher — une liste d'options extensible et propre à chaque projet. Plutôt que de coder en dur une série de champs bool, vous exposez une seule propriété dont les options disponibles sont simplement l'ensemble des gameplay tags situés sous une branche donnée de l'arborescence des tags. Ajoutez un nouveau tag au bon endroit et une nouvelle case apparaît automatiquement, sans aucune modification de code.

C'est ainsi que Libretto expose des éléments tels que les Flags de chaque ligne et de chaque sous-dialogue, ainsi que les options de génération (quelles pistes générer, quels types d'assets, etc.).

Vue d'ensemble

Une valeur LBRGameplayTagFlags est en réalité un FGameplayTagContainer sous le capot — les tags présents dans le conteneur sont les cases qui sont cochées. Comme le champ est filtré sur une catégorie (un tag parent), la grille de propriétés liste chaque tag enfant de cette catégorie comme une case à cocher indépendante.

A Flags property expanded as a checkbox grid

Par exemple, une propriété LineFlags filtrée sur Libretto.Flags.Lines propose chaque enfant de Libretto.Flags.Lines (NoSubtitle, Pause, …) comme un interrupteur distinct.

Tip

Comme le type sous-jacent est un conteneur de gameplay tags, la valeur est par nature extensible et pilotée par les données. Deux équipes (ou deux plugins) peuvent contribuer des options à la même propriété simplement en déclarant des tags sous le même parent — aucun n'a besoin de connaître l'existence des autres.

Ajouter de nouveaux flags

Pour ajouter une option, vous ne touchez pas du tout à la propriété — il vous suffit de créer le gameplay tag correspondant au bon endroit de la hiérarchie. Une propriété de flags filtrée sur un tag de catégorie propose automatiquement chaque enfant de cette catégorie comme case à cocher, quel que soit celui qui l'a déclaré ou d'où il provient.

Adding a child tag under a flags category

Les tags peuvent être déclarés des façons habituelles — l'éditeur Project Settings ▸ GameplayTags, une table de tags .ini, ou nativement en C++. Libretto déclare ses propres tags de flags nativement ; vous pouvez suivre le même modèle pour des options spécifiques à votre projet :

// In a .cpp, using Libretto's helper macros (see LBRGameplayTagFlags.h)
LBR_DEFINE_GAMEPLAY_TAG(TAG_MyProject_Lines_Whisper, "Libretto.Flags.Lines.Whisper",
    "Render this line's subtitle in the whisper style");

Info

Les macros exactes de déclaration de tags (LBR_DECLARE_GAMEPLAY_TAG_EXTERN, LBR_DEFINE_GAMEPLAY_TAG, LBR_DEFINE_EDITOR_GAMEPLAY_TAG) se trouvent dans LBRGameplayTagFlags.h. Ce sont de fines surcouches des macros UE_DEFINE_GAMEPLAY_TAG_* d'Unreal ; si vous avez déjà une convention de déclaration de tags dans votre projet, utilisez celle que vous voulez — l'interface des flags se soucie uniquement que les tags existent sous le bon parent.

Filtrer les options

Une propriété de flags n'est utile qu'une fois filtrée sur une catégorie, afin qu'elle affiche le bon sous-ensemble de tags plutôt que l'arborescence complète. Il existe deux méta-spécificateurs pour cela, tous deux des mécanismes standard des gameplay tags d'Unreal que LBRGameplayTagFlags respecte.

Categories — un filtre fixe

Utilisez le méta-spécificateur Categories pour épingler une propriété (ou un paramètre Blueprint) à une branche de l'arborescence des tags. Tout ce qui se trouve sous ce parent devient une case à cocher :

// A per-line flags property, filtered to the "Lines" category.
UPROPERTY(EditAnywhere, BlueprintReadWrite,
    meta = (Categories = "Libretto.Flags.Lines", AutoExpandFlags), Category = "Dialogue")
FLBRGameplayTagFlags LineFlags;

Cela fonctionne de la même façon sur un UPARAM pour un paramètre de fonction exposé au Blueprint :

UFUNCTION(BlueprintCallable)
void SetFlags(UPARAM(meta = (AutoExpandFlags, Categories = "Libretto.Flags.Subdialogue"))
    const FLBRGameplayTagFlags& Flags);

AutoExpandFlags

Ajoutez AutoExpandFlags (activé par défaut) pour dessiner les options en ligne sous forme de grille de cases à cocher dans le panneau de détails, plutôt qu'une liste déroulante repliée que vous devez ouvrir. Sur un FGameplayTag seul (plutôt qu'un conteneur), vous avez également besoin du méta AsFlag pour qu'il s'affiche comme un interrupteur de flag.

A Flags property in a details panel

GetCategories — un filtre dynamique

Lorsque les options valides ne forment pas une branche fixe mais dépendent du contexte, pointez vers une fonction qui renvoie la chaîne de filtrage, en utilisant GetCategories au lieu de Categories :

UPROPERTY(EditAnywhere, meta = (GetCategories = "GetSelectorsCategories", AutoExpandFlags))
FGameplayTagContainer Selectors;

La fonction nommée est résolue pour produire la liste des catégories au moment de l'édition. Libretto s'en sert, par exemple, pour filtrer un paramètre de flags « dialogue terminé » sur l'ensemble des tags de dialogue qui existent réellement :

static bool AreDialoguesDone(
    UPARAM(meta = (GetCategories = "LBRDialogueTagsSubsystem.GetAllDialogueRootTagsStringStatic"))
    const FLBRGameplayTagFlags& DialogueTags);

GameplayTagFilter sur les fonctions

Pour une UFUNCTION dont les paramètres de type gameplay tag doivent être filtrés en tant que pins Blueprint, le méta-spécificateur standard GameplayTagFilter s'applique, avec GetGameplayTagFilter comme équivalent piloté par fonction (la même association fixe vs. dynamique que Categories / GetCategories).

Info

Dans cette base de code, le filtre est le plus souvent exprimé via Categories / GetCategories. GameplayTagFilter / GetGameplayTagFilter sont reconnus par la même machinerie d'éditeur (LBRTagsEditorFunctionLibrary) ; réservez-les aux cas où vous devez spécifiquement filtrer les pins de tag d'une fonction plutôt que d'un struct/d'une propriété.

Manipuler la valeur en code

FLBRGameplayTagFlags dérive de FGameplayTagContainer, si bien que toute l'API du conteneur est directement disponible :

Opération Comment
Un flag est-il présent ? Flags.HasTag(SomeTag) (hérité du conteneur)
L'un d'un ensemble ? Flags.HasAny(OtherContainer)
Poser un flag Flags.AddTag(SomeTag) / Flags.AppendTags(Other)
Combiner A \| B (ou A \|= B) — ajoute/concatène, renvoie un LBRGameplayTagFlags
Tester l'appartenance A & SomeTag — sucre syntaxique pour HasTag ; A & Container correspond à HasAny
Défaut vide FLBRGameplayTagFlags::EmptyFlags (pratique comme paramètre par défaut)

En Blueprint, la bibliothèque de fonctions LBRTags expose les nœuds correspondants — un nœud Make Literal, un autocast depuis un simple conteneur de gameplay tags, les opérateurs + (ajout / concaténation), et les comparaisons == / != — de sorte que les flags sont aussi faciles à construire dans les graphes qu'en C++.

Tip

Puisqu'une valeur de flags est un conteneur de tags, vous pouvez la fournir à n'importe quel nœud du moteur attendant un FGameplayTagContainer, et convertir un simple conteneur en flags avec le nœud d'autocast fourni.