Mapping et Hammer

Ascenseurs et trains dans Hammer : de func_door à func_tracktrain

Ascenseurs et trains dans les maps Source et GMod : quelle entité choisir, keyvalues, boutons d’appel, parcours path_track, causes d’écrasement et de saccades.

Tu construis un ascenseur à deux arrêts à partir d’un func_door ou d’un func_movelinear, et plusieurs étages ou des trains à partir d’un func_tracktrain qui suit une chaîne d’entités path_track. Les joueurs se font écraser quand une valeur de dégâts de blocage est définie et que l’entité continue de pousser alors qu’elle est bloquée. Les saccades pendant le trajet sont décrites par le wiki de Valve comme une caractéristique générale des plateformes à déplacement vertical dans les jeux Source multijoueurs. Il n’indique aucun correctif, alors teste l’ascenseur tôt. Un ascenseur reste en général bloqué parce que quelque chose se trouve sur son chemin ou que le parcours est mal chaîné.

Quelle entité pour quel usage

EntitéMouvementConvient pourLimites
func_doorentre deux positions, distance = taille du brush moins Lipascenseur simple à deux arrêtsne peut pas s’arrêter entre les deux
func_movelinearle long d’une direction sur Move Distance, n’importe quelle position intermédiaire via SetPositionascenseur à deux arrêts, plateformes, portailsbugué d’après le wiki de Valve quand il est parenté à un autre func_movelinear
func_tracktrainle long d’une chaîne de path_trackplusieurs étages, trains, viragesplus de travail, s’arrête légèrement avant sa cible à vitesse plus élevée

func_tanktrain est un train qui tire sur le joueur et qui peut être tué, il ne convient donc pas ici. func_train et func_plat ne figurent pas dans le FGD de GMod.

Un ascenseur à deux arrêts

Un func_movelinear est ce qui demande le moins de travail :

  1. Construis le plancher de la cabine sous forme de brush, appuie sur Ctrl+T et choisis func_movelinear. Nom : lift.
  2. Règle Move Direction (Pitch Yaw Roll) sur Up. Le champ affiche alors -90 0 0.
  3. Saisis sous Move Distance la distance entre les deux sols, en unités, et sous Speed la vitesse.
  4. Construis les murs et le plafond de la cabine sous forme de func_brush et saisis le nom lift sous Parent.
  5. Place un func_button à chaque étage comme bouton d’appel et relie-le à l’ascenseur.
Entity        My Output       Target Entity   Target Input
button_up     OnPressed       lift            Open
button_down   OnPressed       lift            Close
lift          OnFullyOpen     door_top        Open
lift          OnFullyClosed   door_bottom     Open

Open envoie l’ascenseur jusqu’à la position finale, Close le ramène à la position de départ. OnFullyOpen et OnFullyClosed signalent l’arrivée, et c’est avec eux que tu ouvres les portes palières. Le fonctionnement détaillé des outputs, des délais et des noms est expliqué dans l’article sur les inputs et outputs dans Hammer.

Avec un func_door, le calcul est différent : une porte se déplace toujours de la taille de son propre brush, moins Lip. Un plancher de 16 unités d’épaisseur qui doit monter de 256 unités a donc besoin d’un Lip de -240. Ajoute Delay Before Reset (-1 stay) réglé sur -1, le flag Toggle et Touch Opens décoché.

Portes et boutons sur la cabine

Tout ce qui doit accompagner le mouvement reçoit le nom de l’entité mobile dans son champ Parent. Un enfant garde son décalage par rapport au parent et suit chaque mouvement.

  • Portes de cabine : deux entités func_door avec Parent = lift. N’utilise pas un deuxième func_movelinear ici, à cause du bug de parenting du tableau.
  • Boutons dans la cabine : func_button avec Parent = lift. Avec le flag Don't move, le bouton ne s’enfonce pas dans le mur quand on le presse.
  • Verrouiller les boutons : Sur OnPressed, envoie l’input Lock à tous les boutons (lift_button*), puis de nouveau Unlock sur OnFullyOpen et OnFullyClosed.
  • Outils Sandbox : Le FGD de GMod propose Allow Physics Gun et Sandbox Tool Whitelist pour ces entités. Règle le premier sur No pour que personne en Sandbox n’attrape l’ascenseur avec le Physics Gun.

Trains et plusieurs étages avec func_tracktrain

  1. Place le premier path_track et donne-lui un nom comme track_1. Si tu le clones en maintenant Shift enfoncé, Hammer incrémente le nom et remplit Next Stop Target tout seul.
  2. Construis le train de façon que son avant pointe le long de l’axe X, vers la droite dans la vue de dessus. Au spawn, il se tourne vers le path_track suivant.
  3. Transforme-le en func_tracktrain et saisis le premier path_track sous First Stop Target. Le train spawne à cet endroit.
  4. Max Speed (units / second) plafonne toutes les vitesses. Initial Speed (units / second) à 0 signifie que le train est d’abord à l’arrêt.
  5. Active le flag No User Control. Pour un ascenseur, ajoute Fixed Orientation afin que la cabine ne pivote pas.
  6. Démarre-le avec l’input StartForward. À un arrêt, le path_track envoie Stop au train via OnPass.

Pour une boucle, saisis le premier path_track comme Next Stop Target du dernier. New Train Speed sur un path_track modifie la vitesse à partir de ce point, mais n’a d’effet qu’avec No User Control.

Dans GMod, func_tracktrain possède aussi l’input MoveToPathNode. Il se rend au path_track indiqué sur le même parcours et s’y arrête. Un ascenseur à nombreux étages devient ainsi simple :

Entity          My Output                    Target Entity   Target Input     Parameter   Delay
button_floor3   OnPressed                    lift_door       Close                        0.00
button_floor3   OnPressed                    lift            MoveToPathNode   floor_3     1.00
lift            OnArrivedAtDestinationNode   lift_door       Open                         0.00

Le wiki de Valve mentionne deux autres particularités : un func_tracktrain ne met à jour sa direction que dix fois par seconde, si bien que les trains rapides dépassent le tracé dans les virages serrés. Et Reverse ou StartBackward peuvent échouer si New Train Speed vaut 0 sur les entités path_track concernées.

Pourquoi les ascenseurs écrasent, saccadent ou restent bloqués

Écrasement. Chacune des trois entités a sa propre valeur de dégâts : Blocking Damage sur func_door, Block Damage sur func_movelinear, Damage on Crush sur func_tracktrain. La valeur par défaut est 0 partout. Pour la porte et func_movelinear, le FGD indique la valeur par frame, de petits nombres tuent donc vite. Le comportement de l’entité quand elle est bloquée se lit dans le code public du Source SDK : un func_door repart en sens inverse, sauf si Delay Before Reset est négatif ou si Force Closed est activé. Un func_movelinear ne repart jamais en sens inverse et continue de pousser. Avec 0, l’ascenseur n’inflige aucun dégât de blocage, mais un joueur dans la cage peut le retenir. Donc soit tu gardes 0 et tu fermes la cage avec des portes palières qui ne s’ouvrent qu’une fois l’ascenseur arrivé, soit tu définis une valeur de dégâts et tu laisses l’ascenseur gagner. Sur un func_door, tu peux réagir toi-même avec OnBlockedClosing et OnBlockedOpening.

Saccades. Le wiki de Valve indique que toute plateforme à déplacement vertical paraît saccadée à ses passagers dans les jeux multijoueurs, et donne comme raison la physique réseau des joueurs. Une astuce tirée de la page de discussion du tutoriel sur les ascenseurs du wiki de Valve, non documentée et que toutes les maps ne confirment pas : ne laisse pas les joueurs se tenir directement sur le func_tracktrain, mais sur un func_brush qui lui est parenté. Pour func_brush, le FGD décrit le keyvalue Solid BSP exactement pour ce cas, un brush dans la hiérarchie d’un objet mobile sur lequel des joueurs se tiennent. Vérifie le résultat sur un vrai serveur avec du ping, comme décrit dans tester une map GMod avec des joueurs.

Props à bord. Un prop_physics est simulé par la physique et, d’après le wiki de Valve, se comporte bizarrement quand tu le parentes. La décoration de la cabine a donc sa place sur l’ascenseur sous forme de prop_dynamic parenté. Des props physiques libres sur une plateforme en mouvement peuvent glisser et se coincer. C’est un retour d’expérience pratique, pas un comportement documenté. Les types de props sont comparés dans prop_static, prop_dynamic et prop_physics.

Blocage. Quelque chose se trouve-t-il sur le chemin ? Un path_track a-t-il le flag Disabled ou Disable train activé, ou un Next Stop Target vide ? Des boutons ont-ils été verrouillés sans jamais être déverrouillés, parce que l’ascenseur a été bloqué et que OnFullyOpen n’est jamais arrivé ? Sur un func_tracktrain, le flag Is unblockable by player aide contre les joueurs qui le bloquent.

Questions fréquentes

Pourquoi mon func_tracktrain ne s’arrête-t-il pas exactement au path_track ?

Le train s’arrête juste avant sa cible, de façon plus visible à vitesse plus élevée. Réduis la vitesse avant l’arrêt, ou déplace le path_track de la distance manquante jusqu’à ce que la cabine soit à niveau.

Pourquoi la cabine est-elle mal éclairée pendant le trajet ?

Les entités brush portent des lightmaps précalculées depuis leur position de départ, qui ne correspondent plus dès que la cabine entre dans une zone éclairée différemment. Le remède : construis la cabine visible sous forme de prop_dynamic et parente-la à un brush invisible. Plus de détails dans le guide de l’éclairage du Source Engine.

Les joueurs peuvent-ils conduire un train eux-mêmes ?

Oui, tant que le flag No User Control du train est désactivé. D’après le wiki de Valve, un joueur qui se tient sur un func_tracktrain peut alors le contrôler. Un func_traincontrols dont Train Name et Parent pointent tous deux vers le train limite cela à son brush : le joueur doit se tenir à l’intérieur de celui-ci et sur le train.