ビジュアルスクリプティングチュートリアル (Logic Bricks)
プラットフォームボタンの作成
Lesson 9 of 10 • 10 XP
Keep your place in this quest
Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.
このレッスンでは、前のレッスンで始めたシステムを完成させ、プラットフォームロジックに接続されるボタンを作成して、両システムの相互作用を完了させます。
このプロセスでは、Caveのビジュアルロジックシステムのいくつかの重要な概念を探ります。Rigid Bodyを使用して衝突を検出する方法、アクションが時間の経過とともに発生するタイミングを制御するためにDelayノードを使用する方法、ゲームプレイ中にEntityの色を変更する方法、そしてLogic Bricksを整理可能で再利用可能なものに保つために関数を作成して使用する練習をします。
このレッスンの最後までに、ボタンがプレイヤーによってアクティブ化され、前に作成したプラットフォームと正しく通信できる完全なシステムが作成されます。
1. ボタンの作成
ボタンを作成するには、最初に新しいEntity Templateを作成します。
次に、その目的に応じてEntityの名前を変更し、視覚的表現として使用するMeshを構成し、ゲーム内で正しく相互作用できるように必要な物理コンポーネントを追加します。
その後、新しいLogic Brickを作成し、それをボタンEntityにリンクします。
このプロセスは、プラットフォームを作成する際に以前に行ったことに非常に似ているため、あなたがすでに学んだ概念を練習する良い機会でもあります。
このステップの最後までには、ボタンがアクティベーションロジックを受け取れる基本的な構造が整います。

さて、非常に重要なステップがあります:ボタンEntityにbuttonタグを追加するのを忘れてはいけません。
前のレッスンで、私たちはすでにこの正確なタグを使用して、シーン内にいくつのボタンが存在するかを自動的に数えるようにプラットフォームロジックを準備しました。
そのため、タグは作成され、プラットフォームロジックで使用されていたのと同じ名前を使用してボタンに割り当てる必要があります。
タグ名がわずかに異なる場合でも、プラットフォームはボタンを正しく見つけられず、カウントは期待通りに機能しません。
そのため、続行する前に、buttonタグを作成し、ボタンEntityに追加されていることを確認してください。

次に、ボタンEntityにプロパティを追加しましょう。
buttonタグを使用してマップ内のボタンを識別しますが、プロパティを使用してその動作の一部を制御します。
Active Timeという名前の新しいプロパティを作成し、そのタイプをFloatに設定します。
このプロパティは、ボタンが自動的に非アクティブ状態に戻る前に、どれくらいの間アクティブであるべきかを保存します。
これにより、各ボタンが異なるアクティベーション時間を持つことができるため、システムが柔軟になります。たとえば、1つのボタンが3秒間アクティブであり、別のボタンが10秒間アクティブであることができ、Logic Brick自体を変更することなくできます。

2. ボタンロジックの作成
Entityのタグとプロパティが設定され、準備が整ったので、ボタンの動作を作成し始めましょう。
最初のステップは、ボタンEntityとプレイヤーの間で衝突を検出し、プレイヤーがそれに触れたときにアクティブにすることです。
しかし、このロジックを実装する前に、重要な詳細を考慮する必要があります:ボタンは現在非アクティブなときにのみアクティブにしたいのです。
ボタンにはアクティブと非アクティブの2つの異なる状態があるため、現在使用中の状態を保存する方法が必要です。
そのため、新しいプロパティをボタンのLogic Brickに作成し、Active Buttonという名前を付け、タイプをBooleanに設定します。
このプロパティは、ボタンの現在の状態を保存し、その状態がアクティブかどうかを示します。この値は、次のステップでボタンの動作全体を制御するために使用します。

これで、ビジュアルロジックの構築を開始できます。
On Updateで、私たちはボタンがアクティブか非アクティブかを常にチェックします。これは、先ほど作成したActive Buttonプロパティを使用して行います。
そのため、Get Active Buttonを使ってその値を取得し、その状態をチェックするためにIfノードを使用します。
条件がFalseの場合、ボタンは非アクティブであり、アクティブにすることができます。この場合、ボタンとプレイヤーの間で衝突を検出します。
これを行うには、Collided Withノードを追加します。
このノードにはRigid Body Componentが必要ですので、ボタンのEntityを取得し、それから物理設定時に追加したRigid Body Componentを取得します。
また、ノードにどのオブジェクトを検出したいか伝える必要があります。そのため、キャラクターにplayerタグを追加し、このタグをCollided Withに渡します。
これにより、ボタンがプレイヤーと衝突したときのみ、衝突が有効と見なされます。
この構造を使って、ボタンは非アクティブであり、プレイヤーが実際にそれと衝突している場合にのみアクティブ化されます。

両方のパスが定義されたので、最初にボタンがアクティブなときのロジックを実装しましょう。
その後、ボタンをアクティブにするための動作を作成します。
これを行うには、ボタンがアクティブかどうかを確認するIfノードのTrueの条件に従います。
このフローでは、ボタンEntityで作成したActive Timeプロパティを使用して、ボタンがどれくらいの間アクティブであるべきかを制御します。
最初にボタンEntityを取得し、そのプロパティにアクセスするためにGet Propertiesノードを使用します。
次に、Get Propertyを使用し、以前に返された辞書を接続し、Active TimeをKeyとして使用します。
このプロパティはFloatであるため、Get Propertyの出力タイプをFloatに変更し、この値を次のロジックの部分で正しく使用できるようにします。

Get Propertyの出力は、ボタンがどれくらいの間アクティブであるべきかを定義するActive Timeプロパティの値を返します。
次に、Delayノードを追加し、この値を期間として使用します。
これにより、待機時間がEntityプロパティによって直接制御され、異なるボタンが異なるアクティベーション時間を持つことができ、ロジックを変更することなく実現できます。
Delayが終了した後は、Set Active Buttonを使用し、その値をFalseに設定します。
これにより、ボタンは、自身のプロパティに指定された時間後に自動的に非アクティブ状態に戻ります。

とても良いです。では、もう一つのパスに進み、ボタンをアクティブにするための動作を作成しましょう。
Collided Withノードの出力はBool値を返します。
この値がTrueの場合、ボタンはプレイヤーと衝突しています。
この瞬間に、私たちは単純にSet Active Buttonを使用し、その値をTrueに設定できます。
これにより、ボタンはアクティブ状態になり、以前に作成したアクティブロジックを自動的に使用し、一定の時間アクティブな状態を維持した後、再び非アクティブになります。
これにより、完全な動作サイクルを作成しました:
- プレイヤーがボタンと衝突したとき、ボタンをアクティブにします
- Active Timeで定義された時間の後、非アクティブになります
- その後、別の衝突によって再びアクティブにできます
このロジックはシンプルですが、すでにボタンに二つの異なる状態を与え、私たちが追加する次の機能の基盤となります。

すべてが機能していますが、まだ重要な部分が欠けています。
ボタンのアクティブ化および非アクティブ化のロジックはすでに正しく動作していますが、私たちのプラットフォームはボタンがアクティブ化されたときにそれを知りません。
ここで重要なのが、以前にSceneで作成したButton Countプロパティです。
プラットフォームロジックでは、このプロパティの値がシーン内のボタンの総数と等しくなったときのみ、プラットフォームが削除されるべきであると定義しました。
言い換えれば、プラットフォームはすでに反応する準備ができていますが、これまでボタンがこの値を変更していませんでした。
今必要なのは、ボタンがアクティブ化および非アクティブ化されるたびに、Button Countプロパティをシーンに直接変更できるようにすることです。
これは、Caveにおける非常に重要なLogic Bricksの機能である関数を作成する良い機会です。
同じロジックを何度も繰り返すのではなく、この動作を再利用可能な関数としてカプセル化し、グラフをより整理して理解しやすくし、メンテナンスを容易にします。
Button Countプロパティはシーンに保存されているため、まずAccessする必要があります。
そのため、Get Sceneを使用してシーンを取得し、次にGet Propertiesを使用します。

3. シーンプロパティを制御する関数の作成
これらのノードから、関数を作成します。
これを行うには、関連するノードを選択し、右クリックしてPromote Selection to Functionを選択します。

その後、新しい関数の名前をプロジェクトロジック内での目的を表す明確で説明的な名前に変更します。
この場合、Set Scene Propertyという名前を使用します。

では、Set Scene Property関数がどのように動作するかを構成しましょう。
最初に、Get Sceneからの各プロパティ辞書をGet Propertyノードに渡します。この辞書は、Get Scene → Get Propertiesのフローから取得されます。
次に、Get Propertyの出力をIntに変更して、整数値で作業します。
Function Inputsでは、この関数のために2つの新しいパラメータを作成します:
- Prop Name、タイプはString
- Value、タイプはInt
Prop Name パラメータは、Get Property の Key として使用され、関数が Scene プロパティ辞書内の目的のプロパティにアクセスできるようにします。
次に、このプロパティを Set Property を使用して更新します。
そのためには、プロパティの現在の値を取得し、そこに Value 入力を追加し、その結果を同じプロパティに書き込みます。
Scene プロパティ辞書を再度渡し、Prop Name をキーとして使用します。
これにより、Scene プロパティをシンプルかつ整理された方法で修正できる汎用的で再利用可能な関数が作成されます。
正確な値を設定するのではなく、この関数はインクリメントシステムのように機能します: 受信した Value を Scene プロパティの現在の値に追加します。

この関数が準備できたので、メイングラフ内にこの全体のノードチェーンを直接保持する必要がなくなります。
今後は、Active Button を True に設定した直後に関数を単に呼び出すだけです。
これは、ボタンがアクティブになった瞬間に、プラットフォームロジックにもう1つのボタンが押されたことを即座に伝えることを意味します。
これを行うためには、Scene に保存されているプロパティ名 Button Count を渡し、インクリメントとして値 1 を送ります。
この関数は、そのプロパティの現在の値に +1 を自動的に加えます。
これにより、アクティブ化されたボタンは、ロジックを重複させることなく、システムのグローバル進行状況を直接更新します。
この関数を再利用することにより、将来的に Scene プロパティを変更する際の柔軟性も増します。

このシンプルさと柔軟性を示すために、アクティブボタンロジックに戻りましょう。
有効時間が終わり、Active Button を False に設定する直後に Set Scene Property を再度呼び出します。
Prop Name パラメータは Button Count となり、同じ Scene プロパティを使用します。
ただし、今度の Value パラメータは -1 です。
私たちの関数は受信した値を現在の Scene プロパティ値に追加するので、負の数を渡すと Button Count から自動的に 1 が引かれます。

このようにして、ボタンが無効化されるたびに、システムはグローバル進行状況を正しく更新し、プラットフォームロジックをマップ内のボタンの実際の状態と同期させます。

私たちのロジックは期待通りに機能しています。
あと一つ重要な詳細があります: ボタンがアクティブなときにプレイヤーに明確に示すための視覚効果を作成することです。
ボタンがアクティブになったときは、Tint を使用してその色を直接変更し、その状態を視覚的に強調します。
Active Button を True に設定する前に、Sequence を追加します。
もはや 3 つのフローは必要ないので、右クリックして Remove Last Flow Output を選択し、2 つのパスのみを保持します。
次に、ボタンの子 Entity である ButtonMesh を取得し、その Mesh Component にアクセスし、Tint 値を調整します。
Y 軸で値を 25 に設定し、ボタンがアクティブなときに緑に見えるようにします。
これにより、ボタンが押されるたびにプレイヤーに明確な視覚フィードバックが提供され、ゲーム内でのインタラクションの可読性と応答性が向上します。

同様に、ボタンが非アクティブになったときは、ボタンの元の色に戻します。
同じロジックを使用しますが、Active Button を False に設定するフローで行います。
その瞬間に、子 Entity ButtonMesh に再度アクセスし、その Mesh Component を取得し、Tint 値を調整します。
デフォルトの色に戻すには、すべての Tint 値を 1 に戻し、ボタンの元の視覚状態を復元します。
これにより、ボタンが非アクティブになるたびに、再度操作できることがプレイヤーに明確に伝わります。

シーンに追加した button template instance を選択することで、そのプロパティにアクセスし、Active Time の値を変更できます。
これにより、各ボタンが異なるアクティベーションの持続時間を持ち、独立して動作することができます。
これにより、レベル内で多様なチャレンジを作成する柔軟性が増します。各ボタンは、システムのメインロジックを変更することなく、個別に構成できます。

これにより、マップに必要なだけボタンを追加でき、それぞれが異なるアクティベーション時間と独立した動作を持つことができます。
プラットフォームは、この設定を自動的に追従し、手動での調整を必要とせず、カウントが実行時に行われます。
システムはゲームの実際の状態と同期され、ボタンがアクティベートまたはディアクティベートされると、グローバル値が更新され、条件が満たされたときにプラットフォームが正しいタイミングでシーンから除去されます。
ロジックに加えて、プレイヤーの重要な視覚フィードバックも追加されました。
ボタンがアクティブになったときにその色を変更し、無効になったときに元の外観に戻すことで、システムははるかに明確で直感的になります。プレイヤーは、どのボタンがアクティブで、どのボタンがまだ注意を必要とするかを視覚的に理解できます。
最後に、エンティティ間の通信を統合し、Scene を通じて集中制御を行い、ゲーム世界に直接視覚フィードバックを提供するモジュール式でスケーラブルなシステムを作成しました。
この同じ構造は、ドア、プラットフォーム、エレベーター、パズル、トラップ、タイムチャレンジ、その他多くのインタラクティブイベントに対して簡単に拡張できます。
