こんにちは、あんはるです!
コロナで暇なので、紹介してなかったプロジェクトを紹介したいと思います.
突然ですけど、このGIF見てみてください.
右のウィンドウと左のウィンドウはサーバー経由で座標を共有しあっています〜
これが簡易マルチプレイです!
きっかけ・目的
荒野行動を始めると、100人のユーザーがリアルタイムに走っててすごいなぁと思いました。どうやったらこんなサーバ作れるのだろうという興味がきっかけです。
とりあえず、自前で実装してみたい!となったのでやってみます。
# このプロジェクトの構成
バックエンド
- gRPC
- MongoDB
フロントエンド
- Unity
です。
上のデモはローカルで完結させてます。
なぜgRPC?
Unityで、リアルタイムに処理したいという時に、MagicOnion – C#による .NET Core/Unity 用のリアルタイム通信フレームワークがよく記事に書かれています。
MagicOnionの通信は、gRPCを用いています。
また、Protocol BufferでRPCの定義をするだけで、ホスト、クライアントのコードが生成されることに無駄のなさを感じでクールだなと感じだので、使ってみたいと思いました。
なぜMongoDB?
速度が求められるので。
マルチプレイサーバー
ソースコードは、https://github.com/anharu2394/multiplay-grpc-server
Rustで書いてみた
このプロジェクトを書いた当時、一番Githubスター数が多かったgrpc-rsを使いました。
Protocol Bufferでマルチプレイサーバーの使用を定義。
UserPositionは、ユーザーのidとどこにいるかを表しています。
ConnectPositionで双方向ストリーミングで座標を同期しています。
syntax = "proto3";
package anharu;
service Multiplay {
rpc GetUsers(GetUsersRequest) returns (stream GetUsersResponse);
rpc SetPosition(stream SetPositionRequest) returns (SetPositionResponse);
rpc ConnectPosition(stream ConnectPositionRequest) returns (stream ConnectPositionResponse);
}
message GetUsersRequest {
string room_id = 1;
}
message GetUsersResponse {
repeated UserPosition users = 1;
}
message UserPosition {
string id = 1;
double x = 2;
double y = 3;
double z = 4;
}
message SetPositionRequest {
string id = 1;
double x = 2;
double y = 3;
double z = 4;
}
message SetPositionResponse {
string status = 1;
string id = 2;
string error = 3;
}
message ConnectPositionRequest {
string id = 1;
double x = 2;
double y = 3;
double z = 4;
}
message ConnectPositionResponse {
repeated UserPosition users = 1;
}
service User {
rpc Create (CreateUserRequest) returns (CreateUserResponse);
}
message CreateUserRequest {
string name = 1;
}
message CreateUserResponse {
string id = 1;
}
そして、protoから生成されたコードを使って、それぞれ実装していきました。
マルチプレイクライアント
ソースコードは、 https://github.com/anharu2394/multiplay-grpc-client
Unityなのでc#で書いてます。
Unityはそもそも、gRPCを使う環境を整えるのに時間がかかりました...
https://note.com/npaka/n/n050b1aba7772
これを参考にすると分かりやすいと思います!
ストリーミングして、サーバーから座標が送られてくるごとに、キャラクターの座標を更新するという感じでやりました!
サーバーの動作確認がしたいだけなので、UIや見た目などは超手抜きですが、ジャンプのアニメーションをつけたり少しゲームっぽくして見ました!
# まとめ
おそらく、本番環境では使い物にはならないかもしれませんが、ローカルの中でもgRPCの双方向ストリーミングが体感できてよかったです〜〜
RustもgRPCも頑張ります〜〜!