ゲーム製作でHTML5-Canvasを勉強するぞ!! 第6回

| コメント(0) | トラックバック(0)

6.png みなさん、極座標というのはご存知ですか。
点の位置はx座標とy座標であらわすことが多いと思いますが、これは直交座標です。
これに対し極座標と言うのは原点からの方向(角度)と距離で位置を表します。
ゲームでの使いどころとしては、シューティングゲームの弾の移動増分などですかね。
極座標であれば、移動速度(距離)を一定にしていろいろな方向(角度)に動かすことが簡単になります。

今回はあえて違うことに使います。
Canvasでは画像は直交座標で扱われていますが、これをx座標は角度、y座標は距離という風に置き換えて描画します。
そうすると面白い絵がかけます。
6a.png
なんとなく3Dに見えませんか?
実はこれをやりたいがために、今回のゲームを作り始めました(^^
ただ、このままだと距離の増加が一定なので、より3Dっぽく見せるにちょっと細工する必要があります。

さて、Canvasでどうやって極座標に変換するかですが、簡単にやってくれる関数は残念ながらないようです。
描画する際にいろいろな変換をやってくれる下記の関数もありますが、極座標にはできません。

transform(m11, m12, m21, m22, dx, dy)
指定されたマトリックスを掛け合わせます。要するに回転、移動、反転、その他ができます。

自前でがんばるしかありませんね。
Canvasではピクセルデータを配列として取得することが可能なようです。

getImageData
putImageData
createImageData

これを使いましょう。

極座標と直交座標の関係は一般に以下の式で表されます。

x = r * cos Θ
y = r * sin Θ

今回はこの式に直交座標のx座標をΘ、y座標をrとして計算し、極座標上でのx、y座標を得ます
ただし、実際にやってみるとわかりますが、このままでは歯抜けの画像になってしまいます。
座標系を変換する際によく行われることですが、変換元の座標系から変換先に計算するのではなく、変換先の座標から変換元の色を求めます。
こうすることで歯抜けのないきれいな画像を描画することができます。

ここでもうひとつ工夫。
直交座標上の点は極座標上で必ず同じ点になります。
そこで変換計算を毎回やっていると時間がかかってしまうので、あらかじめ計算して変換元と先のテーブルを作っておきましょう。

var hw = WIDTH / 2;
var hh = HEIGHT / 2;
var r = Math.sqrt(hw * hw + hh * hh);
var lut = [];
var pos = 0;
for (var y = 0; y < HEIGHT; y++)
{
	for (var x = 0; x < WIDTH; x++)
	{
		var sx = Math.atan2(y - hh, x - hw) * hw / Math.PI + hw;
		var sy = Math.sqrt((x - hw) * (x - hw) + (y - hh) * (y - hh));
		sy = (r - sy) / r;
		sy = HEIGHT - sy * sy * HEIGHT - 1;
		
		if (sx < 0) sx = 0;
		if (WIDTH - 1 < sx) sx = WIDTH - 1;
		if (sy < 0) sy = 0;
		if (HEIGHT - 1 < sy) sy = HEIGHT - 1;
		
		sx = Math.round(sx);
		sy = Math.round(sy);
		
		lut[pos++] = (sy * WIDTH + sx) * 4 + 0;
		lut[pos++] = (sy * WIDTH + sx) * 4 + 1;
		lut[pos++] = (sy * WIDTH + sx) * 4 + 2;
		lut[pos++] = (sy * WIDTH + sx) * 4 + 3;
	}
}

あとは通常通り直交座標にすべて描画した後、このテーブルに沿って変換すれば完成です。

setInterval(function ()
	{
		hitTest();

		if (!parseInt(Math.random() * 20)) enemies.push(new Enemy());
	
		move();
		draw(ctx);

		var imageData = ctx.getImageData(0, 0, WIDTH, HEIGHT);
		var src = imageData.data;
		var dst = output.data;
		for (var n = 0; n < HEIGHT * WIDTH * 4; n++)
		{
			dst[n] = src[lut[n]];
		}
		ctx2.putImageData(output, 0, 0);
		
	}, 1000 / 30);
}

Play

トラックバック(0)

トラックバックURL: http://murakya.net/mt/mt-tb.cgi/14

コメントする

オリジナルゲーム

オンラインツール