Als Vorlage für die config.txt habe ich eine vor mir genommen. Die Einträge müssen natürlich individuell angepasst werden.
Vorbereitung der config.txt
kuid
username "Beidseitiger Trigger"
trackside 0
trainz-build 3.6
kind "scenery"
category-era "2000s;2010s"
category-region "DE"
author "callavsg"
organisation "Callavsgs Blog"
contact-email "info@pascal-wirtz.de"
contact-website "http://trainzdev.net/callavsg/"
category-class "WX"
script "trigger_zweiseitig.gs"
class "C2SidedTrigger"
trigger 1
surveyor-only 1
mesh-table
{
default
{
mesh "trigger.im"
auto-create 1
}
}
thumbnails
{
0
{
image "$screenshot$.jpg"
width 240
height 180
}
}
Display More
Das Scripting
Nun wäre es fast schon an der Zeit zu überlegen, wie wir das ganze realisieren können.
Ich denke, wir schreiben uns vorher aber unser obligatorisches Rahmenscript:
Dateiname (wie in der config.txt angegeben): trigger_zweiseitig.gs
include "Trackside.gs"
class C2SidedTrigger isclass Trackside
{
public void Init(Asset pAsset)
{
inherited(pAsset);
}
};
Wie kann man nun feststellen, daß ein Zug einen Trigger auslöst?
Die einzige Möglichkeit dies zu bewerkstelligen ist es, die Nachrichten abzufangen, die die Objekte in Trainz sich diesbezüglich schicken. Aber welche sind das?
Ein Blick auf ?Class Trigger – TrainzOnline? verrät uns, daß wir die Nachricht ?Object, Enter? im Trigger abfangen müssen, um tätig werden zu können.
Bauen wir doch diesen sog. Message-Handler ein. Ein Message-Handler ist wie ein Männelein, daß
im Computer sitzt. Immer, wenn die Nachricht, die es abfangen soll, kommt, löst dieses Männelein eine Funktion aus, die wir selbst definieren. Die Funktion muss als einzigen Parameter ein Objekt des Typs ?Message? haben. Damit können wir nicht nur abfragen, ob unser Trigger ausgelöst worden ist, sondern auch noch:
- Wer hat den Trigger ausgelöst
- Welcher Trigger wurde ausgelöst (Wird später noch wichtig!)
Schreiben wir nun unser Script dementsprechend um. Um eine Nachricht abfangen zu können brauchen wir nur einen Handler in die Init-Methode zu setzen, der die Informationen enthält welche Nachricht abgefangen werden soll. Das ist die Funktion ?AddHandler?.
Schauen wir uns das einfach mal an:
include "Trackside.gs"
class C2SidedTrigger isclass Trackside
{
void TriggerMessageHandler(Message pMsg);
public void Init(Asset pAsset)
{
inherited(pAsset);
// "Object, Enter"-Nachrichten abfangen
AddHandler(me, "Object", "Enter", "TriggerMessageHandler");
}
void TriggerMessageHandler(Message pMsg)
{
}
};
Display More
Dieses Script macht nichts anderes, als daß es auf die Nachricht: ?Object, Enter? reagiert.
Bekommt das Script eine solche Nachricht, wird die Funktion ?TriggerMessageHandler? aufgerufen.
(siehe AddHandler, Zeile 012). Der erste Parameter ?me? ist ein Verweis auf das aktuelle Objekt, bzw. auf die aktuelle Instanz der Klasse ?C2SidedTrigger?. Das sagt der AddHandler-Methode, dass der MessageHandler für das aktuelle Objekt gesetzt wird. Wir können so auch Nachrichten für andere Objekte abfangen. Das soll aber hier nicht Thema sein
Die Funktion ?TriggerMessageHandler? ist noch leer. Das ändern wir jetzt. Wichtig ist nämlich, daß wir noch einmal abfragen, ob die Nachricht für den aktuellen Trigger ist. Das ?me? in AddHandler sagt nämlich nicht aus, daß nur Nachrichten abgefangen werden, die an das aktuelle Objekt geschickt werden.
Außerdem gibt es die Möglichkeit eine solche Nachricht an alle Objekte auf der Strecke zu senden (broadcasting). Das ist aber auch nicht Thema. Wichtig ist eben nur, daß wir diese Abfrage einbauen.
Damit der Code übersichtlich bleibt, ist es von Vorteil für die Prozesse, die wir durchführen, wenn wir erkannt haben, daß ein Zug den Trigger ausgelöst hat, eine eigene Methode zu schreiben, die heißen könnte: ?TriggerEvent?. Als Parameter könnten wir ihr ein GameObject geben, das das auslösende Objekt enthält. Also ändern wir unser Script wie folgt:
include "Trackside.gs"
class C2SidedTrigger isclass Trackside
{
void TriggerMessageHandler(Message pMsg);
void TriggerEvent(GameObject pTriggeredObject);
public void Init(Asset pAsset)
{
inherited(pAsset);
// "Object, Enter"-Nachrichten abfangen
AddHandler(me, "Object", "Enter", "TriggerMessageHandler");
}
void TriggerMessageHandler(Message pMsg)
{
// Abfragen, ob die Nachricht für dieses Objekt ist
// Wenn nicht, die Funktion mit "return" abbrechen
if(pMsg.dst != me)return;
// Die Funktion wurde noch nicht abgebrochen?
// Ein Zug hat tatsächlich diesen Trigger ausgelöst
// Dann die Methode TriggerEvent aufrufen
// Der Member "src" aus der Message-Klasse enthält einen Verweis auf das
// GameObject des auslösenden Objekts. Also genau passend für unser TriggerEvent
TriggerEvent(pMsg.src);
}
void TriggerEvent(GameObject pTriggeredObject)
{
// TODO: Hier kannst du deine gewünschten Funktionen einbauen, die
// abgearbeitet werden, wenn ein Zug diesen Trigger auslöst
// Ich habe mich für eine einfache Nachricht ins Nachrichtenfenster entschieden,
// die uns mitteilt, welche Identifikationsnummer das GameObject des auslösenden Zuges hat
Interface.Print("Train-ID: " + pTriggeredObject.GetId());
}
};
Display More
Die Kommentare im Quellcode erklären eigentlich ziemlich alles genau.
Darum hier nochmal eine Übersicht über den Ablauf des Scripts:
Init: Das Objekt wird initialisiert, es wird ein Message-Handler mit AddHandeler eingerichtet.
Die Nachricht: ?Object, Enter? wird geschickt, sobald ein Objekt in den Trigger-Radius einfährt.
Danach wird sofort überprüft, ob der es sich überhaupt um den jeweiligen Trigger handelt, wenn ja, wird die Funktion ?TriggerEvent? aufgerufen, die dann den Code abarbeitet, der die gewünschte Funktion nach dem Auslösen bringt.
Damit wäre der beidseitige Trigger fertig.
Dieses Beispiel gibt es hier einmal als fertiges Objekt: