Cluster Creator Kit : シグナル・値はどこからどこに送れるの?
Clusterでゲーム制作機能(トリガー・オペレーション(ロジック)・ギミック)を使って凝った機能を設計していると、「ItemからGlobalに値を送る方法はないんだっけ?」といった疑問に出会うことになります。
トリガーやロジックには「Item / Player / Global」の種類がありますが、自由にどこからどこへでも値を送れるわけではありません。このこと自体はロジック機能をいじるとすぐ分かるのですが、では具体的にどこからどこへの送信ができないか?をきちんと把握している人は実はあまり多くないのではないでしょうか。
「なにができないか」を把握できていないと、想定していたゲームロジックが実はClusterでは実現不可能だった…という罠に陥ることになります。例えば、二つのアイテムそれぞれに点数を蓄えて、ゲーム終了時にGlobal Logicで両者の値を比較して勝敗決定をしたい、と考えるのは自然だと思うのですが、じつはこれClusterでは「ItemからGlobalに値を送ることができない」ために実現不可能な設計です。…ということにゲームジャム終盤数時間で気づいたりしたら目も当てられませんね。(私です!)
ではどこからどこにどんな送信ができるのか?をまとめるのがこの記事の目的です。
結論
結論から言うと、こうなります!(なるはずです。見落としをしていなければ)
(注:この表はロジックについてのものです。トリガー、ギミックはのちほど触れます)
https://scrapbox.io/files/63624430906eb80023728d74.png
https://scrapbox.io/files/636244403b8fe8002164cdc9.png
見ての通り、実はシグナルであれば迂回すればどこからどこへでも送れるようです(ややこしくなりますが…)。
どうしようもないのは値の方で、
異なるアイテム同士や、異なるプレイヤー同士で値を送り合うこと
アイテムやプレイヤーからGlobalに値を送ること
はどうやってもできません。
※ …と書きましたが、黒魔術的な方法を駆使した抜け道がなくもないです。この記事の最後のほうで触れます。
というわけで、ここからはどうしてこの表のようになるのか、そして具体的に送り合う方法について解説していきます。
Clusterのロジック機能
まずは、ロジックについておさらいしておきましょう。Clusterのロジック機能は、他のロジックやトリガーとの間でシグナルや値をやりとりしあって「計算」や「判断」といった機能を実現するための基本要素です。図にすると下のようになります。
https://scrapbox.io/files/6362433960e3ad001dee8ee3.png
ロジックは、「シグナル」を受信することで起動します。ロジックが起動するたび、値を使って何かの計算や判断を行い、計算結果を値として保存したり、条件判断の結果として別のシグナルを送信したりできます。
ロジックにはItem Logic, Player Logic, Global Logicの3種類があります。それぞれアイテム単位、プレイヤー単位、ゲーム全体の機能を作るためのものですが、もちろんItem LogicからPlayer Logicへ、というように種類を越えたロジック同士でもシグナルや値のやりとりができます。しかし無制限にというわけではない…というのがこの記事の本題なのでした。
それぞれのロジックには、シグナルや値の「受信元と名前」「送信先と名前」を設定することができます。これによってシグナルや値をどのロジックから受け取るか、そしてどのロジックへ送るかを指定することができます。送受信には、受信元・送信先の種類、そしてシグナルや値の「名前」が一致することが必要です。
https://scrapbox.io/files/636243d59c7cd1001df348ab.png
https://scrapbox.io/files/636243e548315100219b7d80.png
送受信先に設定できるターゲット一覧
上の図の書き方をつかって、Item Logic / Player Logic / Global Logic のそれぞれで「受信元」と「送信先」に指定可能なターゲットの種類を図にまとめました。それが次の図です。
https://scrapbox.io/files/6360b5ebca12690023884ff3.png
例えばGlobal Logicを見てみると、値をGlobalから受信してGlobalに送信することしかできないことがわかります。また、ItemやPlayerを見ても、Globalに向けて値を送信することはできません。アイテムやプレイヤーの値をGlobalに持ち込むことはできないのです。
一方でシグナルならば、アイテムからGlobalへ送れることがみてとれます。指定アイテムからのシグナルをGlobal Logicで受け取る、という方法です。
この図には、ロジック同士の送受信が可能なのかどうかの判別に使えるよう、ちょっとした工夫がしてあります。具体的には、たとえば下のように横に並べたときに左右でつながる部分は、シグナルや値を送受信できる、ということを意味します。
https://scrapbox.io/files/6360b8d9b3cd670023be17aa.png
もちろん、つながっている部分で送信元と受信先が一致していることが必要です。上の例だと、「送信元Item LogicのOwnerプレイヤー」と「受信先Player Logicのローカルプレイヤー」が一致するようなPlayer Logicに向けて値が送られます。要するに「アイテムのOwnerに向けて値を送ることができる」ということです。
https://scrapbox.io/files/63624760964f14002149f37e.png
また、上の図のシグナルの部分にも注目してみてください。値はオーナーに向けてしか送れませんでしたが、シグナルならば、アイテムからプレイヤーに至る経路は次の2種類があります。
アイテムのOwnerへ送る
Player Logicで予め指定した特定のアイテムからのシグナルを受け取る
2番目の選択肢があることで、アイテムからOwner以外のプレイヤーに向けてシグナルが送れることがわかります。
一方で、値のほうは、任意に指定したアイテムから受け取るようなことはできません。あるプレイヤーに値を送ることができるのは、そのプレイヤーがOwnerであるようなアイテムからに限られる…というわけです。
https://scrapbox.io/files/636249a14bf154001dfe1d1c.png
すこし注意が必要なのは、上のように指定したアイテムからプレイヤーにシグナルを送るときは、Item Logic側では送信先に「プレイヤー」ではなく「このアイテム(This)」を選ぶということです。
イメージとしては、Item Logicが自分自身に向けて投げたシグナルを、Player Logicが「盗み見て」動く、といったふうにとらえてもよいかもしれません。Item Logicは自身かOwnerにしかシグナルを送れないので、OwnerではないPlayerに向けてシグナルを送るにはこのような方法が必要になります。
トリガーとギミック
ここまでではロジックについて解説しましたが、Clusterのゲーム制作機能は「トリガー」「ロジック」「ギミック」の3種類でできています。というわけで残りの「トリガー」「ギミック」についても触れていきます。
といっても複雑なことはありません。
「トリガー」は、ワールドやプレイヤーの状況を検出してシグナルを発生させたり値を送信したりするもの
「ギミック」は、シグナルや値を受け取ってワールドやプレイヤーになんらかの変化を起こすもの
です。
図で書くと、下のようになります。
https://scrapbox.io/files/636242f7f48104001d98cd1c.png
ところで、この記事の冒頭で表をあげて「異なるアイテム間で値をやりとりすることはできない」という話をしました。これは、ロジックの場合の話で、トリガーを含めると話は若干変わってきます。
上の図を見ると分かりますが、例えばItemトリガーは値の送信先に「指定した別のアイテム」を設定することができます。つまり、あるアイテムのトリガーから異なるアイテムに向けて値を送る事ができるということです。これはItem Logicと違う所で、便利に使う事ができます。たとえば、「懐中電灯とスイッチを別々のアイテムにして、スイッチアイテムをUseすると懐中電灯アイテムの点灯・消灯が切り替わる」といった挙動は、スイッチアイテムにつけたUseItemTriggerの送信先を懐中電灯アイテムにすることで可能になるでしょう。
では、トリガーを使うことでロジックにあった値の送信先の制約を乗り越えられるのでしょうか?
残念ながら、トリガーから送り出すことのできる値は、基本的に固定値、つまりワールド作成時にトリガー毎にあらかじめ決めた値です。あるアイテムのステートを読み取ってその値を送り出す、といったことはできません。なので、決め打ちの値を他のアイテムに送り込むことはできても、あるアイテムで計算した結果を他のアイテムに送り込む…といった用途には変わらず使えません。「異なるアイテム間で値をやりとりしたければロジックのかわりにトリガーを使えばいい!(?)」とはならないわけですね。
※…が、実はわずかに例外があります。値の指定に「Input」という種類が使えるトリガーがそれです。後のほうで、このInputを使った黒魔術の可能性についても触れます。
スクリプト
2022年10月に、アイテムの挙動をjavascriptで制御できる「スクリプト機能」が導入されました。スクリプトの導入によってここまでに書いた制限が緩和されるのでは…と期待していた方も多いと思います。
残念ながら、2022年10月の時点では、スクリプトでシグナルや値をやりとりできる相手は Item Logic と全く同じです。
毎フレーム処理ができる、数学関数を用いた計算ができる、アイテムの子要素を含むゲームオブジェクトの位置・姿勢を直接取得・設定できる、といった大きな進展はあるものの、現時点でのスクリプトは、少なくともロジック間の値のやりとりに関して言えば「すごいItem Logic」の域を出ません。今後の拡張に期待したいところです。
※…が、この「位置・姿勢の取得・設定が可能」という特徴によって、これまでできなかった新たな黒魔術が行使できるようになりました。これも最後のほうで触れます。
パターン別、シグナル・値の送り方
ここからは、実際にあるロジックから別のロジックに値やシグナルを送るにあたってどういう経路を通ればできるのか(またはできないのか)を、パターン別に網羅していきます。
大きく3種類に分けて解説します。
正攻法編 (表の「◎」「○」のパターン)
ロジック2つ、つまりあるロジックから別のロジックに直接送ることができる場合の方法です。
回り道編 (表の「△」のパターン)
ロジック3つ以上、つまりロジックAからロジックBに送るのにいったん別のロジックCを経由する方法です。正攻法ではできない場合のための方法ですが、ややこしくなります。
黒魔術編 (表の「×」のパターン)
基本的に「できない」とされるパターンをなんとか実現するための特殊な方法です。二つのロジックの間を、ロジック以外のもの(例えばギミック、トリガー、衝突判定、アニメーション、Constraintなど)を使って無理くりつなぎます。積極的におすすめはできませんが、活用できる場面もあります。
あらためて、冒頭の表を載せておきます。
https://scrapbox.io/files/63624430906eb80023728d74.png
https://scrapbox.io/files/636244403b8fe8002164cdc9.png
(以下書きかけ)
~~~正攻法編~~~
ItemからItemへ
ItemからPlayerへ
ItemからGlobalへ
PlayerからItemへ
PlayerからPlayerへ
PlayerからGlobalへ
GlobalからItemへ
GlobalからPlayerへ
GlobalからGlobalへ
~~~回り道編~~~
~~~黒魔術編~~~
Colliderを経由してItemから別のItemにシグナルを送る
スクリプトとConstraintを使ってItemから別のItemに値を送る
角速度検出トリガーを使ってItemからGlobalに値を送る
(未検証)