【Minecraft BE Addon講座#6】フィルターとは？/フィルターの書き方

本ページは**アドオン講座#6、「コンポネ編、フィルターとは？/フィルターの書き方」**です。
目次や、この講座については[#1の記事](https://qiita.com/pencilya/items/7b7e68265151f42a51ac)をご覧ください。

#コンポネ編で理解してほしいこと！
コンポネ編はこのアドオン講座の基礎編の次のページに位置し、**内容としては応用編の中でも基礎寄り**になります。
エンティティの追加には欠かせませんし、特に初回の#5の内容はアニコン編でもお世話になります。
基礎編を終えてとりあえず何かやってみようという方におすすめです！

コンポネ編は3ページからなり、**初回#5は基礎編の延長で、書き方(記法)と仕組みの理解**について、**#6では重要な条件分岐の役割を担う機能**について、**最後#7では実践としてタグによって体力(HP)が変わるアドオンを作って**みます。

このコンポネ編では、エンティティの持つコンポーネントを自由に追加消去編集することで、**エンティティに特殊な性質をもたせる、また特殊な動きをさせられるようになる**ことを目的としています。

* (前提#3~#4)基礎編
* (#5)エンティティとは？
* (#5)`entity.json`とは？
* (#5)エンティティのしくみとコンポーネント
* (#5)[実践]プレイヤーの名前を非表示にしてみよう
* (#6)フィルターとは？
* (#6)フィルターの記法
* (#7)コンポーネントを操るには？
* (#7)センサーとは？/コンポーネントグループとは？
* (#7)[実践]プレイヤーの体力をタグで変更してみよう

#フィルターとは？
[前回#5](https://qiita.com/pencilya/items/89d0fdf6d575baea79c2)ではコンポーネントについて扱いました。
コンポネを変更したり追加したりすることで、おもしろいことができるということは分かってもらえたと思います。
今回は、そんなコンポネのある`entity.json`の中で使える条件分岐のシステムを解説します。
それが**フィルター(filter)**です。

フィルターでは、エンティティの制御を行うための条件分岐が実装されているため、コマンドでできなかったエンティティ関連の特殊な条件設定が可能になっています。

#フィルターの記法
###使用例(バニラ`player.json`)
まずはバニラでフィルターがどのように使われているかを見てみましょう。

この講座内で例を見るときには、エンティティの中でも、プレイヤーのもの(今回なら`player.json`)を見ることが多いです。
他のエンティティが変わるよりも自身が変わった方が、なんでもできる気がしてきておもしろいですよね！[^1]

[^1]: この「なんでもできる気」が楽しくてアドオンやってるまである。

```behavior(v1.17.30)/entities/player.json
      ...
      "minecraft:hurt_on_condition": {
        "damage_conditions": [
          {
            "filters": { "test": "in_lava", "subject": "self", "operator": "==", "value": true },
            "cause": "lava",
            "damage_per_tick": 4
          }
        ]
      },
      ...
```

※「...」は略

ということでフィルターが使われている`player.json`の一部を抜粋してきました。
これは`"minecraft:hurt_on_condition"`というコンポーネントです。
条件を満たしたらダメージなどを与える、という内容です。
ここでは溶岩に浸かっていたら4ダメージを受けると書かれています[^2]。
この「溶岩に浸かっていたら」という部分が抜粋5行目(全体72行目[^3])にある`"filters"`で記述されています。

[^2]: マグマダイブの死因はこれです。このコンポネはいったい何人のプレイヤーを殺めてきたんだ…。
[^3]: バージョン違いによって正確な行数は変わっている可能性が高いです。v1.17.30のバニラでの行数です。

###フィルターの子要素
フィルターのカッコの中の要素について解説していきます。

|  |  | 説明 | 省略時デフォルト |
|:-:|:--|:--|:-:|
| 必  | `"test"`  | 条件名を入力  | (入力必須)  |
|   | `"subject"`  | 直訳「主体[^4]」ようは「対象」どのエンティティの条件を見て条件判定するかの指定  | `"self"`  |
| ※△  | `"domain"`  | 直訳「域」複数ある値のうちのどこを参照するかの指定  | `"any"`  |
|   | `"operator"`  | 「演算子」条件と値がどういう関係だったらokなのかの指定  | `"=="`  |
| △  | `"value"`  | 「値」取得してきた結果と関連があるか調べたい値の指定  | `true`  |

※：`domain`は`has_equipment`、`is_game_rule`でのみ使用。
△：入力必須の場合もある。
入力が必要かどうかは[ドキュメント](https://bedrock.dev/docs/stable/Entities#Filters)で`test`ごとに必須(`Required`)か選択(`Optional`)かを確認してください。
`is_~~`は入力不要、`has_~~`は入力必須の傾向があります。

[^4]: 構文でやるSVOC…とかのSはsubjectのSです。「主」という意味があります。ここでは、そいつを中心に見るという意味で「対象」と呼んでいます。「科目」の方じゃないですよ。

```フィルターの子要素.json
"filters": { "test": "条件名", "subject": "self", "domain": "any", "operator": "==", "value": true }
```

こう言っても抽象的すぎてわけわからんだと思うので、ここからはひとつひとつどんなのがあるかを解説していきます。

####`"test"`
めちゃくちゃたくさんあります。

https://bedrock.dev/docs/stable/Entities#Filters

なかでも代表的なものだけ紹介します。

|  | 説明 | 備考 |
|:--|:--|:--|
| has_tag  | 指定したタグを持っていたら…の条件  | 超重要！`"value"`ではタグ名を指定します  |
| has_equipment  | 指定したアイテムを持っていたら…  | 重要！`"value"`は`minecraft:`抜きのアイテムIDです  |
| is_moving  | 動いているか  | `true`/`false`  |
| is_riding  | トロッコ、mobなどのエンティティに乗っているか  | `true`/`false`  |
| is_sneaking  | スニークしているか  | `true`/`false`  |
| on_ground  | ブロックに足がついているか  | `true`/`false`  |
| is_mark_variant  | 玄人向け。これの何がすごいのかが分かったら使いましょう。  |   |
| is_skin_id  | 〃  |   |
| is_variant  | 〃  |   |

####`"subject"`
条件を問う対象の指定です。
数は限られているので、ドキュメントから抜粋、いい感じに翻訳しています。

|  | 説明 | 備考 |
|:--|:--|:--|
| self  | 自身  | このフィルターが記述されているエンティティとも言える。  |
| other  | このフィルターを起動した自身以外  | たいてい自身の相手のこと。  |
| block  | 関与したブロック  | わけわかめ  |
| damager  | 関与したダメージを与えるエンティティ  | わけわかめ  |
| player  | 関与したプレイヤー  | わけわかめ  |
| parent  | 自身の親  | ひな鳥が親についていくときの親のことだと思われる。  |
| target  | 自身のターゲット  | 敵Mobで言うところの攻撃対象のこと。  |

実際のところ`"self"`と`"other"`以外使ったことがないのでよく分からないです…。
`"self"`と`"other"`以外は使用頻度が低いということでお許しください。

####`"domain"`
ドメインは`has_equipment`、`is_game_rule`でのみ有効です。
`has_equipment`ではどこに持っているものを検知するかの選択、`is_game_rule`では検知するゲームルール名を入力します。
`has_equipment`では`any`がデフォルト、`is_game_rule`では入力必須です。

| `has_equipment` | 説明 |
|:--|:--|
| any  | デフォルト値。下の枠のうちどこかにあれば反応する。  |
| hand  | 手に持っている  |
| armor  | 防具の枠のどれか  |
| head  | ヘルメットの枠  |
| torso  | チェストプレートの枠  |
| leg  | レギンスの枠  |
| feet  | ブーツの枠  |

####`"operator"`
プログラマーの方ならおなじみ、演算子です。
羅列されているものはどれを使っても効果は同じです。

| 演算子 | 説明 | 備考 |
|:--|:--|:--|
| `==`, `=`, `equals`  | 検知した値と指定した値(`value`)が同じとき  | 検知した値＝指定した値 |
| `!=`, `<>`, `not`  | 〃異なるとき  | 検知した値≠指定した値 |
| `<`  | 検知した値が指定した値(`value`)より小さい(未満)とき  | 検知した値＜指定した値 |
| `<=`  | 〃小さいか等しい(以下)とき  | 検知した値≦指定した値 |
| `>=`  | 〃大きいか等しい(以上)とき  | 検知した値≧指定した値 |
| `>`  | 〃大きい(超過)とき  | 検知した値＞指定した値 |

####`"value"`
値を指定します。
`true`(意味：真、Yes)、`false`(意味：偽、No)を指定するような条件(`test`)の場合は、デフォルトが`true`になります。
それ以外の場合は値(`value`)の指定が必要になります。

###フィルターのコレクション
これでフィルターは一通り使えるようになりましたが、仕上げにコレクションを説明します。
コレクションはフィルターのコレクション、ということでフィルターを複数個使う、つまり複数の条件を同時に検知するときに使います。
普通のプログラミングで言うところの`&&`(and、かつ)と`||`(or、または)にあたります。

|  | 説明 |
|:--|:--|
| `all_of`  | 「and、かつ」のこと。含まれるすべての条件が満たされているとき。  |
| `any_of`  | 「or、または」のこと。含まれる条件のうちひとつでも満たされているとき。  |

```フィルターのコレクション.json
"filters": {
    "all_of": [ 
        { "test": "has_tag", "subject": "self", "operator": "==", "value": "タグ名" },
        { "test": "has_equipment", "subject": "self", "domain": "hand", "operator": "==", "value": "アイテム名" }
    ]
}
```

上記の例は**「タグ名」のタグが付いていて、かつ、「アイテム名」を手に持っていたら**、という条件です。

これでフィルターは完璧です！
あとは、コンポーネントグループ、エンティティのイベントを解説して、コンポネ編でやりたいことの材料がすべてそろいます。
[次回#7](https://qiita.com/pencilya/items/c63ac2a6e34be38530fb)では、その残りの材料とコンポネを切り替える方法について解説していきます！
お疲れ様でした！