お問い合わせ

ブログ

これまでに経験してきたプロジェクトで気になる技術の情報を紹介していきます。

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

T, M T, M 3 years
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を使ってのリアルタイム同期通信について学ぶ③
https://www.aska-ltd.jp/jp/blog/108

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

コメントはありません。

4305

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

お問い合わせ
gomibako@aska-ltd.jp