Mapping & Hammer

Hammer Inputs und Outputs: Button und Tür richtig verbinden

Inputs und Outputs in Hammer erklärt: die Felder im Outputs-Reiter, ein Button-Tür-Beispiel, !activator, logic_relay und Debugging mit ent_fire.

In Hammer verbindest du Entities über Outputs und Inputs: Ein Output des einen Entity löst einen Input eines anderen aus, und das Ziel wird über seinen Namen (targetname) gefunden. Für einen Button, der eine Tür öffnet, gibst du der Tür einen Namen und trägst beim func_button den Output OnPressed mit dem Input Open der Tür ein. Kaputt geht so eine Verbindung meist an einem vertippten oder doppelten Namen, an einem entfernten Ziel oder an zwei Outputs, die im selben Moment eintreffen.

Wie Outputs und Inputs zusammenhängen

Ein Output ist ein Ereignis, das ein Entity meldet: Ein Button wurde gedrückt, eine Tür ist ganz offen, jemand hat einen Trigger betreten. Ein Input ist ein Befehl, den ein Entity annimmt, etwa Open, Close oder Kill. Welche Outputs und Inputs eine Klasse hat, steht in der FGD.

Jeder gefeuerte Output landet als Ereignis in einer Warteschlange der Engine und wird nach der eingestellten Verzögerung zugestellt. Erst in diesem Moment sucht die Engine das Ziel anhand des Namens. Zwei Angaben reisen mit: der Activator, meist das Entity, das die Kette ausgelöst hat (beim Button der Spieler), und der Caller, das Entity, dessen Output gerade feuert.

Den Namen vergibst du im Feld Name der Object Properties (Alt+Enter). Ein Entity ohne Namen kann Outputs senden, ist als Ziel aber nur über den Klassennamen oder ein besonderes Ziel wie !activator erreichbar. Die Grundbedienung des Editors zeigt der Einstieg in den Hammer Editor.

Die Felder im Outputs-Reiter

Im Reiter Outputs der Object Properties legst du mit Add... eine Verbindung an. Im Hammer, der GMod beiliegt, heißen die Eingabefelder und die Spalten der Liste leicht unterschiedlich:

FeldSpalteBedeutung
My output namedMy OutputDas Ereignis dieses Entity, das die Verbindung auslöst
Targets entities namedTarget EntityName des Ziels, alternativ Klassenname, Wildcard oder besonderes Ziel
Via this inputTarget InputDer Befehl, den das Ziel ausführt
With a parameter override ofParameterWert für den Input, falls er einen erwartet
After a delay in seconds ofDelayWartezeit zwischen Ereignis und Zustellung
Fire once onlyOnceDie Verbindung wird nach dem ersten Feuern gelöscht

Hammer++ zeigt statt des Häkchens das Feld Limit to this many fires ( -1 = infinite ) und die Spalte „Refires“. Der Reiter Inputs zeigt die Gegenrichtung, also alle Verbindungen, die auf dieses Entity zeigen. Mit Mark springst du zum anderen Ende.

Beispiel: Button öffnet eine Tür und schließt sie wieder

  1. Baue die Tür als Brush, drücke Strg+T und wähle func_door. Gib ihr den Namen door_1.
  2. Stelle Move Direction (Pitch Yaw Roll) auf die Öffnungsrichtung und Delay Before Reset (-1 stay) auf -1. Die Tür bleibt dann offen.
  3. Entferne im Reiter Flags das Häkchen bei Touch Opens. Es ist standardmäßig gesetzt und würde die Tür schon bei Berührung öffnen.
  4. Baue den Button als Brush und mache ihn zum func_button. Das Flag Use Activates ist bereits gesetzt. Mit Delay Before Reset (-1 stay) auf 5 lässt er sich frühestens nach fünf Sekunden wieder drücken.
  5. Lege beim Button im Reiter Outputs zwei Verbindungen an:
My Output   Target Entity   Target Input   Parameter   Delay
OnPressed   door_1          Open                       0.00
OnPressed   door_1          Close                      5.00

Die Tür öffnet sofort und schließt fünf Sekunden nach dem Druck. Ohne zweite Verbindung geht es auch: Eine Tür mit Delay Before Reset auf 5 schließt von selbst. Wie du nach demselben Muster einen Lift rufst, steht im Artikel über Aufzüge und Züge.

Besondere Ziele und Logik-Bausteine

Im Zielfeld kann statt eines Namens ein besonderes Ziel stehen:

ZielBedeutung
!activatorDas Entity, das die Kette ausgelöst hat, etwa der Spieler am Button
!callerDas Entity, dessen Output gerade feuert
!selfAls Ziel dasselbe wie !caller, als Parameter das Entity, das den Input empfängt
!playerDer Spieler, im Multiplayer der erste, der dem Server beigetreten ist
!pickerDas Entity unter dem Fadenkreuz, gedacht fürs Debugging

Auf einem Server ist !player deshalb fast nie richtig. Nimm !activator für den auslösenden Spieler oder den Klassennamen player für alle. Wildcards funktionieren nur am Ende: door_* trifft jeden Namen, der mit door_ beginnt. Ein Muster wie *_door funktioniert nicht, weil die Engine alles hinter dem * ignoriert. Auch ein Klassenname wie func_door ist ein gültiges Ziel, solange kein Entity genau diesen Text als Namen trägt.

Mit wenigen Logik-Entities baust du daraus größere Schaltungen:

  • logic_relay bündelt mehrere Outputs unter einem Namen: Input Trigger, Output OnTrigger. Disable unterbricht die Kette, CancelPending verwirft die noch wartenden Ereignisse des Relais. Solange verzögerte Outputs ausstehen, lässt es sich nicht erneut auslösen, außer das Flag Allow fast retrigger ist gesetzt.
  • logic_timer feuert OnTimer im Takt des Refire Interval.
  • math_counter zählt mit Add und Subtract und feuert OnHitMax oder OnHitMin, sobald eine Grenze erreicht ist.
  • trigger_multiple ist ein Volumen mit OnStartTouch, OnEndTouch und OnTrigger. Über die Flags und über Filter Name mit einem filter_activator_name oder filter_activator_class legst du fest, wer auslösen darf.

Im Spiel debuggen

Vor dem Kompilieren listet Map > Check for Problems (Alt+P) Entities mit ungültigen Verbindungen auf. Im Spiel helfen diese Konsolenbefehle:

developer 2
ent_messages_draw 1
ent_fire door_1 Open
ent_fire !picker Kill
  • developer 2 schreibt jeden Output und jeden Input in die Konsole. dumpeventqueue listet die Ereignisse, die noch auf ihre Verzögerung warten.
  • ent_messages_draw 1 zeigt dieselben Meldungen in der 3D-Welt an den Entities.
  • ent_fire <Ziel> <Input> [Parameter] [Verzögerung] löst einen Input von Hand aus. Damit prüfst du das Ziel unabhängig vom Auslöser.

Teste im Einzelspieler oder als Host, denn laut Valve-Wiki kann ein Client, der mit einem Server verbunden ist, ent_fire nicht nutzen. Verlangt die Konsole Cheats, gib vorher sv_cheats 1 ein. Mit developer 2 folgen die Konsolenzeilen dem Muster unten. Der Block ist aus den Meldungsformaten in der server.dll von GMod zusammengesetzt, mit den Namen aus dem Beispiel und einer erfundenen Zeit. Er ist kein Mitschnitt einer echten Sitzung:

(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

Die erste Zeile ist der feuernde Output, die zweite seine Zustellung. Auf die dritte kommt es an: Sie erscheint, wenn im Moment der Zustellung kein Entity den Zielnamen trägt, in dieser Illustration door_2.

Typische Fehler

  • Name fehlt oder ist vertippt: Hammer zeigt das Ziel rot an, „Check for Problems“ meldet die Verbindung. Nutze dort „Fix“ nicht blind: Laut Fehlertext löscht Hammer die fehlerhaften Verbindungen, statt sie zu reparieren. Wildcards und Klassennamen erscheinen ebenfalls rot, obwohl sie im Spiel funktionieren.
  • Name doppelt vergeben: Hammer zeigt das Ziel fett an. Der Input geht an alle Entities mit diesem Namen. Das ist bei zwei Türflügeln gewollt, bei einer kopierten Tür im Nachbarraum nicht.
  • Ziel entfernt: Kill löscht ein Entity samt seinen Kindern in der Parent-Hierarchie. Verzögerte Outputs, die danach eintreffen, laufen ins Leere, und das entfernte Entity feuert keine neuen Outputs mehr. Dasselbe passiert mit !activator, wenn der Spieler den Server vorher verlässt.
  • Timing-Rennen: Zwei Outputs mit gleicher Verzögerung treffen im selben Tick ein. Verlass dich nicht auf ihre Reihenfolge. Hängt B von A ab, gib B eine kleine Verzögerung. Das Valve-Wiki nennt für einen solchen Fall mindestens 0,02 Sekunden.

Über Outputs lässt sich auch ein lua_run auslösen, das dann Lua-Code ausführt. Der Map Scanner findet solche riskanten Entities in einer BSP. Weitere Prüfschritte nennt der Artikel Map vor dem Release prüfen.

Häufige Fragen

Kann ein Output mehrere Entities gleichzeitig ansprechen?

Ja. Der Input geht an jedes Entity, auf das das Ziel passt: ein gemeinsamer Name, eine Wildcard wie door_* oder ein Klassenname.

Was ist der Unterschied zwischen OnPressed und OnIn beim func_button?

OnPressed feuert, sobald der Button gedrückt wird. OnIn feuert erst, wenn er seine gedrückte Endposition erreicht hat, und OnOut, wenn er wieder in der Ausgangsposition ist.

Kann ich Outputs im laufenden Spiel ändern?

Ja, mit dem Input AddOutput. Das Format lautet <Output> <Ziel>:<Input>:<Parameter>:<Verzögerung>:<maximale Auslösungen>. Die FGD nennt ihn „very dangerous, use with care“, und Schaltungen, die sich im Spiel selbst umbauen, sind später schwer zu durchschauen.