2

そこで、静的メソッドをたくさん持つオブジェクトを作成したいと思います。メソッドは、リモート サーバーへの API です。私は読んでいて、ユニティメソッドを使用できると思ってStartCoroutineいましたが、この状況では使用できないため、どこに行けばよいかわかりません。

一般的な考え方は、オブジェクトのメソッドの 1 つを呼び出し、デリゲートを渡し、id をオフにしてその作業を実行できるようにすることです。完了したら、結果でデリゲートを呼び出します。Unity3D はスレッドセーフではないため、スレッドを使用できません。

私は c# がこのyieldことを持っていることを知っており、それについていくつかの場所で読んだことがありますが、まだ混乱しています。以下のコードをリファクタリングして、やろうとしていることを達成するにはどうすればよいですか?

public class Server
{
        private static string baseURL = "http://localhost/game.php";
        private static Hashtable session_ident = new Hashtable();

        //--- Public API
        public delegate void DeviceSeenCallback(bool seen);
        public static void DeviceSeen(DeviceSeenCallback callBack) {
                StartCoroutine(DoDeviceSeen(callBack));
        }

        public delegate void AuthenticateCallback(bool authenticated, string errorMessage);
        public static void Authenticate(string username, string passwordHash, AuthenticateCallback callBack) {
                StartCoroutine(DoAuthenticate(username, passwordHash, callBack));
        }


        //--- Private API
        private static IEnumerator DoDeviceSeen(DeviceSeenCallback callBack)
        {
                WWWForm form = new WWWForm();
                form.AddField("deviceID", SystemInfo.deviceUniqueIdentifier);

                WWW www = new WWW(baseURL + "?cms=seen", form.data, session_ident);
                        yield return www;

                // Check for errors
                callBack(ResultIsOk(www.text));
        }

        private static IEnumerator DoAuthenticate(string username, string passwordHash, AuthenticateCallback callBack)
        {
                WWWForm form = new WWWForm();
                form.AddField("deviceID", SystemInfo.deviceUniqueIdentifier);
                form.AddField("deviceType", SystemInfo.deviceType.ToString() + "||" + SystemInfo.deviceModel);
                form.AddField("user", username);
                form.AddField("pass", passwordHash);

                WWW www = new WWW(baseURL + "?cms=auth", form.data, session_ident);
                        yield return www;

                if (ResultIsOk(www.text)) {
                        callBack(true, "");
                } else {
                        int code;
                        string message;
                        ResultGetError(www.text, code, message);
                        callBack(false, message);
                }
        }

        private static bool ResultIsOk(string resultText) {
                return false;
        }

        private static void ResultGetError(string resultText, out int code, out string message) {
                code = -1;
                message = "Some Error Message";
        }
}
4

2 に答える 2

3

Unity で常に遭遇するトリックは、コードが実行される唯一のコンテキストがスクリプト コールバックの間であるということです。

これは基本的に、最終的にどこかで、繰り返し実行したいコードを呼び出すオブジェクトに MonoBehaviour がアタッチされたゲームオブジェクトが必要になることを意味します。

MonoBehaviour から継承するクラスのインスタンス以外で使用可能な StartCoroutine がないという事実は別として、何かをチェックするために、フレームごとにコードを実行する必要があるという問題があります。MonoBehaviour を作成する以外に、これを回避する実際の方法はありません。ただそれを受け入れるだけです。

一般的なパターンは、DontDestroyOnLoad が呼び出されるか、シーンごとに必要に応じて再作成されるシングルトン風のゲームオブジェクトを作成することです。特定のクラスなどに関連付けられていない「コルーチン バケット」として 1 つのオブジェクトを指定することもできます。文字通り、人生の唯一の目的がコルーチンを開始することである空の MonoBehaviour です。

Server クラスを MonoBehaviour にすることで、この問題をすばやく解決できます。

次に、シングルトン プロパティを追加します。

    private static Server ServerObject {
        get { 
            if (_serverObject == null) {
                var gameObj = new GameObject("Server Object");
                _serverObject = gameObj.AddComponent<Server>();
                GameObject.DontDestroyOnLoad(_serverObject); // Optional
            }
            return _serverObject;
        }
    }
    private static Server _serverObject;

(シングルトンはひどいですが、この状況では必要悪です)

そして、すべてのStartCoroutine呼び出しをシングルトン MonoBehaviour インスタンスで呼び出されるように変更します。

    public static void DeviceSeen(DeviceSeenCallback callBack) {
            this.ServerObject.StartCoroutine(DoDeviceSeen(callBack));
    }

GoKitはこのパターンを使用して、トゥイーンのすべてのロジックを処理する「Go」という名前の単一の GameObject を作成します。Unity は、ゲーム オブジェクトにアタッチせずに定期的に実行するスクリプトを指定する方法を提供していないため、これが私たちにできる最善の方法です。

サーバー クラスが多くの状態を維持する場合、またはそれがシーンの一部であることが必須ではない場合は、それを呼び出さないことをお勧めしますDontDestroyOnLoad。シーンが変わり、ServerObject ゲーム オブジェクトが削除された場合、_serverObject に対する後続のチェックは null として表示され、再インスタンス化されます (Unity が null 変換演算子をオーバーロードするため)。

于 2013-01-26T10:40:41.287 に答える
0

Unity の場合、通常は手動でスレッド化する必要があります (スレッドが Unity API を呼び出さない場合を除きます)。つまり、たとえばAuthenticate、結果をポーリングする関数 (ブロッキング呼び出しなし!) をプライベートな静的リストにプッシュします。次に、リストを調べて各ポーリング メソッドを呼び出す静的Updateメソッドを提供し、終了したことを示す場合は削除します。各ポーリング メソッドが終了したら、関連するコールバックを呼び出す必要があります。アプリケーションがこの静的Updateメソッドを定期的に呼び出すように調整します (たとえば、通常の unity Update パスで)。

于 2013-01-26T10:31:44.987 に答える