座標法


Description

Canvas内をクリックするとボールがクリックした座標に向かって動き出します。ボールの軌跡から作られる多角形の面積を座標法を使って計算します。

code

<canvas id="game" width="270" height="400"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");

var p;
var c_w = canvas.width;
var c_h = canvas.height;

function init(){
	p = new Player();
}

init();

var tm;
tm = setInterval(main,10);

function main(){
	//画面のクリア
	ctx.clearRect(0,0,c_w,c_h);
	p.main();
}

function Player(){
	var obj = this;
	obj.size = 10;
	obj.x = obj.size/2; //円中心のx座標
	obj.y = c_h-obj.size/2; //円中心のy座標
	obj.mouseX = false;
	obj.mouseY = false;
	obj.action_mode = false; //action modeかどうかのフラグ
	obj.path = new Path(); //pathクラス格納

	//main(最初に起動するメソッド)
	obj.main = function(){
		//ボールを現在のx,y座標に従って表示する
		ctx.beginPath()
		ctx.fillStyle = 'white';
		ctx.arc(obj.x, obj.y, obj.size/2, 0, 360,false);
		ctx.fill();

		//action_modeがtrueだったら、action_main()が実行される
		if(obj.action_mode){
			obj.action_main();
			return;
		}

		/*
		 * クリックされたx座標と現在x座標が合致するか確認
		 * 合致したらpathに、スタート座標の記録
		 * pathに向きの記録
		 * 向きに1進める
		 * アクションモードON
		 * obj.mouseX,obj.mouseYのfalse化
		 */
		if(obj.x == obj.mouseX){
			obj.path_init('x');
			return;
		}
		if(obj.y == obj.mouseY){
			obj.path_init('y');
			return;
		}

		//ノーマルアクションを実行
		obj.normal_action();
	}


	/*
	 * パス初期化関数(マウスでクリックした座標と現在の座標が合致した際に起動)
	 */
	obj.path_init = function(xy){
		//action modeをONにする
		obj.action_mode = true;
		//pathにスタート座標の記録
		obj.path.path.push(new Array(obj.x,obj.y));
		//pathに向きの記録
		if(xy == 'x'){
			//yの向きを調べる
			if(obj.mouseY - obj.y < 0) obj.path.bec = new Array(0,-1);
			if(obj.mouseY - obj.y > 0) obj.path.bec = new Array(0,1);
		}else if(xy == 'y'){
			//xの向きを調べる
			if(obj.mouseX - obj.x < 0) obj.path.bec = new Array(-1,0);
			if(obj.mouseX - obj.x > 0) obj.path.bec = new Array(1,0);
		}
		//向きに1進める
		obj.x = obj.x + obj.path.bec[0];
		obj.y = obj.y + obj.path.bec[1];
		//mouseXとmouseYの消去
		obj.mouseX = false;
		obj.mouseY = false;
	}

	/*
	 * action main メソッド
	 * action mode時に最初に実行されるメソッド
	 */
	obj.action_main = function(){
		//上下左右の壁面に到着していないか確認
		if(obj.x == obj.size/2 || obj.x == c_w - obj.size/2 ||
		  obj.y == obj.size/2 || obj.y == c_h - obj.size/2){
		  	//ノーマルモードに移行
			obj.normal_action();
			obj.action_mode = false;
			//mouseXとmouseYの消去
			obj.mouseX = false;
			obj.mouseY = false;
			//ゴールのパスの登録
			obj.path.path.push(new Array(obj.x,obj.y));
			//スタート座標とゴール座標の数値調整
			obj.path.adjust_coordinate(obj);
			//パス図形のタイプ判別(頂点座標の追加処理)
			obj.path.add_coordinate();
			//パスの描画
			ctx.beginPath();
			ctx.moveTo(obj.path.path[0][0],obj.path.path[0][1]);
			for(var i=0; i < obj.path.path.length; i++){
				ctx.lineTo(obj.path.path[i][0],obj.path.path[i][1]);
			}
			ctx.fill();
			//面積の計算
			alert('面積は ' + obj.path.area());
			//パスのクリア
			obj.path.path = new Array();
			return;
		}

		//クリックした座標にプレイヤーが合致していないか確認
		if(obj.x == obj.mouseX){
			//yの向きを調べる
			if(obj.mouseY - obj.y < 0) obj.path.bec = new Array(0,-1);
			if(obj.mouseY - obj.y > 0) obj.path.bec = new Array(0,1);
			//mouseXとmouseYの消去
			obj.mouseX = false;
			obj.mouseY = false;
			//パスの登録
			obj.path.path.push(new Array(obj.x,obj.y));
		}
		if(obj.y == obj.mouseY){
			//xの向きを調べる
			if(obj.mouseX - obj.x < 0) obj.path.bec = new Array(-1,0);
			if(obj.mouseX - obj.x > 0) obj.path.bec = new Array(1,0);
			//mouseXとmouseYの消去
			obj.mouseX = false;
			obj.mouseY = false;
			//パスの登録
			obj.path.path.push(new Array(obj.x,obj.y));
		}

		//向きに1進める
		obj.x = obj.x + obj.path.bec[0];
		obj.y = obj.y + obj.path.bec[1];
	}


	//normal action
	obj.normal_action = function(){
		if(obj.x == 0+obj.size/2){
			obj.y = obj.y - 1;
			if(obj.y<=0+obj.size/2){
				obj.y=0+obj.size/2;
				obj.x = obj.x + 1;
			}
		}else if(obj.y == 0+obj.size/2){
			obj.x = obj.x + 1;
			if(obj.x >= c_w - obj.size/2){
				obj.x = c_w - obj.size/2;
				obj.y = obj.y + 1;
			}
		}else if(obj.x == c_w - obj.size/2){
			obj.y = obj.y +1;
			if(obj.y >= c_h - obj.size/2){
				obj.y = c_h - obj.size/2;
				obj.x = obj.x -1;
			}
		}else if(obj.y == c_h - obj.size/2){
			obj.x = obj.x - 1;
			if(obj.x <= 0 + obj.size/2){
				obj.x = 0 + obj.size/2;
				obj.y = obj.y - 1;
			}
		}
	}
}

/*
アクション中に曲がった点の集まり
1アクションが終了したら完成させる
*/
function Path(){
	var obj = this;
	obj.bec; //アクションの向き用
	obj.path = new Array();
	obj.sum; //パスが作成する図形の面積

	//面積を求めるメソッド
	obj.area = function(){
		var num = 0;
		//座標法で求める
		for(var i=0; i < obj.path.length; i++){
			if(i+1 == obj.path.length){
				num = num + obj.path[i][0]*obj.path[0][1]-obj.path[0][0]*obj.path[i][1];
			}else{
				num = num + obj.path[i][0]*obj.path[i+1][1]-obj.path[i+1][0]*obj.path[i][1];
			}
		}
		return 0.5*Math.abs(num);
	}

	//スタート座標とゴール座標の数値調整(円中心座標からx0,y0にあわせる)メソッド
	obj.adjust_coordinate = function(player_obj){
		//スタート座標の確認と調整
		if(obj.path[0][0] == 0+player_obj.size/2) obj.path[0][0] = 0;
		if(obj.path[0][0] == c_w-player_obj.size/2) obj.path[0][0] =c_w;
		if(obj.path[0][1] == 0+player_obj.size/2) obj.path[0][1] = 0;
		if(obj.path[0][1] == c_h-player_obj.size/2) obj.path[0][1] = c_h;
		//ゴール座標の確認と調整
		if(obj.path[obj.path.length-1][0] == 0+player_obj.size/2) obj.path[obj.path.length-1][0] = 0;
		if(obj.path[obj.path.length-1][0] == c_w-player_obj.size/2) obj.path[obj.path.length-1][0] =c_w;
		if(obj.path[obj.path.length-1][1] == 0+player_obj.size/2) obj.path[obj.path.length-1][1] = 0;
		if(obj.path[obj.path.length-1][1] == c_h-player_obj.size/2) obj.path[obj.path.length-1][1] = c_h;
	}

	//パスが描いた図形のタイプ判別→頂点座標の追加処理メソッド
	obj.add_coordinate = function(){
		//start位置がy軸かx軸か確認
		//startがy軸なら・・・
		if(obj.path[0][0] == 0 || obj.path[0][0] == c_w){
			//スタートのxとゴールのxが同じ値のケース
			if(obj.path[0][0] == obj.path[obj.path.length-1][0]){

			//スタートのxとゴールのxの差の絶対値がc_wのケース
			}else if(Math.abs(obj.path[0][0] - obj.path[obj.path.length-1][0]) == c_w){
				obj.path.push(new Array(obj.path[obj.path.length-1][0],c_h));
				obj.path.push(new Array(obj.path[0][0],c_h));
			}
			//ゴールのyが0かc_hのケース
			else if(obj.path[obj.path.length-1][1] == 0 || obj.path[obj.path.length-1][1] == c_h){
				obj.path.push(new Array(obj.path[0][0],obj.path[obj.path.length-1][1]));
			}
		//startがx軸なら・・・
		}else{
			//スタートのyとゴールのyが同じ値のケース
			if(obj.path[0][1] == obj.path[obj.path.length-1][1]){

			//スタートのyとゴールのyの差の絶対値がc_hのケース
			}else if(Math.abs(obj.path[0][1] - obj.path[obj.path.length-1][1]) == c_h){
				obj.path.push(new Array(0,obj.path[obj.path.length-1][1]));
				obj.path.push(new Array(0,obj.path[0][1]));
			}
			//ゴールのxが0かc_wのケース
			else if(obj.path[obj.path.length-1][0] == 0 || obj.path[obj.path.length-1][0] == c_w){
				obj.path.push(new Array(obj.path[obj.path.length-1][0],obj.path[0][1]));
			}
		}
	}
}

//マウスイベント感知関連
var mouseX;
var mouseY;

//イベントリスナーの登録
canvas.addEventListener("mousedown", mouseDownHandler, false);

function mouseDownHandler(e) {
	var rect = e.target.getBoundingClientRect();
	p.mouseX =  Math.floor(e.clientX - rect.left);
	p.mouseY =  Math.floor(e.clientY - rect.top);
}
</script>