はじめに
この記事はSiv3D Advent Calendar 2021の10日目の記事です1。
OpenSiv3Dは、v0.6.0から基本的な3D描画に対応しています。そこで、その3D関連の機能を利用してマインスイーパーの3Dバージョンを作ることにしました。(現時点では完成していません……)
この記事を書いている時点での画面は下のような感じです。WASDキーで立方体の集合を回転させることができるようになっています。また、各立方体をクリックして、爆弾があればPrint
でGame Overと表示し、そうでなければ周囲の爆弾の数を表示するようになっています。
実装
コードは長く、ここに載せると見栄えが悪いのでGitHubのリポジトリへのリンクを代わりに貼ります。コードの全体像を確認したい方はご覧ください。
苦労した点
実装する上で苦労した点をいくつか書きます。
3D空間内で物体を回転させる
イメージとしては下の図のような回転を三次元空間で行う感じです。
この処理は回転付きのBoxであるOrientedBoxとQuaternion を使うと簡単に書けました。具体的には、回転の中心から見たときのOrientedBoxの座標をVec3{x, y, z}、三次元空間の原点から見た回転の中心の座標をVec3{a, b, c}として、
OrientedBox{ Vec3{x, y, z} * quaternion + Vec3{a, b, c}, 1, 1, 1,
quaternion }.draw();
のような形で書くことで実装できました。本来なら複雑な処理を書かないといけないクォータニオンの掛け算2を*で、Vec3同士の足し算を+だけで書けるのはとても便利ですね。
三次元配列を用意する
OpenSiv3DにはGridという二次元配列を扱うクラスが存在します。しかし、Siv3D作者のRyo Suzukiさんに相談したところ、Gridの三次元バージョンは現時点(v0.6.3)では存在しないとのことでした。そこで、Array3Dクラスを書いてそれを使うことにしました3。
今回Array3Dに実装した主な機能は、
- 座標またはインデックスによる要素の読み出し(get)
- 座標またはインデックスによる要素の書き込み(set)
- 幅、高さ、奥行きの取得
です。余裕があればoperator[]やVec3で要素にアクセスするようにもしたかったのですが、時間が足りないので後回しにしました。書いたコードはこちらから確認できます。
Array3Dについてはあまりきれいなコードでない上に、今のところ最低限の機能しか実装できていないので、今後OpenSiv3D本体にいい感じの三次元配列が実装されることに期待したいです。
今後の予定
ゲームとして遊べる程度に仕上げる予定です。クリックしたマスに周囲の爆弾の数が表示される機能があるのですが、執筆時点ではまだバグがあるのでそれを修正する必要があります。また、ゲームオーバー時やクリアした時の表示もいい感じに仕上げたいです。4
最後まで読んでいただき、ありがとうございました。
-
遅刻し過ぎでは? ↩
-
クォータニオンの計算方法について、詳しくはdrkenさんの記事をご覧ください。 ↩
-
書いたとは言ってもRyoさんが書いた大元の部分に自分が少し書き加えた程度です。 ↩
-
欲を言えば、3DゲームのサンプルプログラムとしてSiv3Dリファレンス等で紹介されたいという思いがあります。 ↩