[AS3] 45度回転した矩形領域に対するクリック座標の判定 [Edit]

2012年2月28日に催された「ADC MEETUP Round 04 Social Gaming」で、中野亘氏のつくられたパズルゲーム「ワクチンケース」の中でタッチされた座標を、45度傾けた格子で調べられたらというアイデアが出されました(図001)。これをお題として頂戴します。

図001■45度傾けた格子で座標を調べる
kyounoshikaku_01.png

格子が水平と垂直であれば、座標がどの矩形に含まれるかは、xy座標値を調べるだけなので簡単です(図002)。格子を45度傾けると、格子の直線を方程式にしなければならないようにも思えてしまいます。

図002■水平と垂直の格子なら調べるのは簡単[*1]
FF1203031_002.png

けれど、インスタンスは格子が水平と垂直になるようにつくっておき、タイムラインで45度回せば、インスタンスから見た座標でどの矩形に含まれるかがわかります(図003)。

図003■インスタンスは格子が水平と垂直になるようにつくってタイムラインで45度回転する
FF1203031_001.png

ただそれでは、インスタンスに何かの操作を加えるといった、座標を調べる以外の処理が逆にしにくくなります。そこで、インスタンスではなく、座標を計算上45度回して調べることにしましょう。座標はPointオブジェクトでもち、Matrixクラスを用いて回転します[*2]。回転はMatrix.rotate()メソッドで行い、Matrix.transformPoint()メソッドによりPointオブジェクトに適用します。

つぎのスクリプト001は、45度傾けた格子でクリック座標を調べたいMovieClipシンボルのフレームアクションに設定します。すると、クリックした座標を含む矩形領域に、青い外枠が引かれます(図004)。格子の間隔は原点から25ピクセルずつにしました。

スクリプト001■クリックした座標が含まれる矩形領域に外枠を引く
// フレームアクション: クリック座標を調べたいMovieClipシンボル
var rotate45:Number = 45 / 180 * Math.PI;
var gridSize:Number = 25;
var myShape:Shape = new Shape();
var canvas:Graphics = myShape.graphics;
addChild(myShape);
addEventListener(MouseEvent.CLICK, xGetPoint);
function xGetPoint(eventObject:MouseEvent):void {
	var mousePoint:Point = new Point(mouseX, mouseY);
	var myMatrix:Matrix = new Matrix();
	myMatrix.rotate(rotate45);
	var transformedPoint:Point = myMatrix.transformPoint(mousePoint);
	var nX:Number = transformedPoint.x;
	var nY:Number = transformedPoint.y;
	var unitX:int = Math.floor(nX / gridSize);
	var unitY:int = Math.floor(nY / gridSize);
	var left:Number = unitX * gridSize;
	var right:Number = (unitX + 1) * gridSize;
	var top:Number = unitY * gridSize;
	var bottom:Number = (unitY + 1) * gridSize;
	myMatrix.identity();
	myMatrix.rotate(-rotate45);
	var topLeft:Point = myMatrix.transformPoint(new Point(left, top));
	var topRight:Point = myMatrix.transformPoint(new Point(right, top));
	var bottomLeft:Point = myMatrix.transformPoint(new Point(left, bottom));
	var bottomRight:Point = myMatrix.transformPoint(new Point(right, bottom));
	canvas.clear();
	canvas.lineStyle(3, 0x0000FF);
	canvas.moveTo(topLeft.x, topLeft.y);
	canvas.lineTo(topRight.x, topRight.y);
	canvas.lineTo(bottomRight.x, bottomRight.y);
	canvas.lineTo(bottomLeft.x, bottomLeft.y);
	canvas.lineTo(topLeft.x, topLeft.y);
}

図004■クリックした座標を含む矩形領域に青い外枠がつく
FF1203031_003.png

考え方として押さえておくことはふたつです。第1に、クリックした座標を45度傾けた格子にあてはめることです。つぎのステートメントが、クリックした座標を45度回転しています。45度回せば、格子は水平と垂直になりますので、どの矩形領域に含まれるか調べるのはたやすいでしょう。

var mousePoint:Point = new Point(mouseX, mouseY);
var myMatrix:Matrix = new Matrix();
myMatrix.rotate(rotate45);
var transformedPoint:Point = myMatrix.transformPoint(mousePoint);

第2は、調べた矩形領域に対して操作を加えることです。前掲スクリプト001では、外枠を描きました。これは45度回転した(つまり格子が水平と垂直の)状態で矩形座標の4点を決めたうえで、改めてMatrixクラスにより各座標を45度戻しています。なお、Matrix.identity()メソッドは、Matrixオブジェクトを初期化します。

myMatrix.identity();
myMatrix.rotate(-rotate45);
var topLeft:Point = myMatrix.transformPoint(new Point(left, top));
var topRight:Point = myMatrix.transformPoint(new Point(right, top));
var bottomLeft:Point = myMatrix.transformPoint(new Point(left, bottom));
var bottomRight:Point = myMatrix.transformPoint(new Point(right, bottom));

[*1] 中野氏の使われたプレゼンテーション用スライド「ADC MEETUP 04 Flashひとつでスマホアプリ 」p.24。

[*2] Matrixクラスについては、Flashデベロッパーセンター 「Matrixクラス - 変換行列」をお読みください。

コメント

この記事にコメントを書く

記事に対するテクニカルな質問はご遠慮ください(利用規約)。

その他の記事