スクリプト・エディター
ゲームスクリプトを編集するには、ゲームの詳細ページにある "Mod (API) Scripts "リンクをクリックしてください("Chat Log "や "Copy/Extend Game "などのオプションがある場所と同じです)。 いくつかの機能が表示されます:
- 上部に並ぶタブのリスト。 あなたのゲームは、整理しやすいように複数のスクリプトを持つことができます。 つまり、複数のスクリプトが同時に同じ値を上書きしようとすると、意図しない結果になる可能性があります。
- スクリプト・コード・エディター。 このエディターを使うか、外部エディターでスクリプトを編集し、ここに貼り付けることができる。
- 下部にある「MOD(API)コンソール」(下図参照)。
Save Scripts "ボタンをクリックするたびに、ゲームのサンドボックスは再起動されます(ステート
オブジェクトやRoll20オブジェクトに保存されていないインメモリデータは失われます)。 これは、新しいスクリプトを追加したり、スクリプトを削除したり、スクリプトの有効/無効を切り替えたりする場合にも適用されます。
MOD(API)コンソール
MOD(API)コンソールはスクリプトの「窓」です。 MOD(API)スクリプトはサンドボックス内で実行されるため、スクリプトの結果やエラーに関する情報を表示するために、実行中のスクリプトに直接アクセスすることはできません。 MOD(API)コンソールはこの情報をサンドボックスの外に表示するので、スクリプトを編集している間でも情報を見ることができます。 すべてのlog()
コマンドは、スクリプトの実行中に発生したエラーと同様に、ここに表示される。 詳しくは スクリプトのデバッグ.
リアクティブ・スクリプトイベントを聞き、オブジェクトを修正する
MOD(API)の使い方の最初の(そして最も単純な)タイプは、卓上の変更に反応し、変更されたオブジェクトに追加機能で応答することである。 このタイプのスクリプトは、ゲーム中に起こるイベントをリッスンするいくつかの関数で構成される。 そして、それらのイベント中に渡されるオブジェクトを修正し、卓上で起こることを変化させる。
駒をさらに5フィート移動させる基本的なスクリプトは次のようになる(デフォルトのページ設定を想定):
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + 70
});
});
ご覧のように、change:graphicイベントが発生するたびに実行されるシンプルなon関数を作りました。 この関数にはグラフィックオブジェクト obj が渡されます。 変更を加えるには、set関数を使ってobjを変更するだけだ。
setと
getを
使わなければなりません。 (オブジェクト・タイプとそのプロパティの一覧、すべてのイベントと各イベントに渡される引数の一覧は以下を参照のこと)効用関数についてのノート
もちろん、先ほどの例は、トークンの位置に常に70ピクセルを追加しているため、あまり参考にはならない。 しかし、もしユーザーが縮尺を変更し、5ftが140ピクセルになったとしたら? Roll20 API は、このような (そしてその他の) よくあるシナリオを支援する便利なユーティリティ関数をいくつか提供しています。 distanceToPixels関数を
使うと、卓上の「5フィート」(またはインチ、メートル、その他設定されている距離の種類に関わらず)が何ピクセルかを教えてくれる。
on("change:graphic", function(obj) {
obj.set({
left: obj.get("left") + distanceToPixels(5);
});
});
もし現在のページがデフォルトのグリッドサイズを使用するように設定されている場合、distanceToPixels(5);
は70ピクセルを返しますが、ページが通常の2倍の大きさに設定されている場合は140ピクセルを返します。
ページやトークンの設定が変わってもスクリプトが壊れないようにするために、ユーティリティ関数を利用できるときはいつでも利用することをお勧めします。
プロアクティブスクリプト:ユーザーの介入なしに物事を行う
ユーザーイベントに反応するだけでなく、プレイヤーからの特定のイベントに結びつかないことをAPIで自動的に行うこともできます。 例えば、マップを行ったり来たりするトークンがいるとする。
注意:このタイプのスクリプトはユーザーとの対話に依存しませんが、ゲームのMod(API)スクリプトは、少なくとも1人がゲームに接続している場合にのみ実行されます。
on("ready", function() {
//ゲームが完全にロードされたことを知るために、readyイベントが発生するまで待つ。
//パトロール中のトークンへの参照を取得する。
var patroltoken = findObjs({_type: "graphic", name: "Guard A"})[0]; //ゲーム内に「Guard A」というトークンがあることがわかる。
var direction = -1*distanceToPixels(5); //左に70ピクセル歩く。
var stepstaken = 0; //現在の方向に何歩歩いたか?
setInterval(function() {
if(stepstaken > 3) {
//方向を切り替える!
direction = direction * -1; //歩く方向を「反転」させる
stepstaken = 0; //歩数を0に戻す。
}
patroltoken.set("left", patroltoken.get("left") + direction); //歩く!
stepstaken++;
}, 5000); //5秒ごとにアクションを取る
});
非同期関数論
非同期関数とは、制御のスレッドを呼び出し元のスコープに即座に返し、バックグラウンドで何らかの処理を行うものである。 MOD(API)スクリプト・タブに貼り付けることができる、非常にシンプルでわかりやすい例です:
on('load',function(){
log('Parent Scope - Before call to asynchronous function.');
setTimeout(function(){
log('Asynchronous Function Scope - Doing the Asynchronous function work.');
},10 /* 10 milliseconds */);
log('Parent Scope - after call to asynchronous function.');
});
Mod (API)のログには、次のようなものがある:
"親スコープ-非同期関数呼び出し前" "親スコープ-非同期関数呼び出し後" "非同期関数のスコープ-非同期関数の仕事をする"
そのコードを見て、あなたは「もちろん後で起こることだ。 以下は、同じログメッセージを持つ、あまり目立たない例である:
on('load',function(){
log('Parent Scope - Before call to asynchronous function.');
sendChat('Async Function','Evaluate this:[[1d6]]',function(msg){
log('非同期関数のスコープ - 非同期関数の処理を行います。');
});
log('親スコープ - 非同期関数の呼び出し後。');
非同期関数は、APIが常にハングアップするのを防ぐために必要である。 もしすべてのサイコロの出目が同期的に処理されるなら、APIは超スローになり、反応しなくなるだろう。 コールバックを受け取る関数のほとんどは非同期だ。 (_.map、_.reduceなどの一部の関数を除いて、これらは関数型プログラミングの例であり、多くの人が慣れ親しんでいる手続き型プログラミングとは対照的である)