web-dev-qa-db-ja.com

Unityのシンプルなイベントシステム

Unityでイベントシステム(C#の方法)を使用しようとしていますが、実装に問題があります。

ほとんどの例では、ハンドラーを定義する1つのクラスを示しています。次に、同じクラス、ハンドラーのシグネチャに一致する関数を記述し、イベントを静的として記述します

public class EventExample : MonoBehaviour
{
    public delegate void ExampleEventHandler();
    public static event ExampleEventHandler OneDayPassed;

    public static void NextTurn()
    {
        // do stuff then send event
        if (OneDayPassed != null)
            OneDayPassed();
    }
}

次に、別のクラスでイベントをサブスクライブし、実際に何かを行う関数を作成します

public class EntityWatcher: MonoBehaviour
{
    void Start()
    {
        EventExample.OneDayPassed += this.PrepareNextDay;
    }

    public void PrepareNextDay()
    {
        // Do other stuff that happen after the day is done

    }
}

これまでのところ問題はありませんが、どのように設計すればよいかわからないため、特定のタイプのGameObjectがこのイベントをサブスクライブします。たとえば、GOのスタッフカテゴリがあり、それが8から6まで機能していて、実行時にそれらをインスタンス化したとします。このカテゴリのメインクラスにサブスクライブする必要がありますか、それとも、イベントにサブスクライブする、ゲームオブジェクトプレハブにアタッチするスクリプトを作成する必要がありますか?

目的は、スポーツセンターで8から6シフトを行う必要のあるすべてのスタッフメンバーが「一日の終わり」イベントがいつ発生するかを知っていることですが、インスタンス化するすべてのプレハブをサブスクライブしたくありません。

私の理解から、必要なコードを含むスクリプトをプレハブに添付する必要がありますが、それが実際にそれを行う方法であるかどうかを示す実用的な例が見つかりません。

5
user393267

UnityEventを使用する必要があります。

_    public UnityEvent whoa;
_

とても簡単です。

スクリプトBigScript.csを作成する

_using UnityEngine;
using System.Collections;
using UnityEngine.Events;

public class BigScript:MonoBehaviour
    {
    [Header("Here's a cool event! Drag anything here!")]
    public UnityEvent whoa;
    }
_

ゲームオブジェクトの上に置きます。今インスペクタで見てください。

「whoa」イベントが表示されます。

otherスクリプトをそこにドラッグするだけで、 "whoa"が発生したときに、これらのotherスクリプトで何かが起こります。

enter image description here

とても簡単です。 BigScriptでイベントを呼び出すには、

_public class BigScript:MonoBehaviour
    {
    [Header("Here's a cool event! Drag anything here!")]
    public UnityEvent whoa;

    private void YourFunction()
      {
      whoa.Invoke();
      }
_

(必要に応じて:if (whoa!=null) whoa.Invoke();


まれに、エディターで単にドラッグするのではなく、リスナーを追加する必要がある場合がありますvia code。これは簡単です:

_whoa.AddListener(ScreenMaybeChanged);
_

になる必要はありません-ドラッグして接続します。これは完全を期すためだけです。)


これですべてです。

インターネット上のこのトピックに関する古いコード例に注意してください。*


上記は、引数のない単純な関数を接続する方法を示しています

引数が必要な場合:

関数に1つのFLOAT引数がある例:

このコードをファイルの先頭に追加するだけです。

_[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}
_

その後、通常どおり続行します。とても簡単です。

_...
using UnityEngine.Events;

// magic line of code...
[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}

public class SomeThingHappens : MonoBehaviour
{
    public _UnityEventFloat changedLength;
    public _UnityEventFloat changedHeight;

    ... and then ... 

    void ProcessValues(float v)
    {
        ....
        if (changedLength != null) changedLength.Invoke(1.4455f);
    }
}
_

他の関数からこの関数のエディタースロットにドラッグすると、次のようになります。

絶対に上にあるものを使用してください-"Dynamic float"。

enter image description here

混乱を招くように、関数リストされます下部の「静的パラメータ」セクションにあります!

それはUnityの巨大なゴッチャです!

21
Fattie

あなたが数十について話しているだけなら、加入者の数についてあまり心配しないでください。はい、数百または数千に入ったら、これを最適化することをお勧めしますが、それでもなおです。最適化の最初のルール:最適化しないでください。

つまり、すべてのインスタンスにイベントをサブスクライブさせ、それで処理を完了するだけです。

1
Thomas Hilbert