Der Skripteditor
Um Ihre Spielskripte zu bearbeiten, klicken Sie auf der Seite „Spieldetails“ für Ihr Spiel auf den Link „API-Skripte“ (dort, wo sich Optionen wie „Chat-Protokoll“ und „Spiel kopieren/erweitern“ befinden). Ihnen werden mehrere Funktionen präsentiert:
- Eine Liste mit Registerkarten oben. Zur Vereinfachung der Organisation kann Ihr Spiel über mehrere Skripte verfügen. Beachten Sie, dass alle Skripte weiterhin im selben Kontext ausgeführt werden. Das bedeutet, dass nicht mehrere Skripte gleichzeitig versuchen sollten, dieselben Werte zu überschreiben, da es sonst zu unbeabsichtigten Ergebnissen kommen könnte.
- Ein Skriptcode-Editor. Sie können diesen Editor verwenden oder Ihre Skripte in einem externen Editor Ihrer Wahl bearbeiten und sie dann hier einfügen.
- Unten befindet sich eine „API-Konsole“ (siehe unten).
Immer wenn Sie auf die Schaltfläche „Skripte speichern“ klicken, wird die Sandbox für Ihr Spielneu gestartet(alle Speicherdaten gehen verloren, die nicht imStatus-
Objekt oder in Roll20-Objekten gespeichert wurden). Dies gilt auch, wenn Sie ein neues Skript hinzufügen, ein Skript löschen oder ein Skript umschalten, um es zu aktivieren/deaktivieren.
Die API-Konsole
Die API-Konsole ist das „Fenster“ zu Ihren Skripten. Da API-Skripte in einer Sandbox ausgeführt werden, haben Sie während der Ausführung keinen direkten Zugriff darauf, um Informationen zu den Ergebnissen oder Fehlern des Skripts anzuzeigen. Die API-Konsole zeigt diese Informationen aus der Sandbox an, sodass Sie sie anzeigen können, während Sie Ihre Skripts bearbeiten. Hier werden allelog()
Befehle sowie alle Fehler angezeigt, die während der Ausführung Ihrer Skripte auftreten. Weitere Informationen finden Sie im Artikelzum Debuggen von Skripts.
Reaktive Skripte: Ereignisse abhören, Objekte ändern
Die erste (und einfachste) Art der API-Nutzung besteht darin, auf Änderungen auf dem Tabletop zu reagieren und dann mit zusätzlichen Funktionen auf die geänderten Objekte zu reagieren. Diese Art von Skript besteht aus einer Reihe von Funktionen, die Ereignisse überwachen, die während des Spiels passieren. Anschließend werden die während dieser Ereignisse übergebenen Objekte geändert, wodurch sich das Geschehen auf der Tischplatte ändert.
Ein einfaches Skript, das ein Stück um weitere 5 Fuß verschiebt (unter der Annahme der Standardseiteneinstellungen), wäre:
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + 70
});
});
Wie Sie sehen können, haben wir eine einfache On-Funktion erstellt, die immer dann ausgeführt wird, wenn das Ereignis „change:graphic“ ertönt. Der Funktion wird das Grafikobjekt obj übergeben. Um eine Änderung vorzunehmen, ändern wir einfach obj mit der Set-Funktion – alle Eigenschaften, die wir ändern, werden auf der Tischplatte erkannt und geändert.
set
undget
verwenden, um aktuelle Werte für Objekte festzulegen und abzurufen, sonst werden Ihre Änderungen nicht gespeichert. (Siehe unten für eine Auflistung der Objekttypen und ihrer Eigenschaften sowie eine Auflistung aller Ereignisse und der Argumente, die jedem Ereignis übergeben werden.)Ein Hinweis zu Utility-Funktionen
Natürlich ist das vorherige Beispiel nicht besonders hilfreich, da es der Position des Tokens immer 70 Pixel hinzufügt. Was aber, wenn der Benutzer den Maßstab so geändert hat, dass 5 Fuß 140 Pixel entspricht? Die Roll20-API bietet mehrere praktische Hilfsfunktionen, die bei diesem (und anderen) häufigen Szenarios helfen. Ändern wir unser vorheriges Beispiel, um diedistanceToPixels-Funktion
zu verwenden, die uns sagt, wie viele Pixel „fünf Fuß“ (oder Zoll, oder Meter, oder was auch immer für einen anderen Abstandstyp festgelegt wurde) auf der Tischplatte sind.
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + distanceToPixels(5);
});
});
Wenn nun die aktuelle Seite so eingerichtet ist, dass sie die Standard-Rastergröße verwendet,distanceToPixels(5);
gibt immer noch 70 Pixel zurück, aber wenn die Seite so eingerichtet ist, dass sie eine doppelt so große Skalierung wie normal hat, würde sie 140 zurückgeben.
Es ist immer eine gute Idee, Hilfsfunktionen zu verwenden, wann immer sie verfügbar sind, um zu verhindern, dass Ihr Skript abstürzt, wenn sich die Einstellungen einer Seite oder eines Tokens ändern.
Proaktive Skripte: Dinge ohne Benutzereingriff erledigen
Neben der Reaktion auf Benutzerereignisse können Sie mit der API auch automatisch Dinge tun, die nicht an ein bestimmtes Ereignis der Spieler gebunden sind. Nehmen wir zum Beispiel einen Token an, der auf der Karte hin und her patrouilliert.
Hinweis: Obwohl diese Art von Skript nicht von der Benutzerinteraktion abhängig ist, werden die API-Skripte für Ihr Spiel dennoch nur ausgeführt, wenn mindestens eine Person mit Ihrem Spiel verbunden ist.
on("ready", function() {
//Warten Sie, bis das Ready-Ereignis ausgelöst wird, damit wir wissen, dass das Spiel vollständig geladen ist.
//Erhalten Sie eine Referenz auf unser Patrouillen-Token.
var patroltoken = findObjs({_type: "graphic", name: "Guard A"})[0]; //Wir wissen, dass es im Spiel einen Token namens „Guard A“ gibt.
var Direction = -1*distanceToPixels(5); //Gehe 70 Pixel nach links.
varstepstaken = 0; //Wie viele Schritte sind wir in der aktuellen Richtung gegangen?
setInterval(function() {
if(stepstaken > 3) {
//Richtung wechseln!
Richtung = Richtung * -1; //wird die Richtung, in die wir gehen, „umdrehen“ 0stepstaken =
; //reset geht auf 0 zurück.
}
patroltoken.set("left", patroltoken.get("left") + Richtung); //gehen!
Schritte gemacht++;
}, 5000); //alle 5 Sekunden eine Aktion ausführen
});
Eine Abhandlung über asynchrone Funktionen
Eine asynchrone Funktion ist eine Funktion, die den Steuerungsthread sofort an den aufrufenden Bereich zurückgibt und im Hintergrund bestimmte Aufgaben ausführt. Hier ist ein sehr einfaches und leicht verständliches Beispiel, das Sie in eine API-Skript-Registerkarte einfügen können:
on('load',function(){
log('Übergeordneter Bereich – Vor Aufruf der asynchronen Funktion.');
setTimeout(function(){
log('Asynchroner Funktionsbereich – Ausführung der asynchronen Funktion.');
},10 /* 10 Millisekunden */);
log('Übergeordneter Bereich – nach Aufruf der asynchronen Funktion.');
});
Im API-Protokoll sehen Sie etwa Folgendes:
„Übergeordneter Bereich – Vor dem Aufruf einer asynchronen Funktion.“ „Übergeordneter Bereich – nach Aufruf der asynchronen Funktion.“ „Asynchroner Funktionsumfang – Ausführung der asynchronen Funktion.“
Wenn Sie sich diesen Code ansehen, denken Sie: „Natürlich wird es später passieren, Sie haben gesagt, dass es in 10 Millisekunden ausgeführt werden soll, oder?“ Hier ist ein weniger offensichtliches Beispiel, das dieselben Protokollmeldungen enthält:
on('load',function(){
log('Parent Scope – Vor Aufruf der asynchronen Funktion.');
sendChat('Async Function','Evaluate this: [[1d6]]',function(msg){
log ('Asynchroner Funktionsbereich – Ausführen der asynchronen Funktion.');
});
log('Übergeordneter Bereich – nach Aufruf der asynchronen Funktion.');
Asynchrone Funktionen sind erforderlich, um zu verhindern, dass die API ständig hängt. Wenn jeder Würfelwurf synchron verarbeitet würde, wäre die API sehr träge und reagiert nicht. Fast jede Funktion, die einen Rückruf annimmt, ist asynchron. (Mit Ausnahme einiger der Funktionen _.map, _.reduce usw. handelt es sich hierbei um Beispiele funktionaler Programmierung im Gegensatz zur prozeduralen Programmierung, an die die meisten Menschen gewöhnt sind.)