Inputs et outputs dans Hammer : relier un bouton à une porte
Inputs et outputs dans Hammer : les champs de l’onglet Outputs, un exemple bouton et porte, !activator, logic_relay et le débogage avec ent_fire.
Dans Hammer, tu relies les entités entre elles par des outputs et des inputs : un output d’une entité déclenche un input d’une autre, et la cible est trouvée par son nom (targetname). Pour un bouton qui ouvre une porte, tu donnes un nom à la porte et tu ajoutes au func_button l’output OnPressed avec l’input Open de la porte. Une connexion de ce genre casse le plus souvent à cause d’un nom mal tapé ou utilisé deux fois, d’une cible qui a été supprimée, ou de deux outputs qui arrivent au même moment.
Comment outputs et inputs s’articulent
Un output est un événement qu’une entité signale : un bouton a été pressé, une porte est complètement ouverte, quelqu’un est entré dans un trigger. Un input est une commande qu’une entité accepte, par exemple Open, Close ou Kill. Les outputs et les inputs dont dispose une classe sont définis dans le FGD.
Chaque output déclenché est placé dans une file d’événements à l’intérieur du moteur et délivré après le délai que tu as réglé. C’est seulement à ce moment-là que le moteur cherche la cible par son nom. Deux informations voyagent avec lui : l’activator, en général l’entité qui a lancé la chaîne (pour un bouton, le joueur), et le caller, l’entité dont l’output se déclenche.
Tu définis le nom dans le champ Name des Object Properties (Alt+Enter). Une entité sans nom peut envoyer des outputs, mais elle ne peut être ciblée que par son classname ou par une cible spéciale comme !activator. Les bases de l’éditeur sont expliquées dans débuter avec Hammer Editor.
Les champs de l’onglet Outputs
Dans l’onglet Outputs des Object Properties, tu crées une connexion avec Add.... Dans le Hammer fourni avec GMod, les champs de saisie et les colonnes de la liste portent des libellés légèrement différents :
| Champ | Colonne | Signification |
|---|---|---|
My output named | My Output | L’événement de cette entité qui déclenche la connexion |
Targets entities named | Target Entity | Nom de la cible, ou bien un classname, un wildcard ou une cible spéciale |
Via this input | Target Input | La commande que la cible exécute |
With a parameter override of | Parameter | Valeur pour l’input, s’il en attend une |
After a delay in seconds of | Delay | Temps d’attente entre l’événement et la livraison |
Fire once only | Once | La connexion est supprimée après s’être déclenchée une fois |
Hammer++ remplace la case à cocher par le champ Limit to this many fires ( -1 = infinite ) et la colonne « Refires ». L’onglet Inputs montre le sens inverse, c’est-à-dire toutes les connexions qui pointent vers cette entité. Mark saute à l’autre extrémité.
Exemple : un bouton ouvre une porte puis la referme
- Construis la porte sous forme de brush, appuie sur
Ctrl+Tet choisisfunc_door. Nomme-ladoor_1. - Règle
Move Direction (Pitch Yaw Roll)sur la direction d’ouverture etDelay Before Reset (-1 stay)sur-1. La porte reste alors ouverte. - Dans l’onglet
Flags, décocheTouch Opens. Il est coché par défaut et ouvrirait la porte au contact. - Construis le bouton sous forme de brush et transforme-le en
func_button. Le flagUse Activatesest déjà activé. AvecDelay Before Reset (-1 stay)réglé sur5, il ne peut pas être pressé de nouveau avant au moins cinq secondes. - Dans l’onglet
Outputsdu bouton, ajoute deux connexions :
My Output Target Entity Target Input Parameter Delay
OnPressed door_1 Open 0.00
OnPressed door_1 Close 5.00
La porte s’ouvre immédiatement et se referme cinq secondes après l’appui. Ça marche aussi sans la deuxième connexion : une porte dont Delay Before Reset vaut 5 se referme toute seule. La façon d’appeler un ascenseur selon le même schéma est expliquée dans l’article sur les ascenseurs et les trains.
Cibles spéciales et briques logiques
À la place d’un nom, le champ de cible peut contenir une cible spéciale :
| Cible | Signification |
|---|---|
!activator | L’entité qui a lancé la chaîne, par exemple le joueur au bouton |
!caller | L’entité dont l’output se déclenche |
!self | Comme cible, identique à !caller ; comme paramètre, l’entité qui reçoit l’input |
!player | Le joueur ; en multijoueur, le premier à avoir rejoint le serveur |
!picker | L’entité sous le viseur, prévue pour le débogage |
Sur un serveur, !player n’est donc presque jamais le bon choix. Utilise !activator pour le joueur qui a déclenché la chaîne, ou le classname player pour tout le monde. Les wildcards ne fonctionnent qu’à la fin : door_* correspond à tous les noms qui commencent par door_. Un motif comme *_door ne fonctionne pas, car le moteur ignore tout ce qui suit le *. Un classname comme func_door est lui aussi une cible valide, sauf si une entité porte exactement ce texte comme nom.
Quelques entités logiques permettent d’en faire des circuits plus grands :
logic_relayregroupe plusieurs outputs sous un seul nom : inputTrigger, outputOnTrigger.Disableinterrompt la chaîne,CancelPendingabandonne les événements du relais encore en attente. Tant que des outputs retardés sont en attente, il ne peut pas être déclenché de nouveau, sauf si le flagAllow fast retriggerest activé.logic_timerdéclencheOnTimerau rythme de sonRefire Interval.math_countercompte avecAddetSubtractet déclencheOnHitMaxouOnHitMindès qu’une limite est atteinte.trigger_multipleest un volume avecOnStartTouch,OnEndTouchetOnTrigger. Les flags etFilter Name, avec unfilter_activator_nameou unfilter_activator_class, définissent qui peut le déclencher.
Déboguer en jeu
Avant la compilation, Map > Check for Problems (Alt+P) liste les entités dont les connexions sont invalides. En jeu, ces commandes console t’aident :
developer 2
ent_messages_draw 1
ent_fire door_1 Open
ent_fire !picker Kill
developer 2écrit chaque output et chaque input dans la console.dumpeventqueueliste les événements qui attendent encore la fin de leur délai.ent_messages_draw 1affiche les mêmes messages dans le monde 3D, au niveau des entités.ent_fire <target> <input> [parameter] [delay]déclenche un input à la main. Tu peux ainsi tester la cible indépendamment de ce qui la déclenche.
Teste en solo ou en tant qu’hôte, car d’après le wiki de Valve, un client connecté à un serveur ne peut pas utiliser ent_fire. Si la console réclame les cheats, tape d’abord sv_cheats 1. Avec developer 2, les lignes de la console suivent le modèle ci-dessous. Le bloc est assemblé à partir des formats de message de la server.dll de GMod, avec les noms de l’exemple et un temps inventé. Ce n’est pas l’enregistrement d’une vraie session :
(12.50) output: (func_button,button_1) -> (door_1,Open)()
(12.50) input button_1: door_1.Open()
unhandled input: (Open) -> (door_2), from (func_button,button_1); target entity not found
La première ligne est l’output qui se déclenche, la deuxième sa livraison. C’est la troisième qu’il faut repérer : elle apparaît quand aucune entité ne porte le nom de la cible au moment de la livraison, dans cette illustration door_2.
Erreurs typiques
- Nom manquant ou mal tapé : Hammer affiche la cible en rouge, et « Check for Problems » signale la connexion. N’y utilise pas « Fix » à l’aveugle : d’après le texte de l’erreur, Hammer supprime les connexions fautives au lieu de les réparer. Les wildcards et les classnames apparaissent eux aussi en rouge alors qu’ils fonctionnent en jeu.
- Nom utilisé deux fois : Hammer affiche la cible en gras. L’input part vers toutes les entités qui portent ce nom. C’est voulu pour deux battants de porte, pas pour une porte copiée dans la pièce voisine.
- Cible supprimée :
Killsupprime une entité avec ses enfants dans la hiérarchie de parents. Les outputs retardés qui arrivent ensuite tombent dans le vide, et l’entité supprimée ne déclenche plus aucun nouvel output. Il se passe la même chose avec!activatorsi le joueur quitte le serveur avant. - Courses de timing : Deux outputs avec le même délai arrivent dans le même tick. Ne te fie pas à leur ordre. Si B dépend de A, donne un petit délai à B. Le wiki de Valve utilise au moins 0,02 seconde dans un tel cas.
Les outputs peuvent aussi déclencher une lua_run, qui exécute alors du code Lua. Le Map Scanner trouve ce genre d’entités à risque dans un BSP. D’autres vérifications sont listées dans l’article sur la vérification d’un BSP avant publication.
Questions fréquentes
Un output peut-il s’adresser à plusieurs entités à la fois ?
Oui. L’input part vers chaque entité à laquelle la cible correspond : un nom partagé, un wildcard comme door_* ou un classname.
Quelle est la différence entre OnPressed et OnIn sur un func_button ?
OnPressed se déclenche dès que le bouton est pressé. OnIn ne se déclenche qu’une fois que le bouton a atteint sa position finale enfoncée, et OnOut quand il est revenu à sa position de départ.
Puis-je modifier des outputs pendant que le jeu tourne ?
Oui, avec l’input AddOutput. Le format est <output> <target>:<input>:<parameter>:<delay>:<max times to fire>. Le FGD le qualifie de « very dangerous, use with care », et les circuits qui se recâblent eux-mêmes en jeu sont difficiles à suivre par la suite.