[ScriptAPI参考書] イベントの操作 構造編 #4

# 目次

- [はじめに](#はじめに)
- [イベントとは](#イベントとは)
- [イベントの種類](#イベントの種類)
    - [afterEvents](#afterevents)
    - [beforeEvents](#beforeevents)
- [イベントの扱い](#イベントの扱い)
    - [イベントの登録](#イベントの登録)
        - [登録オプション](#登録オプション)
    - [イベントの解除](#イベントの解除)
- [最後に](#最後に)

# はじめに
今回から、ScriptAPIの基本、イベントの操作を扱っていきます。
構造編ということで、ScriptAPIのイベントとは何なのか、ということについて考えたいと思います。
次回以降、どのようなイベントがあるのかを紹介していきます。

この「ScriptAPI参考書」シリーズではマインクラフト統合版のScriptAPIについて基礎から応用、例文まで詳細に解説し、ScriptAPI開発者や、ScriptAPIの開発を始めようと思っている人の助けになることを目的としています。

また、このシリーズを読むにあたって、ある程度のマインクラフトとJavaScriptの事前知識が必要になってくることがあります。

*注意: このシリーズではMinecraft Bedrock Editionを省略してマインクラフトと表記しています。*

前回: [基本的な扱い](https://qiita.com/yuki2825624/items/e62ed10a71d43903bb22)
次回: [イベントの操作 アフターイベント編](https://qiita.com/yuki2825624/items/23a857b785a50a9f9c61)

# イベントとは

先ずはじめに、プログラミングで言うイベントとは、ScriptAPIに限らず、大体のライブラリにはイベントが備わっており、そのライブラリ特有のイベントが発生した時に、そのイベントの情報をプログラム内で扱えるようにするためのものです。

例えばScriptAPIの場合では、任意のプレイヤーがチャットを送信した時や、アイテムを使った時など、限界はありますが様々な事象のデータが取得出来ます。

# イベントの種類
ScriptAPIのイベントは、`@minecraft/server`の`world`と`system`にのみ存在しており、他のモジュールにはありません。
また、`world`と`system`のどちらにも`afterEvents`と`beforeEvents`が存在しており、これらの使い分けでイベントの操作を行います。

### afterEvents
そのイベントが発生した後に実行されます。
通常、こちらのイベントを使用する事が多いです。
詳しくは次回のアフターイベント編で紹介します。

### beforeEvents
そのイベントが発生する前に実行されます。
この特性により、イベントの発生をキャンセルすることが出来ます。
例えば、チャットの送信のイベントをキャンセルすれば、メッセージの送信が取り消されるといった具合です。
但し、一部[制限](https://qiita.com/yuki2825624/items/2730a3f420f45c7c7eef#beforeevents%E3%81%AE%E4%BB%95%E6%A7%98)が存在しています。
詳しくは次々回のビフォーイベント編で紹介します。

# イベントの扱い
### イベントの登録
ScriptAPIでイベントを登録するときは、基本的に以下の様なコードが一般的です。
```js
world.afterEvents.itemUse.subscribe((ev) => {
    // evにイベントのデータが渡される
});
```
これはどのようになっているかというと、`subscribe`という関数の引数に、「`ev`という引数を持った、そのイベントが発生した際に実行される関数」を渡している形になります。`ev`にはイベントが発生した際のイベントの情報が渡されます。

:::note info
ここが少しややこしいところで、理解が出来なくてもプログラム自体は書けますが、ここが分かることで根本的な理解を得られ、大変有益なので、理解に難がある方は、「イベントハンドラ」や「イベントリスナー」等のキーワードで一度検索してみることをお勧めします。
:::

ここで使用している`ev`という引数名は、`event`の略で、ScriptAPIのイベントではよく見る引数名です。人によっては`event`や`itemUse`などと名付ける人も居ますが、ここは好みの問題ですね。
因みに、公式のJSDocでは、itemUseイベントなら`itemUse`のように、イベント名が引数になっていることが多いようです。

また、ここではアロー関数を使用していますが、当然通常の関数を渡すことも出来ます。
```js:直接関数を渡す
world.afterEvents.itemUse.subscribe(function (ev) {
    // 処理
});
```
```js:定義されている関数を渡す
function onItemUse(ev) {
    // 処理
}

world.afterEvents.itemUse.subscribe(onItemUse);
```
これは、JavaScriptではモジュールやライブラリ等を使っているとよく出てくる形で、他の場所でも活用出来るので、覚えておいて損はないでしょう。

#### 登録オプション
イベントを登録する時、第二引数としてオプションを入力出来るイベントがあります。

`playerBreakBlock`イベントが一例で、このイベントはプレイヤーがブロックを破壊した時に実行されますが、オプションを使用して特定のブロックを破壊した時のみ実行させることが出来ます。
```js
world.afterEvents.playerBreakBlock.subscribe((ev) => {
    // 処理
}, {
    blockTypes: [
        // どのブロックを破壊した時にイベントを実行させるかを指定出来る
    ]
});
```

### イベントの解除
実際にモジュールを入れて書いた経験がある方は既知かもしれませんが、`subscribe`ともう一つ`unsubscribe`というメソッドがあります。
このメソッドは名前の通り、イベントの登録を解除するためのもので、登録時に渡した関数を引数に入れることで、その関数の登録を解除することができます。
```js
function onItemUse(ev) {
    // 処理
}

world.afterEvents.itemUse.subscribe(onItemUse); // イベントの登録

world.afterEvents.itemUse.unsubscribe(onItemUse); // イベントの登録の解除
```
例えば、以下のようにすることで、一度だけイベントを拾う関数を簡単に作成することができます。
```js
function onceItemUse(ev) {
    // 処理
    
    world.afterEvents.itemUse.unsubscribe(onceItemUse); // イベントの解除
}

world.afterEvents.itemUse.subscribe(onceItemUse); // イベントの登録
```
実行したときに処理と同時にイベントの登録の解除をするような構造ですね。

応用として、`subscribe()`は返り値として、引数に入れたコールバック関数を返すので、以下のようにイベントの解除を記述することも出来ます。
```js
const itemUse = world.afterEvents.itemUse.subscribe((ev) => { // イベントの登録
    // 処理
    
    world.afterEvents.itemUse.unsubscribe(itemUse); // イベントの解除
});
```

# 最後に
今回は、ScriptAPIにおいてイベントとは何か？を中心として紹介しました。
この記事を参考にイベントの扱いについて少しでも理解して頂けたら、とても幸いです。
冒頭にも記述した通り、次回以降はどのようなイベントがあるのかを紹介していきます。
今後ともよろしくお願いいたします。