プログラミング

Node.jsからGo-langへ移行

投稿日:2022年7月13日 更新日:

ストレスなく思いっきり遊べるゲームを実現したくなりました。現行のNode.jsでは処理性能が限界。PaaSが対応しているものの中で高速化が望めるものがGo言語しかない。全くもって無知だがやるしかない。プログラム自体は大したことをやっていないので必要な要素のみを学べば行けるはず。行ってみましょう。

分からない事は全てWeb検索で調べようと思います。本は読みません。

※途中で断念するかもしれませんがご了承ください。

1日目

良質な例題を見つける事が移行の運命を左右します。ひたすらサンプル探し。Go-langでリアルタイム通信ゲームを探す。
良さそうなものをいくつか見つけたが、通信のデータ方式がProgbufという未知のものを使用しているのが多い。無難なJson方式を見つけたい。
フレームワークにあまり依存したくないので、「フレームワークなし」で検索するがほとんど見つからない。
これを改造すればフォートナイトになるという良い例題を発見。

https://qiita.com/tashxii/items/75b99c32b024a1c06eb7

「Gin」、「Melody」と2つもフレームワーク的なものが入ってしまっているが良しとした。

Go-langをインストール。Versionは1.18。
「Gin」、「Melody」 のインポートで躓く。
go mod initを実行してディレクトリにgo.modファイルを作成しておかないといけないらしい。
go get が実行可能になり、go.modに自動でrequireに追加される。
go run main.goでlocal:5000を開いてゲームを起動、プレイする事ができた。

websocketの仕組みに少し触れる事ができた。socket.ioの部分をwebsocket方式に全て書き換えれば通信部分の移行は完了か。結構な作業量になりそう。

2日目

ゲームのフレームごとの処理をsetinterval内で行っていたので、go言語で該当する関数を探す。time.NewTickerがそれらしいが思っていたのと違う。5msでぶん回そうとしたら上手く動作しない。しかも何でforループを描く必要があるのだろう。 面倒になって断念。時間をとってきて前回より5ms経過していたら関数実行、という方法でとりあえず行く。

3日目

websocketの理解がまだ浅い。socket.ioと同じ感覚でやりたい放題できるようになるまで少々お勉強が必要。色々試して、できる事を増やしていく。
websocket、かなり手がかかる。というよりsocket.ioが便利すぎたのかもしれない。Node.js、Javascriptの組み合わせも最高に効率が良かった。サーバー側とクライアント側が同じ言語だと、通信時のデータの型にほとんど気を遣わずに済んでいた。Go言語はJavascriptのように型など何でもOKというわけには行かず、文字と数値の変換が絶えず必要という印象。サンプルプログラムでも通信の型変換は丁寧に行われていた。
作業量が予想より増えそうだが、地道にやっていきたい。

wキーの入力だけ実装できた。wキーを押すとブラウザ側でキャラが前進するのを確認できた。

wキー入力、
クライアントからサーバーへws.sent(“movement”…)、
サーバー、HandlerMessageで”movement”受け取り、
サーバー、UpdateGameにて ”movement” から前進orそのままを位置情報に反映、
サーバーからクライアントへプレイヤーの位置情報をBroadCast、
クライアント、位置情報受け取り、
クライアント、描画

1つのキー入力の実装だけどかなり大変だった。
これを全てのキー入力(いくつあるんだろう。。。)マウス入力について実装できれば終わり。
かなり時間かかりそう。

4日目

予想通り、型変換のエラーが多い。Javascriptのどんぶり勘定に慣れすぎてしまった。Go言語は一切融通が利かないので通信から数値を取り出すときは文字、float64の変換を必ず入れるよう気を付ける。

とりあえずウォークスルー的なものはできた。
接触判定回数がゼロなので当たり前だが、安定した200FPS動作。気持ちいい。

Go言語に少し慣れてきた?
簡易物理表現とグラウンドコンタクトを実装。
しゃがみ、ジャンプ、ジャンパーの実装。

次はいよいよ接触判定。
一番単純な「木」から行きますか。

5日目

Websocketでサーバー(Go言語)からクライアント(Javascript)に配列データを送ろうとして大苦戦。やはりNode.jsのように融通が利かない。型の定義を丁寧に行ってなんとか成功。一日かかってしまった。。。

6日目

「木」を追加したら200FPSが出なくなってしまった。描画側(Three.js)にて処理の遅い個所が発覚。200FPSキープはマストなので仕方なく対処。ここでもはまる。
描画自体の時間は問題ない短さだが、Geometry作成に予想以上の時間がかかっていた。破壊できるオブジェクトにしたいため、初期で作ってそのままというわけにはいかない。今まではほぼ時間がかからない(<1[ms])と思っていたので毎フレーム作成しなおしていた。これはやめないといけない。描画速度を上げるためにMergeしているので厄介だ。。。
とりあえず接触判定を先に実装しよう。そして射撃(Ray判定)を実装する時にGeometryの再作成部分も同時にやろう。

「木」との接触が入った。なかなかしんどかった。相変わらず型の部分で苦労している。数学的な計算箇所はあっという間に実装できている。
やっとスクリーンショットをとるに値する成果。

ゲームフィールドに木は26本。Node.js版と同じ数。近傍探索などはせずに全ての木との接触を判定している。200FPSをキープ。このためにGo言語に移行したのだ。毎フレームの計算時間は余裕で1[ms]以下で回せると考えています。これに校舎、山ほどの建築を行っても200FPSを割らないことを願う。。。

7日目

今日も型で苦労した。新しい変数定義の仕方をするたびにはまっている。しかし、そろそろ新たなパターンもなくなってくる。作業スピードの加速を願う。
校舎が追加された。接触もしっかりと入っている。
200FPSキープ。まだ射撃、建築、編集を未実装だから当然か。

今日のスクショは校舎内でジャンプしているところ。天井と頭の接触を確認。

8日目

プレイヤー建築以外の構造物である「木」「校舎」に対する射撃当たり判定と破壊(構造物の削除)を実装。
一日でやれたので良かった。

射撃の連射時には200FPS。構造物に当たると180FPSに落ちてしまう。恐らく音の負荷だと思われる。
複数の音(射撃音と構造物に当たった音)を再生すると処理が重くなるのか?
とりあえずサーバー側の処理は200FPSをキープしている。

9日目

プレイヤーにダメージが入るようになった。ゼロビルドならこれでひとまず終了。


勢い付いてきたところで建築にとりかかろう。
壁を数枚建てたところでFPS激落ちで2ケタに。描画コードにやはり問題あり。小規模のバトルなら描画部分の改善のみで十分に遊べるゲームなったのではと思い始めた。しかし、サーバ側をGo言語にすればかなり無茶な事(大人数プレイ、大量建築など)ができるはずである、と思う事にしよう。

10日目

連日の作業で目が疲れてきた。何とか勢いで乗り切りたい。

建築のうち、壁、床、階段を実装した。時間切れで屋根を残してしまった。

建築を100枚ほど建てるとFPSが180台になってしまう。これは完全に描画の問題。描画コードの改善はまた後でゆっくりとやろう。とりあえずサーバー側のGo言語移行に集中。

地獄の編集機能の実装が見えてきた。苦労するだろうな。最低でも3日はかかると思っておいた方が良い。

11日目

屋根建築を実装。建築が終了した。描画方法も少し改良した。あとは描画コールを減らす作業をすれば200FPSをキープできるかもしれない。

すぐにでも編集機能実装にとりかかるべきだが動画を撮ってしまった。
以前とは段違いのスピードで縦積みができるようになった。

明日からは腹をくくって編集をやろう。

12日目

地獄の編集一日目。
予想通り苦戦。Javascriptに助けられていたと実感。
とにかく型の宣言で時間を取られる。何とか床の編集パターンだけ実装できた。

しかし、バグ地獄。高速で編集リセットなどをかけるとプログラムが落ちる。配列の削除のタイミングなどに問題があるようだ。はまりそう。。。

13日目

朝からGo言語について学んだ。
落ちた時のエラーメッセージ

「fatal error: concurrent map read and map write」

で検索して対処法を探した。
sync.RWMutexでロックすればよいらしい。配列の書き込みを行っている箇所にLock、呼出しをしている箇所にRLockをかけた。落ちずに動作するようになった。

また動画を撮ってしまった。編集の腕は別として、かなり速い床の連続編集ができた。

共通部分の多い「床」編集の実装も完了した。しかし作業がかなりヘビィだ。編集操作だけでなく描画のコーディングも結構必要なので時間がかかる。。。
残すは壁と階段。あと2日は必要か。

14日目

疲労困憊。何とか「壁」の実装が完了。やろうと思えばトリプルエディットも可能。しかし本家フォートナイトをしばらくやっていないのでプレイ技術的にできなかった。。。

15日目

「階段」編集の実装が完了。これでNode.jsからGo言語への移行はほぼ完了した。

動作確認のために少しフリービルドをやってみた。つまづくところが本家と同じだった。。。

結構、きれいにトリプルエディットが決まって少し感動した。


2週間以上かかってしまった。なかなかハードだった。作業を通じてGo言語の基本的な部分については理解する事ができた。
バグが無数にあると思われるが、とりあえずアルファ版として公開して完成度を上げていこうと思う。

明日はGo言語Webアプリの公開という試練。まずはrender.comでやってみますか。

16日目

編集操作のバグ修正。予想はしていたがバグだらけ。とにかく色々な操作をしてバグを洗い出し、1つ1つ修正していこう。

render.comで無事にデプロイできた。Websocketでws通信がだめというエラーを食らったが、強引にwssと書き換えて乗り切った。機密情報をやり取りする予定はないので動けばいい。

少し作業のペースを落としつつ、改善を続けようと思う。

クラッシュして落ちている事が多いと思われますが、興味があればこちらからプレイしてみてください。

https://g-llc.co.jp/cutefightSA



-プログラミング

執筆者:

関連記事

Android App: How to share video in external storage to MediaStore?

Code Android Studio Electric Eel | 2022.1.1 Patch 2[Java]String path = xxx; //path of the video in t …

FFmpeg.wasmの使い方:ブラウザでアップロードした動画をグレー動画に加工

FFmpeg.wasmの使い方の一例として、・ブラウザで動画をアップロード・動画から音声を抽出・動画からすべてのフレーム画像を取得・すべてのフレームをグレースケールに加工・グレースケール動画を作成・グ …

Cycle inside OOO; building could produce unreliable results. Xcodeで史上最高に難解なエラーでハマった話

あるiPhoneアプリを約2年ぶりにアップデートしようと思い、XcodeでArchiveを実行したら見たことのないエラーが出ました。 Cycle inside OOO; building could …

Mac miniに移行して世界が変わった。MacBook Proは2度と買わない

MacBook Pro(2016)からMac miniに移行して半年くらいが経ちました。何の問題もなく快適に使用できています。移行の経緯とMac Mini使用の感想などについて述べたいと思います。 目 …

How to use FFmpeg.wasm. What’s the Cross Origin Isoration?

Nowadays, I got the information that FFmpeg can be used with Javascript and I tried it immediately. …

スポンサーリンク