はじめての script
script は、オブジェクトに付ける TypeScript のファイルです。プレイヤーの中で、それを使う オブジェクトごとに 1 つずつ動きます。
これが完結した例です。オブジェクトをタップすると回りはじめます。
init((ctx) => {
const props = defineProps({
speed: { type: 'number', default: 1, min: 0, label: 'Speed' },
});
let spinning = false;
ctx.on('on-click', () => {
spinning = !spinning;
});
ctx.tick((dt) => {
if (!spinning) return;
const t = ctx.entity.getComponent(TransformComponent);
t?.update({
rotation: { ...t.$data.rotation, y: t.$data.rotation.y + props.speed * dt },
});
});
return () => {
// 任意: このオブジェクトが消えるときの後片付け
};
});
ここで起きていることは 4 つです。
init | 動いているシーンへの取っ手 ctx を受け取ります。すべてはここから始まります |
defineProps | エディターのインスペクターに出す設定を宣言します。値はオブジェクトごとに入ります |
ctx.on | トリガーを購読します。イベントや patch と同じトリガーです |
ctx.tick | 毎フレーム実行されます。dt は秒です |
init と defineProps は常に使えます。import は不要です。
オブジェクトの読み書き
const transform = ctx.entity.getComponent(TransformComponent);
transform.position; // 値を 1 つ読む
transform.$data; // 全体を素のオブジェクトとして読む
transform.update({ … }); // 書き込む
落とし穴が 2 つあり、これは全員が引っかかります。
update({ position: { y: 2 } }) は x と z も 0 にします。y だけ入った新しい position を
まるごと渡したことになるからです。
残したいものは展開してください。
transform.update({ position: { ...transform.$data.position, y: 2 } });
material.update({ color }) は何も起きません。color は最上位ではなくスロットの中にあるからです。
スロットを書いてください。
material.update({
materials: [{ ...material.$data.materials[0], color: '#ff0000' }],
});
それと、$data に直接代入してはいけません。うまくいったように見えて、変更は捨てられます。
インスペクターの設定
defineProps こそが、script を使い回す価値のあるものにします。同じ script を 10 個の
オブジェクトに付け、それぞれ別の設定にできます。コピペは不要です。
const props = defineProps({
speed: { type: 'number', default: 1, min: 0, softMax: 10, suffix: 'm/s' },
target: { type: 'entity', label: 'Look at' },
sound: { type: 'resource', resource: 'audio' },
mode: { type: 'select', options: ['chase', 'patrol'], default: 'patrol' },
});
| 型 | エディターの表示 | script が受け取るもの |
|---|---|---|
number | 入力欄またはスライダー | 数値 |
string | テキスト入力欄 | 文字列 |
boolean | スイッチ | 真偽値 |
color | カラーピッカー | 色の文字列 |
select | ドロップダウン | 指定した選択肢のどれか |
entity | オブジェクトの選択 | そのオブジェクト自体。すぐ使えます |
scene | シーンの選択 | シーンのオブジェクト |
resource | リソースの選択 | そのまま渡せる参照 |
array | リスト | 配列 |
group | 見出し付きのブロック | 入れ子のオブジェクト |
覚えておくとよいもの:パネル用の label と help、本物の上下限である min と max、手入力での
超過は許しつつスライダーの端を決める softMax、ほかの項目が特定の値のときだけ項目を出す
showWhen、そして長い一覧を整える group。
defineProps はそのまま書き下す必要がありますエディターは script を実行せずに設定を読むので、直接見えている必要があります。変数から組み立てたり、 関数から返したりしてはいけません。
値は毎回読み直されるので、props.speed は常にいまインスペクターにある値を反映します。
import する
import { TransformComponent } from '@was/engine';
import helpers from 'Scripts/helpers';
エンジンの component クラスと、パスで指定したほかのリソースを import できます。別の script
ならその export、patch ならコンパイル済みモジュール、それ以外なら ctx.spawn や
ctx.audio.play に渡せる参照が得られます。
リソースの名前を変えたり移動したりすると、これらの import は自動で追随します。
サンドボックスで使えるもの、使えないもの
script はページから隔離されて動きます。重い script が描画を止めてしまわないためです。したがって、 次のものは使えません。
window・document・DOMfetch・localStorage、あらゆるネットワークアクセス- 描画系のライブラリ。シーンは描くのではなく component を通じて変えます
- ブラウザーのタイマー。代わりに
ctx.tickを使います
代わりに使うもの:UI には
インターフェースカード、音には ctx.audio、
何かを保持するには ctx.store と globals。
script が始まるとき、止まるとき
インスタンスは、そのオブジェクトが生きていて画面にあるとき(上位に無効なものがなく、シーンが アクティブ)に作られ、そうでなくなったときに破棄されます。
on-launch は作られた直後に発火するので、取り逃すことはありません。init から返す関数が
後片付けです。購読の解除、音の停止、状態のクリアに使ってください。
エディターはシーンを描きますが、ロジックは実行しません。編集したら Preview を開いてください。 動いている体験は、次に再起動したときに編集後の script を読み込みます。
次へ: script はどこに置くか