はじめに
「スカッシュゲームを作る(1) - S.F. Page」でレトロな2Dゲームを作ろうとしていて、描画をcanvasベースで作ろうか、WebGLベース(three.js)ベースで作ろうかと考えた。今作ろうとしてるゲームは極力凝ったグラフィックを排して、昔の質素なものにしようとしているので、canvasでも十分作れると思うのだが、将来的なことも見越してね。
描画は極力高速化したい。その場合はcanvas
ではなくWebGLを使ったほうがいいような気がする。おそらく今はcanvas
でもアクセラレートされるのかもしれないけども、3D的なエフェクトとか、ブレンド描画の豊富さとかを考えるとWebGL(three.js)ベースで作ろうかなと。
three.jsで2Dゲームを作る時のアイデア
スクリーン座標は仮想的なものする。実画面サイズに座標を合わせるのではなくて、幅および高さは固定サイズとして、それを実画面に拡大縮小して投影するのである。例えば幅192ピクセル・高さ256ピクセルのゲーム画面を設定し、これを実画面サイズに合わせて拡大・縮小し表示するようにする。
座標は以下のように考える。
- X,Y座標は仮想スクリーン座標
- Z座標は拡大縮小や優先順位コントロール
となる。Z座標が0の時、仮想スクリーン座標に一致するように作ると、2D的な考えでゲームを作ることができる。
そうなるようにするためにはカメラのパラメータを以下のようにすればよい。
var WIDTH = 192;
var HEIGHT = 256;
var camera = new THREE.PerspectiveCamera(90 /* 視野角 */, WIDTH / HEIGHT /*アスペクト比*/, 0.1, 1000);
camera.position.z = HEIGHT / 2;
こうすると、z座標が0の時、仮想スクリーン座標に一致するようになる。透視投影になっているので、z座標を変えると拡大・縮小される。あと描画優先順位がコントロールできるようになる。ただz座標をいじると仮想スクリーン座標と一致しなくなるので、それなりの配慮は必要になるけれども。
次に実画面に合わせてこの仮想画面をフィットする方法だが、これは簡単である。アスペクト比を考慮し、実画面サイズにフィットする幅・高さを求め、それをWebGLレンダラのsetSize()
で設定するだけである。
実際の画面サイズがどうであれ、仮想スクリーン座標は維持される。実画面サイズに合わせて拡大縮小描画をしたりとかする必要もない。
const WIDTH = 192;
const HEIGHT = 256;
var screen_width;
var screen_height;
// アスペクト比を考慮し実画面サイズにフィットさせる幅と高さを求める
function calcScreenSize() {
screen_width = window.innerWidth;
screen_height = window.innerHeight;
if (screen_width >= screen_height) {
screen_width = screen_height * WIDTH / HEIGHT;
} else {
screen_height = screen_width * HEIGHT / WIDTH;
}
}
calcScreenSize();
var renderer = new THREE.WebGLRenderer({ antialias: false /*, sortObjects: true */ });
renderer.setSize(screen_width, screen_height);
これを使ったサンプルは以下である。