5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

JavaとgRPCで2Dバーチャルオフィスっぽい何かを作る ②gRPC bidirectional streaming

Last updated at Posted at 2022-12-09

この記事は TLB Enjoy Developers Advent Calendar 2022 9日目の記事です。

概要

前回に引き続き、2Dバーチャルオフィスっぽいツールを作っていきます。
JavaとgRPCで2Dバーチャルオフィスっぽい何かを作る ①概要編

今回の目的

今回はgRPCの双方向通信を用いてプレイヤー同士が位置を共有する方法について書きます。
調べたところ同期方式にもいくつかの選択肢があるようですが、今回は非同期でクライアントからサーバーに位置を送信するような方式を選択しました。多人数が接続する上に対戦する訳ではないので、厳密な同期は不要と判断したからです。

また同期間隔について、多人数参加型のオンラインゲームなどでは1フレーム事に同期を取っているわけではなく、数フレームごとに同期を取ることでわずかなラグを許容しているようです。したがって今回は60FPSで10フレームごとにクライアントからサーバーに同期するような実装を目指します。

以下のサイトが参考になりました。

試しに作ったもの

qiita1.gif

未完成ですが、ソースコードは以下になります。
https://github.com/kdr250/grpc-2d-sample

gRPC Spring Boot Starter

gRPC Spring Boot Starterを使用しました。
チュートリアルに従って、インターフェース定義用のプロジェクト、サーバープロジェクト、クライアントプロジェクトのようにマルチプロジェクト化しています。

protobufによるインターフェースの定義

gRPCのインターフェース定義はprotobufで行います。
generateProtoタスクを実行することでjavaファイルが自動生成されます。

Player.proto
syntax = "proto3";

option java_multiple_files = true;

option java_package = "com.example.shared";

option java_outer_classname = "PlayerProto";

service Player {
    rpc Initialize (GrpcPlayer) returns (AddEvent);
    rpc Sync (stream PlayerSyncRequest) returns (stream PlayerSyncResponse);
}

message PlayerSyncRequest {
    GrpcPlayer player = 1;
    repeated string otherPlayerIdList = 2;
}

message PlayerSyncResponse {
    oneof event {
        AddEvent addEvent = 1;
        MoveEvent moveEvent = 2;
    }
}

message AddEvent {
    GrpcPlayer otherPlayer = 1;
    repeated GrpcImageType imageType = 2;
}

message MoveEvent {
    GrpcPlayer otherPlayer = 1;
}

message GrpcPlayer {
    string id = 1;
    string name = 2;
    GrpcLocation location = 3;
}

message GrpcLocation {
    int32 x = 1;
    int32 y = 2;
}

message GrpcImageType {
    string name = 1;
    string base64Image = 2;
}

gRPC bidirectional streamingについて

bidirectional streamingで永続的にstreamを維持する方法がわからず苦戦したのですが、クライアント側で以下の手順を踏む事で解決しました。

  1. 最初にクライアント側のスタブでリクエストする。
  2. スタブの戻り値のStreamObserverを変数化して保持しておく。
  3. 以降、2で保持したStreamObserverを使ってサーバー側に送信する。

以下のサイトが参考になりました。

感想

gRPC難しい...!

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?