2022年09月29日

新人がリアルタイムオセロゲームを実装してみた 後編

はじめに

「新人がリアルタイムオセロゲームを実装してみた 」の後編記事となります。

前編ではAgora Video SDKをオセロゲームに実装し、映像通話をするところまで完成させました。

今回は主にAgoraRTM SDKを用いて、周辺の機能を追加していきます。

ガイドブックダウンロード  【大充実】通話・配信SDK「Agora」ガイドブック  通話・配信サービス開発や、配信技術のリプレイスを検討中の方、必見の内容です。 Agora SDKの特徴から活用例まで徹底解説! 無料ダウンロード

Agoraの利用用途

  • Agora Video SDK for Web : 映像音声の送受信、映像音声のミュート・ミュート解除
  • Agora RTM (Real-time Messaging) SDK for Web : オセロゲーム機能、ゲーム参加者数の取得、ゲーム開始情報の送受信
    (今回はこちらの実装記事です。)

実装概要

今回は、前編の記事までの内容に加えてAgoraRTM SDKを導入し、チャット機能やリアルタイムでのオセロ対戦が出来るようにしていきます。

実装

スタート画面

スタート画面の作成をします。
「対戦する」又は「観戦する」を押下してメイン画面に入室する実装です。
プレイヤー名を入力してから、「対戦する」を選択できるように実装しました。
「対戦する」でゲーム画面に遷移したら、前半の記事で導入したwebRTCを使用して自分の映像が左上、相手の映像は右上に表示されるようになっています。

Othello-2_01

チャットの実装

対戦者は映像・音声でコミュニケーション可能ですが、観客もコミュニケーションが取れるよう、テキストチャット機能を追加します。
チャットの実装には、AgoraのRTMSDKを使用します。
RTMSDKの機能であるchannel messageの送受信により、リアルタイムチャットを実現します。

Othello-2_02

※チャット部分の実装コードを抜粋


    const myRtmClient: RtmClient = AgoraRTM.createInstance(appId);
    const myRtmChannel: RtmChannel = myRtmClient.createChannel(channel);
    
    function joinRtm(){
     
        myRtmClient.on("ConnectionStateChanged", (newState, reason) => {
          console.log("on connection state changed to " + newState + " reason:" + reason);
        });
        myRtmChannel.on('MemberLeft', memberId => {
          alert("プレイヤーが退出しました");
          leave();
        })
        
        //Log in the Agora RTM system
        myRtmClient.login({uid: "" + client?.uid}).then(function(){
          console.log("AgoraRTM client login success");
          myRtmChannel.join().then(function(){
            console.log("AgoraRTM client join success");
            myRtmChannel.getMembers().then(function(uidList){
              if(localStorage.getItem('role') != 'audience') setRole(uidList);
            })
            receiveChannelMessage();
          }).catch(function (err){
            console.log("AgoraRTM client join failure, ", err);
          });
        }).catch(function(err){
          console.log("AgoraRTM client login failure, ", err);
        });
      }
     
      //チャンネルメッセージの送信
      function sendMessage(){
      
        var form = document.getElementById("messageForm") as HTMLInputElement;
        var message = form.value;
     
        myRtmChannel.sendMessage({ text: message }).then(() => {
          console.log("sendMessage");
          addMessageList("あなた : " + message);
          form.value = "";
        }).catch(error => {
          console.log(error);
        })
      }
     
      //チャンネルメッセージの受信
    function receiveChannelMessage(){
    
    
        myRtmChannel.on("ChannelMessage", function (sentMessage, senderId) {
          var message: string = JSON.parse(JSON.stringify(sentMessage)).text;
          console.log("メッセージ取得");
          console.log("メッセージ受信: " + JSON.stringify(sentMessage) + " from " + senderId);
          addMessageList(message);
          }
        })
    }
     
    //受信したメッセージをチャット欄に追加
    function addMessageList(message: string){
        var comment_element = document.createElement('li');
        comment_element.textContent = message;
        document.getElementById("comments")!.appendChild(comment_element);
    }
    

オセロ対戦部分の実装

オセロのアルゴリズムの大部分は、下記記事を参考にしました。
参考:https://magazine.techacademy.jp/magazine/22767

肝心の「遠隔リアルタイム対戦の実現」においても、RTMSDKを使用します。

自分が石をどこに置いたかの情報をchannel messageに乗せて送る事で、盤面の状況を共有することが出来ます。

石の位置情報messageの内容は`placeOthelloPiece:${置いた場所を示す番号}`とすることで通常チャットと区別して処理します。


    //オセロの駒をどこに置いたかを伝え、盤面を相手に同期させる
    function sendPlaceOthelloPieces(index: number){
      myRtmChannel.sendMessage({ text: `placeOthelloPiece:${index}` }).then(() => {
        console.log("sendPlaceOthelloPieces(" + index + ")");
      }).catch(error => {
        console.log("errorだよ:" + error);
      }) 
    }
   
  //メッセージ受信時の挙動に場合分けを追加
    function receiveChannelMessage(){
      myRtmChannel.on("ChannelMessage", function (sentMessage, senderId) {
        var message: string = JSON.parse(JSON.stringify(sentMessage)).text;
        if(message.indexOf("placeOthelloPiece:") === 0){
          placeOpponentOthelloPiece(message);
        }else{
          console.log("メッセージ取得");
          console.log("メッセージ受信: " + JSON.stringify(sentMessage) + " from " + senderId);
          addMessageList(message);
        }
      })
    }
   
  //相手の打ち手を自分の画面で反映させる
  function placeOpponentOthelloPiece(message: string){
    var placeNum: number = Number(message.substring(18));
    onClickSquare(placeNum);     //自分が自分の番に石を置いた時と同じ処理
  }

またAgoraの機能とは少し異なりますが、対戦であるため現在どちらの手番であるかを直感的に分かるようにしたり、相手の手番の間は盤面のクリックを無効化するなどの工夫は別途で施す必要があります。

下の図は、実際に社内で対戦した様子です!

Othello-2_01

参照

Agora.io Developer Center : Agora Web SDK API Reference

Agora.io Developer Center : RTM API Reference

Bootstrap

最後に

ここまでの実装を通して、Agoraを用いる事で映像配信や通信部分の実装工数を抑え、自分達がオリジナリティーをもって実装したい箇所に時間を使えました!

今回はAgoraの中でも基本的な機能のみを用いて制作しましたが、まだAgoraを知ってから日が浅い社員でも満足いくゲームを作成することができました!

皆様も是非Agoraを使って面白いアプリを作っていただければ幸いです。

 

 

※『オセロ』は株式会社オセロが保有する登録商標です。

資料ダウンロード  【一気に読める!】Agora 導入事例集  オンラインフィットネス・カウンセリング、音声サービスやファンサービスなど、バラエティに富んだ導入事例をご紹介! 無料ダウンロード
菊名 良一&礒部 洸生

執筆者菊名 良一&礒部 洸生

株式会社ブイキューブ 技術本部
Agoraの技術サポートを担当。

関連記事

先頭へ戻る