Admin.ts

admin ページにアクセスするには、index.html の Admin をクリックします。ユーザー名とパスワード (どちらも admin) を入力後、プレイヤーテーブルを操作して、ゲームコンテンツを操作できます。adminUnity.ts のドキュメントに、アクションに使用するコードがすべて含まれています。

このファイルには、1 つのインターフェイスと 1 つの class があります。

インターフェイス ICommandRequest

ICommandRequest インターフェイスがゲームにコマンドを送信します。

    interface ICommandRequest {
        id: string;
        value: string;
    }

class AdminController

AdminController class には、ストリームへの接続、適切な情報表示、ゲームへのコマンド送信を行うすべてのメソッドが含まれています。

class 以外では、 AdminController のインスタンスを作成し、それに対して onConnect() を実行してストリームへの接続を開始します。

let admin = new unitySample.AdminController("video_player_hidden");
admin.onConnect();

以下のセクションでは、AdminController class の内容について説明します。

onConnect

onConnect()

onConnect メソッドがサービスへの接続を開始します。接続が適切に実行できると、検出した IChannelJoinResponse()on_channel_join を実行します。この処理は、unity.ts ファイルと同一のものです。

        // Start the connection to the services
        onConnect() {
            let promise = $.post("/api/public/channels/join", {}, (joinRep) => {
                this.on_channel_join(<genvid.IChannelJoinResponse>joinRep);
            });
            promise.fail((err) => {
                alert("Can't get the stream info:" + err);
            });
        }

on_channel_join

on_channel_join(info: genvid.IChannelJoinResponse)

on_channel_join メソッドは、サービスとチャネルに接続後、Genvid クライアントを作成します。このプロセスで検出された情報と、class 作成プロセスで送信された video_player_id を使用してクライアントを作成します (これは AdminController class の引数です)。この処理は、unity.ts ファイルと同様のものですが、こちらはメソッドを必要としません。

その後、この class に特定のイベントを関連付ける必要があります。

onStreamsReceived
ストリームコンテンツを受信した時にトリガされます (タイムコードと
ゲームデータの取得に使用)。
onDraw
ビデオで新しいフレームの描画時にトリガします。

次に、start() メソッドでクライアントを開始します。

        // Create the genvid Client and the function listening to it
        private on_channel_join(joinRep: genvid.IChannelJoinResponse) {
            this.streamInfo = joinRep.info;
            this.client = genvid.createGenvidClient(this.streamInfo, joinRep.uri, joinRep.token, this.video_player_id);
            this.client.onStreamsReceived((streams) => { this.on_streams_received(streams); });
            this.client.onDraw((frame) => { this.on_new_frame(frame); });
            this.client.start();
        }

on_streams_received

on_streams_received(dataStreams: genvid.IDataStreams)

on_streams_received メソッドがロープ処理を使用して、ゲームデータに関連付けられた最新のタイムコードを取得します。また、受信した JSON データを IGameData に変換します。これは、Web サイトがストリームを受信したときに呼び出します。この処理は、unity.ts ファイルと同一のものです。

        // Upon receving the stream
        private on_streams_received(dataStreams: genvid.IDataStreams) {
            for (let stream of dataStreams.streams) {
                for (let frame of stream.frames) {
                    if (this.last_game_time_received < frame.timeCode) {
                        this.last_game_time_received = frame.timeCode;
                    }
                }
            }

            // Parse the JSON from each elements
            for (let stream of [...dataStreams.streams, ...dataStreams.annotations]) {
                for (let frame of stream.frames) {
                    frame.user = JSON.parse(frame.data);
                }
            }
        }

on_new_frame

on_new_frame(frameSource: genvid.IDataFrame)

on_new_frame メソッドは、常に更新が必要な様々なタスクを実行します。作成した Genvid クライアント用に、フレームごとに呼び出します。

  1. さまざまな処理を行う前に、ゲームデータを取得してから、そのデータが有効であることを確認する必要があります。

  2. データの妥当性が確認でき、プレイヤーテーブルが作成されていないことが確認できたら、データ (キューブ) からオブジェクトリストを取得します。

  3. オブジェクトごとにループ処理を作成し、それぞれにプレイヤーテーブルを作成します。

  4. プレイヤーテーブルのボタンクリックを検知するためのイベントリスナーも追加します。

  5. ループ処理後に、シーンとカメラ変更のための 2 つのボタンを作成します。

  6. シーンとカメラ変更ボタンのクリックを検知するためのイベントリスナーを追加します。

        // During a new frame, if the game data is valid, the player table is created
        private on_new_frame(frameSource: genvid.IDataFrame) {
            // Parse the JSON from each elements
            let gameDataFrame = frameSource.streams["GameData"];
            let gameData = null;

            if (gameDataFrame && gameDataFrame.user) {

                if (this.message === "Unable to retreive data from the stream, is it still active ?") {
                    this.message = "Success: data received from the stream";
                    this.displayMessage();
                }
                if (this.playerTableSetup === false) {
                    this.playerTableSetup = true;

                    gameData = gameDataFrame.user;
                    let cubes = gameData.cubes;

                    for (let cube of cubes) {
                        let cubeAdd = "<table>" +
                                "<tr>" +
                                    "<td id='table_name'>" + cube.name + "</td>" +
                                "</tr>" +
                                "<tr>" +
                                    "<td>" +
                                        "<div id='command_button' class='" + cube.name + "_upDirection'>↑</div>" +
                                        "<div id='command_button' class='" + cube.name + "_downDirection'>↓</div>" +
                                        "<div id='command_button' class='" + cube.name + "_leftDirection'>←</div>" +
                                        "<div id='command_button' class='" + cube.name + "_rightDirection'>→</div>" +
                                    "</td>" +
                                "</tr>" +
                                "<tr>" +
                                    "<td id='command_button'><div class='" + cube.name + "_reset'>Reset</div></td>" +
                                "</tr>" +
                                "<tr>" +
                                    "<td id='command_button'><div class='" + cube.name + "_slower'>Slower</div></td>" +
                                "</tr>" +
                                "<tr>" +
                                    "<td id='command_button'><div class='" + cube.name + "_faster'>Faster</div></td>" +
                                "</tr>" +
                            "</table>";

                        $(".admin_table_section").append(cubeAdd);
                        let upButton = <HTMLButtonElement>document.querySelector("." + cube.name + "_upDirection");
                        upButton.addEventListener("click", (_event) => { this.setDirection(cube.name, 0, 1); }, false);

                        let downButton = <HTMLButtonElement>document.querySelector("." + cube.name + "_downDirection");
                        downButton.addEventListener("click", (_event) => { this.setDirection(cube.name, 0, -1); }, false);

                        let leftButton = <HTMLButtonElement>document.querySelector("." + cube.name + "_leftDirection");
                        leftButton.addEventListener("click", (_event) => { this.setDirection(cube.name, -1, 0); }, false);

                        let rightButton = <HTMLButtonElement>document.querySelector("." + cube.name + "_rightDirection");
                        rightButton.addEventListener("click", (_event) => { this.setDirection(cube.name, 1, 0); }, false);

                        let resetButton = <HTMLButtonElement>document.querySelector("." + cube.name + "_reset");
                        resetButton.addEventListener("click", (_event) => { this.reset(cube.name); }, false);

                        let slowerButton = <HTMLButtonElement>document.querySelector("." + cube.name + "_slower");
                        slowerButton.addEventListener("click", (_event) => { this.changeSpeed(cube.name, 0.8); }, false);

                        let fasterButton = <HTMLButtonElement>document.querySelector("." + cube.name + "_faster");
                        fasterButton.addEventListener("click", (_event) => { this.changeSpeed(cube.name, 1.25); }, false);
                    }
                    let sceneCameraButtons = "<table>" +
                                "<tr>" +
                                    "<td id='command_button' class='cameraChange'>Camera change</td>" +
                                "</tr>" +
                                "<tr>" +
                                    "<td>" +
                                        "<div id='command_button' class='sceneChange'>Scene change</div>" +
                                    "</td>" +
                                "</tr>" +
                            "</table>";
                    $(".admin_table_section").append(sceneCameraButtons);

                    let cameraButton = <HTMLButtonElement>document.querySelector("." + "cameraChange");
                    cameraButton.addEventListener("click", (_event) => { this.changeCamera(); }, false);

                    let sceneButton = <HTMLButtonElement>document.querySelector("." + "sceneChange");
                    sceneButton.addEventListener("click", (_event) => { this.changeScene(); }, false);

                }
            }
            else {
                this.message = "Unable to retreive data from the stream, is it still active ?";
                this.displayErrorMessage();
            }
        }

setDirection

setDirection(cubeName: string, x: number, z: number)

setDirection はゲームにコマンドを送信し、プレイヤーの向きを設定します。プレイヤーの向きをクリックしたときに呼び出します。

        // Change the direction of the cube
        setDirection(cubeName: string, x: number, z: number) {
            this.message = this.error = "";

            let command: ICommandRequest = {
                id: "direction",
                value: `${cubeName}:${x}:0:${z}`
            };

            let promise = $.post("/api/admin/commands/game", command).then(() => {
                this.message = `Set direction to ${cubeName}:${x}:${z}`;
                this.displayMessage();
            });

            promise.fail((err) => {
                this.message = `Failed with error ${err} to do Set direction to ${cubeName}:${x}:${z}`;
                this.displayErrorMessage();
            });
        }

changeSpeed

changeSpeed(cubeName: string, factor: number)

changeSpeed メソッドは、ゲームにコマンドを送信し、オブジェクトの低速化、または高速化を指示します。プレイヤーの SlowerFaster をクリックしたときに呼び出します。

        // Change the speed of the cube
        changeSpeed(cubeName: string, factor: number) {
            this.message = this.error = "";

            let command: ICommandRequest = {
                id: "speed",
                value: `${cubeName}:${factor}`
            };

            let promise = $.post("/api/admin/commands/game", command).then(() => {
                this.message = `changeSpeed ${cubeName}:${factor}`;
                this.displayMessage();
            });

            promise.fail((err) => {
                this.message = `Failed with error ${err} to do changeSpeed ${cubeName}:${factor}`;
                this.displayErrorMessage();
            });
        }

reset

reset(cubeName: string)

reset メソッドは、ゲームにコマンドを送信し、オブジェクトを元の位置に戻します。プレイヤーの Reset をクリックしたときに呼び出します。

        // Reset the position of the cube
        reset(cubeName: string) {
            this.message = this.error = "";

            let command: ICommandRequest = {
                id: "reset",
                value: cubeName
            };

            let promise = $.post("/api/admin/commands/game", command).then(() => {
                this.message = `reset ${cubeName}`;
                this.displayMessage();
            });

            promise.fail((err) => {
                this.message = `Failed with error ${err} to do reset ${cubeName}`;
                this.displayErrorMessage();
            });
        }

changeCamera

changeCamera()

changeCamera メソッドは、ゲームにコマンドを送信し、現在のカメラを変更します。プレイヤーの Camera change ボタンをクリックしたときに呼び出します。

        changeCamera() {
            this.message = this.error = "";

            let command: ICommandRequest = {
                id: "camera",
                value: "change"
            };

            let promise = $.post("/api/admin/commands/game", command).then(() => {
                this.message = `camera change done`;
                this.displayMessage();
            });

            promise.fail((err) => {
                this.message = `Failed with error ${err} to change the camera`;
                this.displayErrorMessage();
            });
        }

changeScene

changeScene()

changeScene メソッドは、ゲームにコマンドを送信し、現在のシーンを変更します。プレイヤーの Scene change ボタンをクリックしたときに呼び出します。

        changeScene() {
            this.message = this.error = "";

            let command: ICommandRequest = {
                id: "scene",
                value: "change"
            };

            let promise = $.post("/api/admin/commands/game", command).then(() => {
                this.message = `scene change done`;
                this.displayMessage();
            });

            promise.fail((err) => {
                this.message = `Failed with error ${err} to change the scene`;
                this.displayErrorMessage();
            });
        }

displayMessage

displayMessage()

displayMessage メソッドは、実行した操作が正常に行われたことを示すメッセージを表示します。ストリームから適切にデータを取得するかどうかを確認したり、コマンド操作が成功したかどうかを確認する場合に役立ちます。

        // Display a message in the page as a sucess
        displayMessage() {
                let messageErrorDiv = <HTMLDivElement>document.querySelector("#alert_error_cube");
                messageErrorDiv.style.visibility = "hidden";

                let messageDiv = <HTMLDivElement>document.querySelector("#alert_sucess_cube");
                messageDiv.style.visibility = "visible";
                let messageSpan = <HTMLSpanElement>document.querySelector("#sucess_message_cube");
                messageSpan.textContent = this.message;
        }

displayErrorMessage

displayErrorMessage()

displayErrorMessage メソッドは、実行した操作のエラーメッセージを表示します。ストリームから適切にデータを取得できなかったことを確認したり、コマンド操作が失敗したかどうかを確認する場合に役立ちます。

        // Display a message in the page as an error
        displayErrorMessage() {
                let messageDiv = <HTMLDivElement>document.querySelector("#alert_sucess_cube");
                messageDiv.style.visibility = "hidden";

                let messageErrorDiv = <HTMLDivElement>document.querySelector("#alert_error_cube");
                messageErrorDiv.style.visibility = "visible";
                let messageSpan = <HTMLSpanElement>document.querySelector("#error_message_cube");
                messageSpan.textContent = this.message;
        }