見出し画像

Logic de タイマーもどき

今回GAMEJAMでLogicを使って疑似タイマーを作ったので共有できたらと思い書いてみました。
今回は、
「Logic de タイマーもどき」として
Logicだけを使ってタイマーを実装(多分精度は悪い)してみようという企画です。
今回も長いです。。。(すみません。)

実際作った時の動作する様子です。

このデータは下記からダウンロードできます。

※ダウンロードしたZIPを解凍して、UnityHUBに登録してもらえると
 見れると思います。
 シーン自体は、Assetsフォルダ内にあるScenesフォルダの中に
 「MinimalSample」をダブルクリックしてもらえれば開けます。
 (ClusterCreatorKitSampleを流用してます。)

では、始めていきたいと思います。

最終的に作るものは、下記のようなものです。

・スイッチを踏むと300秒(5分)タイマースタート
・スイッチから離れるとタイマーストップ
・再度スイッチを踏むとその秒数からタイマースタート
・0になったらタイマー終了
・リセットを押すと初期状態に戻る。

構造は下記のよう形です。

LogicdeTimer説明1

・基本は踏む為のスイッチを作ってコライダー判定によりタイマーの
 スタート/ストップを制御します。
・タイマーオブジェクトがCubeになっていますが、
 このオブジェクトはわかりやすいように設置しています。
 実際は、GameObjectなど目に見えないオブジェクトでもかまいません。
 このオブジェクト内に疑似タイマー用Logicを組んでいきます。
・タイマー描画用のCANVASはわかりやすいように表示用に用意しただけ
 なので、タイマーとしては特に必須ではありません。

1.オブジェクトの配置について

まずはオブジェクトを下記のように配置します。

画像2

この形にしたらLogicを仕込んでいきます。
※PlayerUIは、ClusterCreatorKitTemplateにある
 ProgressionのPlayerLocalUIにある
 GaugeとCapacityTextをベースにしています。
実際の動きは下記の通りとなります。

ヒエラルキーはこのような感じです。
※細いオレンジ枠の部分は、ClusterCreatorKitSampleにある
 「MinimalSample」のサイズを変えただけですので、説明を割愛します。

LogicdeTimer説明_2

2.タイマー処理機能追加(濃いオレンジ枠)

次に濃いオレンジ枠の「ClockLogic」にタイマー機能を割り当てます。
ここが今回のメインどころだったりします。
※見た目的にわかりやすいように追加しているだけなので、
 Cube自身には何も手を入れません。
まずは、今回作るロジックの概念から。。。

今回扱う値としては、
「Bool型(True or False)」、「Integer型(整数)」
を使用します
タイマー自身はカウントダウン型として、
今回は5分(300秒)のタイマーとします。
ざっくりロジックは下記の通りです。

LogicdeTimer説明6

上記をItemLogic、ItemTimer、On Create Item Trigger、Global Logicを使って実装していきます。
※実際は、Global Logicの部分は使用していませんが、
 ItemLogicからGlobalLogicの渡し方のサンプルとして入れてあります。
 (ItemLogic内で定義した値はそのItem内でしか参照が出来ないため、
  時には変換が必要になります。)

まずは①の処理については下記のように設定します。
(「On Create Item Trigger」以下が追加した処理です。)

LogicdeTimer説明7

・「On Create Item Trigger」を使って、
 インスタンス初期化(ワールド作成)時、
 「InitSignal」というSignalを出します。
・「InitSignal」のSignalを受けたら、
 下記のように変数の値を初期化します。
  -「MainTimerValue」という変数に300という値をセットします。
   (この値が300秒=5分のタイマーの初期値になります。)
  ー「IsTimerEnable」変数の値をFalseにします。
  -Globalで参照できる変数を初期化するために、
   「InitGlobalValue」というSignalを出します。
   このとき、「=Equals、Constant-Bool-チェックOnが2つ」
   となっていますが、コレは必ず「InitGlobalValue」が
   実行されるように、両方同じ値にしている感じです。
   「=、Constant-Bool-チェックOn」だと値を入れるだけのため、
   Signalの代入は無いので、わざとこうしています。
   (ひょっとしたら、いけるかもしれませんが、
    ぱっと見た時、混乱しそうなので、
    あえてこうしています。)
・「InitGlobalValue」のSignalを受けたら、
  -「IsEnd」というGlobalで参照できる変数の値をFalseに設定します。
 この処理は、GlobalLogicを使っています。
 ItemLogicで出したSignalは、
 GlobalLogicでもTargetをItem(今回はClockLogic)にして
 信号を読み取りたいItemを指定することで、Signalを受け取れます。
 ※「IsEnd」は定義していますが、
  この値はこのプロジェクトでは使っていません。
  ItemLogic→GrobalLogicへの変換方法のサンプルとして
  のせているだけになります。

②以降の処理の流れは下記のような感じとなります。

LogicdeTimer説明13

では、それぞれの設定を詳しく見ていきたいと思います。

②の処理については、下記の通りです。

LogicdeTimer説明8

・スイッチを踏んだとき、「TimerStartSignal」というSignalを
 出すようにするので、ここで、「TimerStartSignal」を
 受けられるようにItemLogicを使って設定します。
 「TimerStartSignal」のSignalを受け取ったら、
  -「IsTimerEnable」をTrueにして、タイマー動作中にします。
  -「MainTimerSignal」のSignalを送りタイマー処理を開始します。

③の処理については、下記の通りです。

LogicdeTimer説明9

「MainTimerSignal」の処理は、ItemTimerを使って設定します。
ItemTimerは、
「DelayTimer Seconds」で設定した秒数(0.1なども設定可能)後に、
Triggerで設定した処理を行うものです。
ここでは、1秒後にタイマーが動いているかの判定を行いたいので、
「CheckMainTimerSignal」というSignalを1秒後に出すように設定します。

ここで気をつけたいのは、ItemTimerは、指定した秒数ディレイさせて処理すると言うことです。
なので、1秒毎に処理させるには、処理が終わったあと再度ItemTimerの処理を呼び出す必要があります。
そのため厳密に1秒間隔で処理が行われない事になります。
※厳密に言うと
 1秒後に設定した内容の処理時間+再度ItemTimerのSignalを受け取る時間
 を経て、再度1秒後に処理するように設定される。
なので、(多分精度は悪い)としています。(^^;

④の処理については、下記の通りです。

LogicdeTimer説明10

「CheckMainTimerSignal」のSIgnalを受けると、
「IsTimerEnable」変数の値がをチェックしてTrueであれば、
「CountDownSignal」のSignalを出します。
※Falseの場合は何もせず終了します。(=タイマー処理が止まる。)

「CountDownSignal」のSignalを受けると、下記の処理を行います。
 -「MainTimerValue」の値を1減算する処理を行う。
 -「MainTimerValue」の値が0より大きい(>0)なら
  「MainTimerSignal」のSignalを送る。(③の処理に戻る=ループ処理)
 -「MainTimerValue」の値が0以下(<=0)なら
  「TimerStopSignal」のSignalを送る。

⑤の処理については、下記の通りです。

LogicdeTimer説明11

「TimerStopSignal」のSignalを受けたら、
「IsTimerEnable」の値をFalseにして、「StopSignal」のSignalを送ります。

GlobalLogicで、「StopSignal」のSignalを受けたら、
Global変数「IsEnd」の値をTrue(チェックON)になります。
(ここでも、
 ItemLogic内で送ったメッセージをGlobalLogicで受け取るために、
 TargetをItemにして、Itemに「ClockLogic」を指定しています。)

※「TimerStopSignal」は、
 「MainTimerValue」の値が0以下になるか、
 このあと説明する。タイマースイッチのコライダーがなくなると、
 呼び出されます。

以上でタイマー処理部分は終了です。

3.タイマースイッチ機能をCubeに割り当てる
  (緑色枠)

次に緑色枠のCubeにスイッチの機能を割り当てます。
まず、下記のように、SW_Cubeのインスペクターを見て、
Box Colliderにある「Is Trigger」チェックを入れます。
※「Is Trigger」にチェックがないとコライダーに関する
 イベントが発生しない為チェックは必須となります。
※このサンプルはPrefub化していますが、
 必ず必要というわけではないです。

LogicdeTimer説明4

また、1つ上のGameObject「StartPause」には、
「On Collide Item Trigger」を2つ追加して、
Collision Event Typeを「Enter」と「Exit」に割り当てます。
※EnterはCollider判定が起きた時、ExitはCollider判定が無くなった時に
 動作するTriggerの設定になります。
さらに、
Targetを「SpecifiedItem」、
Specified Target Itemには、「ClockLogic」を
登録します。
Keyはそれぞれ、
「Enter」は、「TimerStartSignal」
「Exit」は、「TimerStopSignal」
として、Parameter Typeは両方とも「Signal」にします。
そのほかは下記を参照ください。

LogicdeTimer説明5

4.タイマーリセット機能実装(黄色枠)

Sphereの部分にTriggerを下記のように設定するだけです。
(Sphereはデフォルトのオブジェクトに
 テクスチャを張れるようにしただけです。)

LogicdeTimer説明14


組み込むTriggerは、「Interact Item Trigger」です。
クリックやVRのハンドコントローラのトリガをひくと反応するようにするTriggerです。
コレを、下記のように設定しています。

TargetをSpecifiedItemにする。
Specified Target Itemに「ClockLogic」を指定する。
keyに「InitSignal」を指定する。
Parameter Typeに「Signal」を指定する。

5.カウントダウンタイマー値表示機能実装(赤枠)

現在のカウントダウン値表示の為のものです。
基本は、Canvasを使ったパネル表示になります。
Canvasの設定は下記のようにしてます。

LogicdeTimer説明15

Panelの設定は下記のように設定します。

LogicdeTimer説明16

最後にTextの設定をします。
設定は下記のようにします。

LogicdeTimer説明17

ここでは、「Set Text Gimmick」をつかって、ここに表示されるTextの値が変わるようにしています。
ここの設定は下記の通りです。

Targetは、Itemにします。
Keyは、「MainTimerValue」を指定します。
Itemは、「ClockLogic」を指定します。
Parameter Typeは、Integerにします。
Formatはそのままの表示をしたいので、「{0}」とデフォルトにします。

画像19

6.PlayerLocalUI(水色の枠)

「PlayerLocalUI」は、ClusterCreatorKitTemplateにあるProgressionのPlayerLocalUIを改変しています。
元からは、下記のように変更しています。
※半透明のグレー部分はバッサリ削除したところです。

①文字部分を「TIMER BAR」に変更

LogicdeTimer説明3

②Set Fill Amount Gimmickの設定を変更

・Targetを「Item」にする。
・Keyを「MainTimerValue」に変更。
・Itemに「ClockLogic」を指定する。
・Parameter Typeを「Integer」にして、
 Min Valueを「0」、MaxValueを「300」にする。

LogicdeTimer説明12

以上ですべて終了になります。
あとは実行してみてください。
お疲れ様でした!

ちなみに、一応、このロジックは多少のずれはありますが
同期して動くので、マルチでも動作します。(動作するはず!)