Admin.js

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

このファイルには 1 つの class があります。

class AdminController

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

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

let admin = new AdminController("video_player_hidden");
admin.start();

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

start

start()

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

  // Starts the connection to the services
  start() {
    fetch("/api/public/channels/join", {
      method: "POST",
    })
      .then((data) => data.json())
      .then((res) => this.onChannelJoin(res))
      .catch((error) => genvid.error(`Can't get the stream info: ${error}`));
  }

onChannelJoin

onChannelJoin(joinRep)

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

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

onStreamsReceived
ストリームコンテンツを受信した時にトリガされます。(ゲームデータの取得に使用)

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

  // Creates the genvid Client and the function listening to it
  onChannelJoin(joinRep) {
    this.client = genvid.createGenvidClient(
      joinRep.info,
      joinRep.uri,
      joinRep.token,
      this.videoPlayerId
    );
    this.client.onStreamsReceived((streams) => {
      this.onStreamsReceived(streams);
    });
    this.client.onNotificationsReceived((notifications) => {
      this.onNotificationsReceived(notifications);
    });
    this.client.start();
  }

onStreamsReceived

onStreamsReceived(dataStreams)

onStreamsReceived` メソッドは、常に更新を必要とする様々なタスクを実行します。Genvid クライアント用に作成したストリームとフレームごとに、Web サイトが受信した際にコールします。この処理は、 web.js ファイルの中で全く同じ方法で行います。

  1. まず、プレイヤーテーブルが作成されていないことを確認します。

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

  3. データの妥当性が確認できたら、データ (キューブ) からオブジェクトリストを取得し、JSON データを変換します。

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

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

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

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

  onStreamsReceived(dataStreams) {
    for (const stream of dataStreams.streams) {
      switch (stream.id) {
        case "Ability":
          for (const frame of stream.frames) {
            let abilities = JSON.parse(frame.data).ability;
            if (abilities) {
              this.canChangeCamera = abilities[0]; // will be used by changeCamera
              this.canChangeScene = abilities[1]; // will be used by changeScene
            }
          }
          
          if (this.canChangeCamera) {
            let cameraButton = document.getElementById("cameraChange");
            cameraButton.removeAttribute("disabled");
            cameraButton.addEventListener(
              "click",
              () => {
                this.changeCamera();
              },
              false
            );
          }

          if (this.canChangeScene) {
            let sceneButton = document.getElementById("sceneChange");
            sceneButton.removeAttribute("disabled");
            sceneButton.addEventListener(
              "click",
              () => {
                this.changeScene();
              },
              false
            );
          }
          break;

        case "Names":
          for (const frame of stream.frames) {
            const cubeNames = JSON.parse(frame.data).name;
            let cubeControlPanel = document.getElementById(
              "admin_prototype_panel"
            );
            for (const name of cubeNames) {
              let cubeControlPanelClone = cubeControlPanel.cloneNode(true);
              cubeControlPanelClone.id = name;
              cubeControlPanelClone.querySelector(
                ".table_name"
              ).innerText = name;
              document
                .querySelector(".admin_table_section")
                .append(cubeControlPanelClone);
              let upButton = cubeControlPanelClone.querySelector(
                ".upDirection"
              );
              upButton.addEventListener(
                "click",
                () => {
                  this.setDirection(name, 0, 1);
                },
                false
              );

              let downButton = cubeControlPanelClone.querySelector(
                ".downDirection"
              );
              downButton.addEventListener(
                "click",
                () => {
                  this.setDirection(name, 0, -1);
                },
                false
              );

              let leftButton = cubeControlPanelClone.querySelector(
                ".leftDirection"
              );
              leftButton.addEventListener(
                "click",
                () => {
                  this.setDirection(name, -1, 0);
                },
                false
              );

              let rightButton = cubeControlPanelClone.querySelector(
                ".rightDirection"
              );
              rightButton.addEventListener(
                "click",
                () => {
                  this.setDirection(name, 1, 0);
                },
                false
              );

              let resetButton = cubeControlPanelClone.querySelector(".reset");
              resetButton.addEventListener(
                "click",
                () => {
                  this.reset(name);
                },
                false
              );

              let slowerButton = cubeControlPanelClone.querySelector(".slower");
              slowerButton.addEventListener(
                "click",
                () => {
                  this.changeSpeed(name, 0.8);
                },
                false
              );

              let fasterButton = cubeControlPanelClone.querySelector(".faster");
              fasterButton.addEventListener(
                "click",
                () => {
                  this.changeSpeed(name, 1.25);
                },
                false
              );
            }

            cubeControlPanel.remove();

            this.cubesStreamReceived = true;
          }
          break;
      }
      if (this.cubesStreamReceived) {
        this.client.onStreamsReceived(null);
        this.playerTableSetup = true;
      }
    }
  }

sendCommands

sendCommands(bodyCommands, successMessage, errorMessage)

sendCommands` メソッドは AdminController クラスのメソッドから受け取ったコマンドをゲームに送信します。表示するすべてのメッセージを displayMessagedisplayErrorMessage メソッドに転送します。

  sendCommands(bodyCommands, successMessage, errorMessage) {
    fetch("/api/admin/commands/game", {
      method: "POST",
      body: JSON.stringify(bodyCommands),
      headers: {
        "Content-Type": "application/json",
      },
    })
      .then(() => {
        this.displayMessage(successMessage);
      })
      .catch((err) => {
        this.displayErrorMessage(`Failed with error ${err} ${errorMessage}`);
      });
  }

setDirection

setDirection(cubeName, x, z)

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

  // Changes the direction of the cube
  setDirection(cubeName, x, z) {
    const commands = {
      id: "direction",
      value: `${cubeName}:${x}:0:${z}`,
    };
    const successMessage = `Command sent.`;
    const errorMessage = `to set direction to ${cubeName}:${x}:${z}`;

    this.sendCommands(commands, successMessage, errorMessage);
  }

changeSpeed

changeSpeed(cubeName, factor)

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

  // Changes the speed of the cube
  changeSpeed(cubeName, factor) {
    const commands = {
      id: "speed",
      value: `${cubeName}:${factor}`,
    };
    const successMessage = `Command sent.`;
    const errorMessage = `to changeSpeed ${cubeName}:${factor}`;

    this.sendCommands(commands, successMessage, errorMessage);
  }

reset

reset(cubeName)

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

  // Resets the position of the cube
  reset(cubeName) {
    const commands = {
      id: "reset",
      value: cubeName,
    };
    const successMessage = `Command sent.`;
    const errorMessage = `to reset ${cubeName}`;

    this.sendCommands(commands, successMessage, errorMessage);
  }

changeCamera

changeCamera()

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

  changeCamera() {
    const commands = {
      id: "camera",
      value: "change",
    };
    const successMessage = "Camera change done";
    const errorMessage = "to change the camera";

    this.sendCommands(commands, successMessage, errorMessage);
  }

changeScene

changeScene()

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

  changeScene() {
    const commands = {
      id: "scene",
      value: "change",
    };
    const successMessage = "Scene change done";
    const errorMessage = "to change the scene";

    this.sendCommands(commands, successMessage, errorMessage);
  }

displayMessage

displayMessage()

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

  displayMessage(message) {
    let messageErrorDiv = document.querySelector("#alert_error_cube");
    messageErrorDiv.style.visibility = "hidden";
    let messageNotificationDiv = document.querySelector(
      "#alert_notification_cube"
    );
    messageNotificationDiv.style.visibility = "hidden";
    let messageDiv = document.querySelector("#alert_success_cube");
    messageDiv.style.visibility = "visible";
    let messageSpan = document.querySelector("#success_message_cube");
    messageSpan.textContent = message;
  }

displayErrorMessage

displayErrorMessage()

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

  displayErrorMessage(message) {
    let messageNotificationDiv = document.querySelector(
      "#alert_notification_cube"
    );
    messageNotificationDiv.style.visibility = "hidden";
    let messageDiv = document.querySelector("#alert_success_cube");
    messageDiv.style.visibility = "hidden";
    let messageErrorDiv = document.querySelector("#alert_error_cube");
    messageErrorDiv.style.visibility = "visible";
    let messageSpan = document.querySelector("#error_message_cube");
    messageSpan.textContent = message;
  }