C++でも使ってみようと思ったのにPhotonの情報を調べるとほぼUnityの情報しか出てこなくて辛かったので、とりあえず動かせるようになるまでの記録。
※当記事は筆者がググっても全然情報が出なかった、あるいは理解に時間がかかったところを重点的に書いてるので、ところどころ端折ってます。また、記事内においてPhotonについての詳細は省いていますので、Photonについての概要に関する情報をお求めの方は別の記事を検索してみてください。
本記事の想定環境は「OS X」「C++」「v4.1.15.2」です。Windows等でも大きな差はないはずですが、適宜読み替えてください。
#SDKをダウンロードする
https://www.photonengine.com/ja/sdks
ここから目的のプラットフォームのSDKを落とします。
ちゃんと動くDEMOがzipの中に付いているので頼りになります。しかし複雑で読んでても全然分からん状態になるので、ほどほどに読む程度にしておくことをおすすめします。動作確認はできますね。
ここから具体的にどうやってパスを通すかなどはdocにドキュメントが入ってるので、それを読んだりして気合いでどうにかします。というか気合いで解決したので何をどうやったのか詳しく覚えてないです…
https://doc-api.photonengine.com/en/cpp/current/a05867.html
#AppIDを取得する
Photonの公式サイトでIDを作っておきます。あとで入力します。20人接続までなら無料です。
https://www.photonengine.com/
#公式ドキュメントの紹介
APIリファレンス
https://doc-api.photonengine.com/en/cpp/current/index.html
docフォルダの中身と同じです。ところで、当記事執筆時点ではLoadBalancing-cppの中身が何も書かれていません。未完成では…?下のAPIの方はありますが…
これを見つつ手探りで進めてたらわけわからなくなったので最初に見るのはおすすめできません。理解してきたら使うとよいでしょう。
Realtimeイントロ
https://doc.photonengine.com/ja-jp/realtime/current/getting-started/realtime-intro
一見C#のサンプルに見えますが、クリックするとC++のコードが見れます。
これがプルダウンメニューになってます
段階を追って組み上がっていくので理解しやすいです。最もおすすめ。(他の選択肢がほとんどないんですけどね…)
#仕様についてのメモ
だいたい上の「Realtimeイントロ」に書いてあることのまとめです。v4.1.15.2時点。
多くの動作をコールバックで記述することになるので、特に現在の状態の把握などには工夫がいります。(状態の扱いについては、DEMOが参考になったのでおすすめです。)
###とりあえず動かすまで
ExitGames::LoadBalancing::Listener を継承したクラスを実装する
このクラスがPhotonのコールバックを受け取ります。これを継承したクラスは、以降記事内でListenerクラスと呼ぶことにします。 純粋仮想関数がたくさんあるので、IDEの機能でオーバーライド関数を一括作成すると楽ですね。Realtimeイントロでは継承クラスは実装されていないのでコピペしただけだとエラーが出ます。要注意です。
コールバックの中で、最初に使うのはconnectReturn()になると思います。
実装例
void connectReturn(int errorCode,
const ExitGames::Common::JString& errorString,
const ExitGames::Common::JString& region,
const ExitGames::Common::JString& cluster)
{
//エラーを弾くならこう
if(errorCode){ std::cout << "connect error\n"; return; }
std::cout << "connected\n";
}
errorCodeが0以外ならエラーがある、ということのようです。(DEMOの実装より)
このif文を超えられれば接続はできているはずなので、ひとまずここに到達できるよう頑張りましょう
ExitGames::LoadBalancing::Clientを用意する
「用意する」と書きましたがインスタンスのことです。
connect()で接続したりします。具体的な通信開始はこのクラスが行います。コンストラクタに、上で作ったListenerクラスやAppIDなどを渡せば生成できます。
DEMOでは、Listenerクラスの中にClientクラスのインスタンスを作り、Clientにthisを渡す設計をしています。これだと確かにクラスがひとつにまとまり、その後の実装もスムーズに進むんですが、クラスが肥大化していて非常に分かりづらかったです。
Realtimeイントロのコードでは、継承済みクラスが実装されてない罠があるものの、別々のクラスになっています。分離されていて役割分担が見えやすいのでまずはこの実装方法の方がよいでしょう。
(ExitGames::Common::Loggerを用意する)
必須ではありません。ログがここに流れてくるようです。最初は無視でいいでしょう
毎フレーム Client.service()を呼ぶ
通信は非同期処理で行われるので、内容がPhoton側でキューに蓄積されます。
ExitGames::LoadBalancing::Client.service()を呼ぶことでそれが消化され、Litenerクラスのコールバックが発火します。この関数を定期的に呼ぶようゲームループに仕込んでおきましょう。これを呼び忘れると、接続成功しても、どんなに待ってもうんともすんとも通知が来ないので注意です。
ここまで準備して、ExitGames::LoadBalancing::Client.connect();を呼ぶとたぶん接続できると思います。私は出来ました。勉強しつつ大急ぎで執筆しましたので、記事中に大きな間違い、勘違いがあればご教示のほどお願いします。
そしてこれを読んだみなさんもPhoton C++をガンガン使いこなして日本語の記事を充実させていってください。私はやりました。