Web ブラウザを用いてオンラインで対戦できるオセロです。サーバー側はGo言語
、クライアント側はJavascript
を利用しました。これを作った理由は単純で、作れる気がしたからです。アイデアのオリジナル性は低いことは理解しています。ですが「オセロを作ろう」的なチュートリアルを見たことはなく、オセロのコードなどは全て自分で考えました。2Dだとありきたりな気がしたので3Dにしました。制作期間は一か月程ですが、そのほとんどが WebGL との戦いでした。Three.js 使えばもっと早く終わったでしょう。ですが、一から書くことで大まかですがOpenGL
の仕組みや処理の流れが把握できたので勉強としては良かったと思います。
- 機能の要約
- サーバーのビルド
- クライアントのビルド
- サーバーの起動
- プレイ方法
- 詳しいプログラムの流れ
WebSocket
の接続待機- プレイヤー同士を対戦させる
- ゲームの進行
- 進行状態の通信
- github.com/gorilla/websocket
- サーバーと
Websocket
で接続する - サーバーに対戦相手の検索を依頼
- サーバーから受け取ったゲーム情報をクライアントに反映
WebGL
を利用してゲームの状況を画面に描画
- svelte
- gl-matrix
- WebGL: ウェブの 2D および 3D グラフィック
- WebGL の基本
- wgld.org
- API Docs - Svelte
- 実践プログラミング WebGL HTML & JavaScript による 3D グラフィックス開発
- Blender (ボードとオセロの石をモデリングするために利用)
サーバーはGo 言語(v1.16.5)で開発しました。
Go をビルドする際は Go のプロジェクトルート./src/server/
に移動してから行います。
cd ./src/server
go -o gothello build main.go
無事完了するとsrc/server
の中にgothello.exe
が作成されているはずです。
クライアントをビルドするには、yarn
が必要です。(npm
でビルド可能かどうかは未検証)
また、yarn
を利用するうえでNode.jsも必要になります。(開発環境の Node.js は、v12.13.1 です)
初めに、プロジェクトのルートに移動してから以下のコマンドを実行します。
yarnを使う場合
yarn install
yarn build
特にエラーが出なければクライアントのビルドは完了です。
また、クライアントとサーバーをビルドするこれらのタスクをスクリプトにしてあります。
./build.sh
まず、gothello.exe
をpublic
と同じ階層に配置 します。
(build.sh
を利用してビルドした場合は自動で配置されます。)
そして、このバイナリファイルを実行するために以下のコマンドを入力します。
#デフォルトではポート番号80で起動します
./gothello.exe
#また、特定のポート番号を使用したい場合は以下のようにします
./gothello.exe -port=8080
#実行権限がないとき
chmod u+rx gothello.exe
Web ブラウザを起動し、アドレスバーにアドレスを入力します。
#サーバーを起動しているコンピューターでプレイする場合
http://localhost
#ポート番号を指定した場合
http://localhost:8080
#例: ローカルネットワークからプレイ
http://192.168.3.2
- 「Click to find an opponent」をクリックすると対戦相手の検索を開始します
- 対戦相手が見つかるとゲームが開始します。
- 「Your turn」と表示されているときがあなたのターンです。
- ボードをクリックして石を設置できます。
- ルールは一般的なオセロと変わらないので割愛
- 石を設置できなくなるか、対戦相手が切断するとゲームが終了します。
- 結果が表示されます。結果表示をクリックすると初期画面に戻ります。
- 対戦相手の検索を要求されると、キューの最後尾にプレイヤーを追加する
- 次にキューの長さが 2 以上のとき、先頭の 2 プレイヤーで新しいゲームを開始する
Player
の線形リストpush
の操作は、新しい要素を最後尾に連結するのみpop
の操作は、先頭の次の要素を先頭の要素にするのみ
- ゲームを開始すると、初期状態やプレイヤーの情報をクライアントに送る
- 現在ターン中のプレイヤーからクリック位置を受け取る
- 受け取った位置に石を設置した場合、「どの石を裏返せるか?」を調べる
- 一枚も裏返せないなら、そこは設置できないので何もしない
- そうでないなら裏返し、石を設置する。そして、ターンを更新する
- ターンを更新すると、そのターンで設置できる石の枚数を調べる
- 一枚も設置できないなら
pass
を 1 増やし、さらにターンを更新する pass
が 2 を超えたとき、これ以上ゲームを進めることは不可能なので終了する- また、石の設置と同時に
pass
は 0 に戻される
- 一枚も設置できないなら
- そして、ゲームの状態やターンの更新をプレイヤーに送る
- ゲームが終了すると結果情報をプレイヤーに送る
WebGL Context
を取得する。(ブラウザが対応していない場合はエラーを表示)- 3D モデルをロードする。(OBJ ファイルから頂点や法線の情報を取得し GPU にアップロード)
- ロードが終了すると描画ループに入る
- 発生した
DOMイベント
はキューに格納され、描画ループで処理される
Go
とJavascript
の両方で扱うのが簡単なJSON
で通信するように- 不正防止のため、サーバーはターン中のプレイヤーのクリック情報のみを処理する
- ゲームプログラム (
./src/server/game/game.go
) は全て自分で考えた。 - マッチングには FIFO 線形リストを用いた。計算量の削減と、先に待機を始めたプレイヤーからゲームを開始するため。
Disc(disc.go)
はint8
のエイリアスである。-1
を掛けることで裏返しを表現しているManager(manager.go)
ではハッシュテーブルを実装している