• T, M T, M
  • — 3 weeks ago
Unity初心者がawsサーバーとWebSocketを使ってのリアルタイム同期通信について学ぶ②

◆まえがき

さて、ここからはサーバー部となります。

なお、本ブログは「Unity初心者がawsサーバーとWebSocketを使ってのリアルタイム同期通信について学ぶ①」の続きとなります。
もし前を見ていない方は下記より、見て頂ければと思います。

Unity初心者がawsサーバーとWebSocketを使ってのリアルタイム同期通信について学ぶ①: https://www.aska-ltd.jp/jp/blog/105

サーバー部ではタイトル通り、AWS(Amazon Web Services)上に、WebSocket通信のプログラムを構築していきます。
なお、WebSocket通信のプログラムはnode.jsを使っての実装となります。
AWSを使用するため、こちらは最低限AWSの構築が出来き、コンソールで接続できる事を前提として記載いたします。
その点については、ご了承お願いいたします。

◆使用するサーバーについて

使用するサーバー構成は下記の通りとなります。
実験なので使うものは極力最低限にしています。
この辺りのサーバーの作成と設定はAWSのコンソール画面より設定しています。

AWS EC2 instance
    t2micro
    OS:Amazon Linux

Security group
    type:Custom TCP Rule
    protocol:TCP
    port range:3000
    source:anywhere

◆サーバーへのソフトウェアのインストール

実装はnode.jsで行います。
そのため下記のnode.js関連のツールをサーバーへインストールします。
インストールする内容は、ざっと説明すると下記の通りです。

・gcc   // コンパイルするのに必要な開発ツール
・git   // gitコマンドを使用するためのアプリ
・nvm   // node.jsのバージョンを管理するツール
        // ※これを利用して指定バージョンのnode.jsをインストールします。

インストールまでの手順は下記の通りです。
サーバーのコンソール上で、ざっとNode.js関連のアプリのインストールからインストール確認までを行います。

// OSの更新
$ sudo yum update

// 必要な開発ツールのインストール
$ sudo yum -y install gcc-c++
$ sudo yum -y install git

// nvmのダウンロード
$ git clone https://github.com/creationix/nvm.git ~/.nvm

// nvm実行コマンドのパス設定
$ source ~/.nvm/nvm.sh

// 再ログイン時に設定したパスが有効になるように、プロフィールファイルに下記を追加
$ vi /home/[ログインユーザー名]/.bash_profile\

========================================
# nvm
if [[ -s ~/.nvm/nvm.sh ]] ; then
        source ~/.nvm/nvm.sh ;
fi
========================================

// インストール可能なNode.jsのバージョンをチェック
$ nvm ls-remote
     ...
     14.15.0
     14.15.1
     15.0.0
     15.0.1
     15.1.0
     15.2.0
     15.2.1
     15.3.0
     ・・・ なんか一杯でできます。

// Node.jsの14.15.1をインストール
$ nvm install 14.15.1

// 使用するバージョンを指定
$ nvm use v14.15.1

// 有効なNode.jsのバージョンを確認 使用するバージョンは(v14.15.1)となります。
$ node -v
v14.15.1

◆WebSocketのPGの作成

Node.jsでサーバー側のWebSocket用のプログラムを作成します。
作成内容は下記の通りとなります。

// 「ws.js」というファイルを作成
$ vi ~./ws.js

// ファイルを下記内容に編集
========================================
const WebSocket = require('ws');
const wss = new WebSocket.Server({
    port: 3000
});

const rooms = {
    room1: {}
}

/**
 * WebSocket 接続
 */
wss.on('connection', function connection(ws) {

    /**
     * WebSocket メッセージ受信
     * 
     * @param string json 
     */
    ws.on('message', function incoming(json) {

        // 受け取ったJSONを配列にパース
        const arg = JSON.parse(json)

        // アクション毎の各処理を実行
        switch (arg.action) {
            case 'connect':     // Roomへの入室
                onJoin(arg)
                break;
            case 'disconnect':  // Roomからの退室
                onLeave(arg)
                break;
            case 'move':        // 座標移動
                onMove(arg)
                break;
            default:
                break;
        }
    });

    /**
     * WebSocket 切断
     */
    ws.on('close', () => {
        delete rooms['room1'][ws.user]
    })

    /**
     * Roomへの入室
     * 
     * @param {Object} arg 
     */
    function onJoin(arg) {

        // set message
        rooms['room1'][arg.user] = arg

        // return json
        sendAll(rooms)

        // action after wait
        waitAction(arg.user);
    }

    /**
     * Roomからの退室
     * 
     * @param {Object} arg 
     */
    function onLeave(arg) {

        // delete user from rooms
        delete rooms['room1'][arg.user]

        // return json
        sendAll(rooms)
    }

    /**
     * 移動
     * message move
     * 
     * @param {Object} arg 
     */
    function onMove(arg) {

        // set message 
        rooms['room1'][arg.user] = arg

        // emit event
        sendAll(rooms)

        // action after wait
        waitAction(arg.user);
    }

    /**
     * WebSocket 待機
     */
    function waitAction(user) {
        rooms['room1'][user].action = 'wait'
    }

    /**
     * WebSocket 一斉送信
     */
    function sendAll(message) {
        wss.clients.forEach(client => {
            client.send(JSON.stringify(message))
        })
    }
})
========================================

処理の説明をすると下記のようになります。

・ポートの設定
WebSocketサーバーの読込と、接続ポートの設定です。

> const WebSocket = require('ws');
> const wss = new WebSocket.Server({
>     port: 3000
> });

接続オブジェクト名は「wss」にしています。
接続ポートは「3000」に設定しています。

・ル―ムの設定
接続する部屋(room)の設定です。

> const rooms = {
>     room1: {}
> }

ここでは簡単にするために「room1」に固定です。
余裕があれば部屋を複数管理する事を念頭に、ソースを修正してみてもいいかもしれません。

・「wss.on('connection', ・・・」
クライアントよりWebSocketサーバーへ接続した(クライアントの「webSocket.Connect」実行時)時の処理です。
接続後はこのメソッド内のメソッドが通信時に実行されます。

・「ws.on('message', ・・・」
クライアントよりWebSocket通信が発生した時の(クライアントの「webSocket.Send」実行時)時の処理です。
クライアントから通信が発生すると、下記内容の「json文字列」がサーバーへ送信されてきます。



送信された「Json文字列」のactionの内容より、下記の処理が実行されます。

'connect'
    ROOM入室時の処理で「onJoin」メソッドを実行
'disconnect'
    ROOM退室時の処理で「onLeave」メソッドを実行
'move'
    移動した時の処理で「onMove」メソッドを実行

・「ws.on('close', ・・・」
クライアントがWebSocketサーバーから切断した(クライアントの「webSocket.Close」実行時)時の処理です。
room変数から切断したクライアントの情報を削除しています。

・「onJoin」
クライアントが部屋に入室(action:connect の通信発生時)した時に実行するメソッドです。
入室したプレイヤーの情報をRoomに追加し、全プレイヤーに送信します。
送信後は、入室したプレイヤーの状態を待機にします。

・「onLeave」
クライアントが部屋から退室(action:disconnect の通信発生時)した時に実行するメソッドです。
退室したプレイヤーの情報をRoomから削除し、全プレイヤーに送信します。

・「onMove」
クライアントが移動(action:move の通信発生時)した時に実行するメソッドです。
Roomの移動したプレイヤーの情報を更新し、全プレイヤーに送信します。
送信後は、移動したプレイヤーの状態を待機にします。

・「waitAction」
room内の指定プレイヤーを待機状態に設定するメソッドです。
接続後、移動後にこの処理が実行されます。

・「sendAll」
引数に指定された配列の情報をJSON形式に変換し、全プレイヤーに送信するメソッドです。
送信する内容は、ここではROOMの内容となり、下記の内容となります。

処理の説明は以上となります。

◆サーバー側のWebSocketのPGの実行

作成したプログラムを実行します。

$ node ws.js

実行するとWebSocketサーバーが立ち上がり、コンソールが実行状態になります。
すぐにクライアント側から接続はしないので、起動を確認したら一旦「Ctrl+C」で強制終了させておきます。

ここまで出来れば、後はクライアントとサーバーと同期だけとなります。

次回:Unity初心者がawsサーバーとWebSocketを使ってのリアルタイム同期通信について学ぶ③
※来月公開予定

T, M

System engineer

Unity初心者がawsサーバーとWebSocketを使ってのリアルタイム同期通信について学ぶ②

お気軽に
お問い合わせください。

お問い合わせ