Search Unity

2017 年の Timeline の公開以来、イベントの送信が行えるようになるのを心待ちにされて来た皆様、お待たせしました!Unity 2019.1 から、Signal という新しい機能によってイベントの送信が可能になりました。本記事ではこの新機能について詳しくご紹介します。

Signal

Timeline ウィンドウ上で、Signal は以下のように表示されます。

Signal は、Timeline と外部のシステムとの間の通信チャンネルを確立するために開発されました。しかし、これは具体的に何を意味するのでしょうか?また、私達は何故このアプローチを採用したのでしょうか?

例えば、Timeline を使用してカットシーンを作成するとしましょう。カットシーンの終了時には、新しいシーンを読み込み、物理システムを有効にする必要があります。このシナリオの実装は、以下の 2 つの方法で行うことができます。

  1. カットシーンの終了時にカスタムスクリプトを使用して、Timeline インスタンスが直接シーンマネージャーおよび物理システムとやりとりするようにする。
  2. カットシーンの終了時にマーカーとシグナルを作成して「カットシーン終了」のシグナルを送信し、関連のシステムがそのシグナルに反応するようにする。

Timeline チームは、上記の 2 つ目のアプローチを採用しました、何故なら、この方法だとエミッターがレシーバーから独立する形になるからです。エミッターとレシーバーを独立させることで、大きな柔軟性とパワーと再利用性が生まれます。これをより深く理解していただくために、各要素がどのように連携して機能するのかをご説明します。

各要素が連携して機能する仕組み

Signal を使用して外部のシステムとの通信を行うには、Signal Asset、Signal Emitter、 Signal Receiver の 3 つの要素が必要です。

  • Signal Emitter:Signal Emitter には Signal Asset への参照が含まれます。Timeline 上では、Signal Emitter はマーカーによって視覚的に表されます。マーカーは、トラック上、あるいは Timeline の目盛りの下の「Markers」の領域内に配置できます。

  • Signal Receiver: Signal Receiver は反応のリストを含むコンポーネントです。各反応が特定の Signal Asset に紐付けられています。
  • Signal Asset: Signal Asset は特定の Signal Emitter と特定の Signal Receiver を関連付けるものです。同じ Signal Asset を多数の Timeline インスタンス内で再使用できます。

以下は、 画面上に表示された矢印に一致する方向キーを押してウサギのゾンビを倒す単純なゲームです。


矢印は音楽の 1 拍ごとにランダムに変化します。矢印が変わる前に正しい方向キーを押さないとミスになります。方向キーを一定の回数押すとクリアとなります。

このゲームでは、GameTimeline インスタンスにゲームプレイが含まれています。これが Signal を使って 1 拍ごとに新しい矢印を表示します。以下の最終的な GameTimeline インスタンスでこれをご覧いただけます。

シグナルの作成とセットアップ方法をご説明するために、Signal が一切作成されていないプロジェクトから始めましょう。本記事を読みながらお試しになりたい方は、こちらからプロジェクトをダウンロードしていただけます。

まず、Signal を追加する「Markers」の領域を表示するために、クリップ編集モードボタンの横の Marker アイコンをクリックしてください。「Markers」の領域が Timeline の目盛りの下に以下のように表示されます。

Signal Emitter を追加するには、「Markers」の領域内で右クリックし、「Add Signal Emitter」 を選択してください。

Signal Emitter が「Markers」の領域に以下のように表示されます。

今追加した Signal Emitter が選択された状態になり、そのプロパティが Inspector ウィンドウに表示されます。Inspector ウィンドウには、Signal の他の要素を作成するボタンも表示されます。

Signal Emitter を Signal Receiver に紐付けるには、新しい Signal Asset を追加する必要があります。Inspector ウィンドウ内で「Create Signal…」をクリックしてください。Signal Asset に「ShowKey」という名前を付けます(この Signal Asset は、矢印を変化させるために、エミッターをレシーバーに紐付ける目的で使用されるため)。「Save」をクリックすると、この Signal Asset がプロジェクトに追加されます。

さらに、Signal Emitter を Signal Receiver と関連付ける必要もあるので、「Add Signal Receiver」をクリックしてください。Inspector ウィンドウは以下のような表示になります。

先に進む前に、ここで何が起きているのかご説明します。「Add Signal Receiver」ボタンをクリックすると、2 つの事が起こります。新しい Signal Receiver コンポーネントが紐付けられたゲームオブジェクトに追加され、新しい反応が追加されて先ほど作成した Signal Asset に紐付けされます。下の画像のように、「ShowKey」が Emit Signal として表示され、反応のリストにも「ShowKey」が追加されていることから、これらが紐付けされていることが分かります。

以下のように Inspector ウィンドウには、2 つの要素(Signal Emitter プロパティおよび、Signal Receiver コンポーネントによって定義される反応)が表示されます。

Signal Receiver コンポーネントは Timeline インスタンスに関連付けられたゲームオブジェクトに紐付けされていますが、Inspector ウィンドウ内で Signal Receiver の編集が可能です。反応は Signal Receiver がシグナルを受け取った時に実行されます。

最後のステップは、反応が何を実行するかの指定です。この例では、ShowRandomKey メソッドを持つ「Manager」という名前のコンポーネントがあります。このメソッドが新しいランダムな矢印を表示します。この反応に ShowRandomKey メソッドを呼び出させるには、以下のように、Unity Event にこのメソッドを選択します。

これで完了です!Signal Emitter を追加し、その Signal Receiver と反応を追加したら、シーンと通信する Timeline インスタンスの完成です。

Timeline が Signal Emitter に到達すると、「ShowKey」シグナルが発信されます。「ShowKey」シグナルをリッスンしている Signal Receiver が ShowRandomKey メソッドを呼び出します。

しかし、ここで終わりにする必要はありません。複数の Signal Emitter に同じシグナルを発信させることも可能です。例えば以下の Timeline インスタンスは、複製されて異なる時点に移動された同じ Signal Emitter を持っています。音楽のすべての拍に 1 つの Emitter があります。

Signal Asset を Project ウィンドウから直接 Timeline ウィンドウにドラッグすることもできます。Emit Signal プロパティがすでに設定された状態で、Signal Emitter が自動的に作成されます。

すべての Signal が組み込まれた状態で完成したプロジェクトを確認したい方は、こちらからプロジェクトをダウンロードしてください

まとめ

最初のシグナルの設定は、以下の手順で行います。

  1. シグナルに対応する「Marker」の領域内またはトラック上で右クリックし、「Add Signal Emitter…」を選択します。
  2. Inspector ウィンドウで「Create Signal Asset」をクリックし、ファイル名を選択してEnter キーを押します。
  3. 引き続き Inspector で「Create Reaction…」ボタンをクリックし、作成したシグナルに紐付いた反応を設定します。

よくある質問

  • ひとつのゲームオブジェクトに複数のレシーバーを持たせることは可能ですか? はい。ゲームオブジェクトのすべての Signal Receiver が、そのゲームオブジェクトに送られたシグナルを受け取ります。
  • 1 つのSignal Assetを複数の Timeline インスタンスで使用できますか? はい。1 つの Signal Asset を 2 つ以上の Timeline インスタンスで使用可能です。
  • Signal Asset は拡張やカスタマイズが可能ですか? はい。Signal Asset、Signal Emitter、Signal Receiver はすべて拡張可能です。これに関しては後日、カスタマイズに関するブログ記事を別にお届けして詳しく説明します。
  • シグナルは必ず発信されますか? はい。Signal は飛ばされることはありません。ゲームの FPS に関わらず、次のフレームで発信されます。
  • Signal Emitter を含む Timeline Asset の複製を作成した場合はどうなりますか? Signal Emitter は、Signal Asset への参照を保持します。Signal Asset の複製は作成されません。

 

 

21 コメント

コメントの配信登録

コメント受付を終了しました。

  1. Can markers and signal emitter properties be accessed/modified via script? For example, can you change the position of a marker on a timeline during runtime? Create a new marker and assign a Signal asset on a Timeline during runtime?

    My apologies if I missed an obvious answer to this somewhere! Thanks!

    1. Julien Blais

      6月 14, 2019 10:25 pm

      Yes, signal emitter properties can be accessed and modified in a script. You can also change the position of a marker or create a new one and assign a signal at runtime .

  2. I’m just going to go on a limb here and say that not only does this feel over complicated..

    But the “demo” that was shown as an example I think doesn’t quite show it’s full capability. How many here are actually using this to build a Rhythm Game?….

    Maybe having a demo that switches between animation states for a character based or a system that effects the lighting of an environment (all based off a signal) might be a better example for curious developers…

    Going into this as one of those curious developers – I can tell you that after reading this and seeing the provided demo. I’m not interested or intrigued…

    I mean no ill will – just trying to provide useful and critical feedback to hopefully improve the engine I love! :)

    1. Julien Blais

      5月 30, 2019 4:48 pm

      Thanks for your feedback!
      I understand when you say that signals can feel over complicated. At first, it can feel like so. I think that by using signals you will discover why we chose that design. If not, feel free to comment here or on the forums.

      About the demo: Whilst not everybody wants to make a rhythm game, I tried to show a simple example; I wanted to focus solely on signals. I thought it could be a good way to showcase signals in a visual way. Next time I will try to integrate more details for curious developers.

  3. Felix Herbst

    5月 24, 2019 3:52 pm

    I think you forgot a very important case in your Bonus FAQ:
    How are Signals handled if one is manually controlling timeline time? Cases: a) jumping in timeline
    b) syncing timeline from an external source (e.g. “usually going to the next frame but not quite always”)
    c) scrubbing timeline backwards

    1. Julien Blais

      5月 30, 2019 4:26 pm

      Signals are not send while scrubbing (ie calling Evaluate() on a PlayableDirector), so jumping in a timeline or scrubbing backwards will not emit signals.
      However, signal emitters have a Retroactive property, which will emit the signal if the timeline begins playing after the signal. Let’s say you have a signal at time 1 with Retroactive toggled on. If you start playing the timeline at time 2, the signal will be emitted right when the timeline starts playing. This is useful for signals that trigger a LoadScene(), for example.

  4. Russ Painter

    5月 24, 2019 9:07 am

    I’m going to join the others commenting here in expressing that this seems both unnecessarily complicated, and also limited in expected functionality as opposed to an event system where any game object could listen for an event broadcast by a timeline.

    Is the awkward implementation of this going to have some pay-off with DOTS (ECS) that we’re not seeing?

    1. Julien Blais

      5月 30, 2019 4:51 pm

      We chose that design because it makes for a very clear list of dependencies between Timeline and a scene.
      To emit signals on multiple objects at once, you can setup a reaction that will call all the appropriate methods on each GameObjects you want.

      Also, we are still working on how timeline will work in DOTS, so I can’t comment about that right now.

  5. Carl Emil Carlsen

    5月 22, 2019 11:53 am

    I am not sure I understand the design decision of inventing additional assets and concepts for this problem. It seems over complicated. I imagine the decision will potentially result in a confusing ocean of signal assets. I also find it illogical to select a marker that I want to emit/transmit/send from, and then being shown a “SignalReceiver” containing a UnityEvent in the inspector. Why not just add a UnityEvent directly to a marker?

    1. Julien Blais

      5月 30, 2019 4:12 pm

      A marker being an asset, this created problems with UnityEvents, since those need to reference objects in the scene. We also want timelines to be reusable, and having UnityEvents embedded directly in a marker prevented timelines to be reused in multiple scenes.

  6. Im also confused as to why we have to attach to the receiver? Why on have a kind of awake() function execution when the marker is hit and allow the user to add any component to the signal. That way it more of a gameObject activating at a certain time, then we can also script into that marker anything we want. Or maybe I didn’t understand the post.

    1. Julien Blais

      5月 22, 2019 10:21 am

      A Timeline can emit signals to Gameobjects with the following rules:
      – If the signal emitter is on the timeline itself (under the time area), the Gameobject that has the PlayableDirector component used to play the timeline will receive the signals.
      – If the signal emitter is on a track, the Gameobject bound to the track will receive the signals.
      A SignalReceiver component placed on a GameObject will be able to respond to signals. You can then setup what the receiver will do when it receives a signal.

      1. Got it , thanks for clarifying

  7. There is one think I do not understand, the receiver is on the bound object, why ? What if I want many objects to be notified ? I thought a receiver could reference a Signal asset and subscribe to an event which would have been trigger when the Emitter is reached in the Timeline.

    1. Matthew Holtzem

      5月 21, 2019 6:13 pm

      Yeah I second this. you say “The Timeline team went with the second approach because it keeps the emitter independent from the receiver.” but at the end of the day if everything has to be pre-determined and bound together by the timeline it doesn’t really seem like they are independent. If I can’t spawn in a prefab with a signal receiver on it at runtime then I don’t really see what you gain by this asset based approach aside from making it more complicated

      1. A signal is just a scriptable object they are using to pass events – such as described by Ryan Hipple (https://unity3d.com/how-to/architect-with-scriptable-objects).
        A signal receiver is just a component with a reference to a signal; You can spawn in as many prefabs as you want they just need a signal receiver component with a reference to the signal and they will receive the event from the timeline… it’s pretty easy

        1. Matthew Holtzem

          5月 21, 2019 7:45 pm

          That’s how you would think it would work but it doesn’t actually behave that way. In order for a gameObject to receive a signal emitted from the signal emitter it needs to be bound to the timeline. So even though the receiver has a reference to the asset, and the emitter has a reference to the asset, they still need to be connected by a timeline track :(

        2. From what they said in the blog post and in the forum the receiver has to be bound to the timeline so it’s quite different from Ryan Hipple approach which is much more flexible.

    2. Julien Blais

      5月 22, 2019 10:44 am

      Signal emitters will only send signals to objects bound on their parent track (or on the Gameobject that contains the PlayableDirector component, if the emitter is on the marker area).
      We chose that design because it makes for a very clear list of dependencies between Timeline and the scene.
      To emit signals on multiple objects at once, you can setup a reaction that will call all the appropriate methods on each GameObjects you want. A SignalReceiver can invoke methods on any GameObjects in the scene.

      1. It is what it is. But it is not really a convenient and intuitive way to have receiver bounds to the timeline. Regarding the blog post example I could want characters, NPCs, props or whatever (already in scene or dynamically instantiated) be in sync with the timeline audio beats. Be able to simple add a Receiver on those objects to achieve that would have been far easier that put one receiver on the timeline ruler, received the Signal and then re-dispatch the event to all those objets.

  8. Isaac Surfraz

    5月 21, 2019 4:44 pm

    This is awesome stuff, been waiting for this since sometime in 2017 and its finally with us! And it looks as good and as useful as hoped!