HTML5のCanvas上でJavaScriptを使ってテオ・ヤンセンのビーストを3D空間内で動かす

HTML5のCanvas上でJavaScriptを使ってテオ・ヤンセンのビーストを3D空間内で動かす

今回のテオ・ヤンセンのアニマル・ビーストは、以前作ったサンプルに3次元処理を加えたものです。下記のデモページをクリックして、「脚」や「Y」の黒いボタンを左右に動かしてみてください。

HTML5のCanvas上でJavaScriptを使ってテオ・ヤンセンのビーストを3D空間内で動かす : デモ

HTML5のCanvas上でJavaScriptを使ってテオ・ヤンセンのビーストを3D空間内で動かす : ZIPファイル(23kb)

3D回転を実現するためには、下記の座標回転の公式が必要です。

座標回転のY軸の公式

1.HTML

<!doctype html> <!-- 標準モードでWebページをレンダリング -->
<html lang="ja"> <!-- 言語指定付きのhtml要素 -->
	<head> <!-- ヘッダーの指定 HTMLページの生成に必要な情報を記述 -->
		<meta charset="UTF-8"> <!-- Web上の文字エンコーディングの指定 -->
		<title>HTML5のCanvas上でJavaScriptを使ってテオ・ヤンセンのビーストを3D空間内で動かす</title> <!-- ブラウザの上部ウィンドウのバーに表示されるタイトル -->
        <link href="css/base.css" rel="stylesheet" type="text/css"> <!-- cssファイル(デザインの仕様)の読み込み -->
        <script src="js/devicecheck.js"></script>
		<script src="js/base_3d.js"></script> <!-- JavaScriptファイル(制御の仕様)の読み込み -->
	</head>

    <body> <!-- HTMLページのメインコンテンツを示す要素 -->
    	<canvas id = "viewArea2" width = "400" height = "400"></canvas> <!-- 描画領域 -->
        <canvas id = "viewArea" width = "400" height = "300"></canvas> <!-- 描画領域 -->
        <div id="buttonZ" width = "30" height="30"><img src="images/ballz.png" width = "30" height="30"/></div>
        <div id="buttonY" width = "30" height="30"><img src="images/bally.png" width = "30" height="30"/></div>
    </body>
</html>

2.CSS

@charset "UTF-8";

body /* bodyのデザイン */
{
	margin:0; /* borderより外側の余白は0 */
	padding:0; /* borderより内側の余白は0 */
	background-color: #fff; /* 背景色は白 */ 
	-webkit-transform:translateZ(0px); /* GPUの機能を使う */
}

#viewArea, #viewArea2 /* id名「viewArea」が付いたCanvas要素(タグ)のデザイン */
{
	position: absolute; /* 配置方法は絶対値 */
	top: 10px; /* Webのページの上から10ピクセルの位置 */
	left: 10px; /* Webのページの左から10ピクセルの位置 */
	width: 400px; /* 幅は275ピクセル */
	height: 300px; /* 高さは275ピクセル */
	border: 1px solid #000; /* 線は1ピクセルの太さで、実線、色は黒。上下左右に引く */
}

#viewArea2
{
	height: 400px;
	border:none;
}

#buttonZ, #buttonY
{
	position: absolute; /* 配置方法は絶対値 */
	/*background-color: #000000;*/
	top: 330px;
	left: 200px;
	height: 30px;
	width: 30px;
	/*border-radius:15px;
	-moz-border-radius:15px;
	-webkit-border-radius:15px;*/
}

#buttonY
{
	top: 375px;
}

3.JavaScript

devicecheck.js

function Sandbox()
{
}
	
Sandbox.prototype = 
{
	/*name : "My App",
	version : "1.0",
	getName : function()
	{
		return this.name;
	}*/
};

Sandbox.prototype.g_mobiledevice = false;
Sandbox.prototype.g_browsername = "unknown";
Sandbox.prototype.g_browserver = -1;

var g_mobiledevice = false;	//iPhone、iPad、Androidのときtrue
var g_browsername = 'unknown';
var g_browserver = -1;

if(checkUserAgent() == false)
{
	window.alert('このブラウザは対象外です');
}

function checkUserAgent()
{
	var ua = navigator.userAgent;

	//iPhoneか?	
	var mstr = ua.match(/iPhone OS \d+/);
	if(mstr != null){
		var vstr = mstr[0].match(/\d+/);
		if(parseInt(vstr[0]) >= 3) 
		{
			Sandbox.prototype.g_mobiledevice = true;
			Sandbox.prototype.g_browsername = 'iPhone';
			//alert('major-version ' + vstr);
			return true;
		}
	}
	//iPadか?
	if(ua.indexOf('iPad') > -1)
	{
		mstr = ua.match(/CPU OS \d+/);
		if(mstr != null)
		{
			var vstr = mstr[0].match(/\d+/);
			if(parseInt(vstr[0]) >= 3) {
				Sandbox.prototype.g_mobiledevice = true;
				Sandbox.prototype.g_browsername = 'iPad';
				//alert('major-version ' + vstr);
				return true;
			}		
		}		
	}	
	//Androidか?	
	var mstr = ua.match(/Android \d+\.\d+/);
	if(mstr != null)
	{
		Sandbox.prototype.g_browsername = 'Android';
		var vstr = mstr[0].match(/\d+\.\d+/);
		Sandbox.prototype.g_browserver = parseFloat(vstr[0]);
		Sandbox.prototype.g_mobiledevice = true;
		if(Sandbox.prototype.g_browserver > 2.1) 
		{
			//alert('version ' + vstr);
			return true;
		}
	}
	//Chromeか?
	mstr = ua.match(/Chrome\/\d+/);
	if(mstr != null)
	{
		Sandbox.prototype.g_browsername = 'Chrome';
		var vstr = mstr[0].match(/\d+/);
		Sandbox.prototype.g_browserver = parseInt(vstr[0]);
		if(Sandbox.prototype.g_browserver >= 9) 
		{
			//alert('major-version ' + vstr);
			
			return true;
		}		
	}
	//Safariか?
	if(ua.indexOf('Safari') > -1)
	{
		mstr = ua.match(/Version\/\d+/);
		if(mstr != null){
			var vstr = mstr[0].match(/\d+/);
			if(parseInt(vstr[0]) >= 5) 
			{
				Sandbox.prototype.g_browsername = 'Safari';
				//alert('major-version ' + vstr);
				return true;
			}		
		}		
	}
	//Internet Explorerか?
	mstr = ua.match(/MSIE \d+/);
	if(mstr != null)
	{
		var vstr = mstr[0].match(/\d+/);
		if(parseInt(vstr[0]) >= 9) 
		{
			Sandbox.prototype.g_browsername = 'MSIE';
			//alert('major-version ' + vstr);
			return true;
		}		
	}
	//Firefoxか?
	mstr = ua.match(/Firefox\/\d+/);
	if(mstr != null){
		var vstr = mstr[0].match(/\d+/);
		if(parseInt(vstr[0]) >= 4) 
		{
			Sandbox.prototype.g_browsername = 'Firefox';
			//alert('major-version ' + vstr);
			return true;
		}		
	}
	//Operaか?
	if(ua.indexOf('Opera') > -1)
	{
		mstr = ua.match(/Version\/\d+/);
		if(mstr != null){
			var vstr = mstr[0].match(/\d+/);
			if(parseInt(vstr[0]) >= 11) 
			{
				Sandbox.prototype.g_browsername = 'Opera';
				//alert('major-version ' + vstr);
				return true;
			}		
		}		
	}
	
	return false;
}

base_3d.js

window.addEventListener("load", init, false);

function init()
{
	//変数の定義
	var offsetX = 0,
	offsetY = 0,
	centerX = 0,
	centerY = 0,
	ctx = null,
	ctx2 = null,
	angleX = 0 * Math.PI/180,
	angleY = 0 * Math.PI/180,
	angleZ = 0 * Math.PI/180,//回転がスタートする座標値
	radius = 3,
	ratio = 0.4,

	fl = 300,
	vpX = 0,
	vpY = 0,

	y_oa = 67.5 * ratio, //70

	x_a = 0,
	y_a = y_oa

	//left_side  start
	x_b = -162 * ratio, //-162
	y_b = 0 * ratio,
	x_c_init = -93 * ratio,
	y_c_init = -140 * ratio,
	x_e_init = -213 * ratio,
	y_e_init = 149 * ratio,
	
	x_f = 0,
	y_f = 0,
	x_g = 0,
	y_g = 0,
	x_h = 0,
	y_h = 0,

	x_g_init = -360 * ratio,
	y_g_init = 74 * ratio,
	x_f_init = -310 * ratio,
	y_f_init = -75 * ratio,
	x_h_init = -329 * ratio, //-329 -306
	y_h_init = 378 * ratio,  //378   333

	side_a = 0,
	side_b = 0,
	side_c = 0,
	side_c2 = 0,
	side_e = 0,
	side_a2 = 0,
	side_b2 = 0,
	side_b3 = 0,
	side_f = 0,
	side_e2 = 0,
	side_e3 = 0,
	side_g = 0,
	side_g2 = 0,
	side_h = 0,
	//left_side end

	//right_side  start
	_x_c_init = x_c_init,
	_y_c_init = y_c_init,
	_x_e_init = x_e_init,
	_y_e_init = y_e_init,
	_x_g_init = x_g_init,
	_y_g_init = y_g_init,
	_x_f_init = x_f_init,
	_y_f_init = y_f_init,
	_x_h_init = x_h_init,
	_y_h_init = y_h_init,

	_x_b = -x_b,
	_y_b = y_b,
	_x_c = 0,
	_y_c = 0,
	_x_e = 0,
	_y_e = 0,
	_x_f = 0,
	_y_f = 0,
	_x_g = 0,
	_y_g = 0,
	_x_h = 0,
	_y_h = 0,
	//right_side end

	theCanvas = null,
	theCanvas2 = null,
	size = 3,
	buttonStart = null,
    buttonMove = null,
    buttonEnd = null,
    sliderLeft = 0,
    sx = 0,
	mx = 0,
	walkZ = 0,

	sliderLeftY = 0,
    sxY = 0,
	mxY = 0,
	walkY = 0;

	document.getElementById('buttonZ').addEventListener('touchstart', function() 
    {
        event.preventDefault();
    });
    document.getElementById('buttonZ').addEventListener('touchmove', function() 
    {
        event.preventDefault();
    });
    document.getElementById('buttonZ').addEventListener('touchend', function() 
    {
        event.preventDefault();
    });
	
	//視覚の処理を行うオブジェクトのグループ
	View =
	{
		//空のinit関数を作る
		init : function()
		{

		}
	}
	
	//Viewの中の関数(init)にプロトタイプの変数や関数を定義します
	//プロトタイプには、インスタンスで使う共有の関数や変数を設定します
	View.init.prototype.button = function()
	{
		//スライダーボタン Z
        var element = document.getElementById('buttonZ');
        element.addEventListener(buttonStart, model.sliderStartHandler, false);
        //element.addEventListener(buttonMove, model.sliderMoveHandler, false);
        element.addEventListener(buttonEnd, model.sliderEndHandler, false);

        //スライダーボタン Y
        element = document.getElementById('buttonY');
        element.addEventListener(buttonStart, model.sliderStartHandlerY, false);
        //element.addEventListener(buttonMove, model.sliderMoveHandlerY, false);
        element.addEventListener(buttonEnd, model.sliderEndHandlerY, false);
	}

	View.init.prototype.animation = function()
	{
		View.init.prototype.rotateY();
	}

	View.init.prototype.pointInit = function()
	{
		//頂点A ここから		
		Model.rotateZ(ball1, angleZ);

		Model.perspective(ball1);

		
		//頂点A ここまで

		//頂点B ここから
		Model.perspective(ball2);
		//頂点B ここまで
		
		//頂点C ここから
		//辺AC
		var dx = ball1.x - ball2.x;
		var dy = ball1.y - ball2.y;

		//var side_c = Math.sqrt(dx*dx+dy*dy);
		var side_c = Math.min(Math.sqrt(dx*dx+dy*dy), side_a+side_b);

		//console.log(side_c);

		var D = Math.atan2(dy, dx);

		//余弦定理からラジアン角度を算出します。
		var B = Math.acos((side_c * side_c + side_a * side_a - side_b * side_b) / (2 * side_c * side_a));
		
		B -= D;

		ball3.xpos = Math.cos(B) * side_a;
		ball3.ypos = Math.sin(B) * side_a;
		
		Model.perspective(ball3);
		//頂点C ここまで
		
		//頂点E ここから
		//辺AE
		side_e = side_c;
		
		//余弦定理からラジアン角度を算出します。
		B = Math.acos((side_a2 * side_a2 + side_e * side_e - side_b2 * side_b2) / (2 * side_a2 * side_e));
		
		B += D;

		ball4.xpos = Math.cos(B) * side_a2;
		ball4.ypos = Math.sin(B) * side_a2;

		Model.perspective(ball4);
		//頂点E ここまで

		//頂点F ここから
		//辺BF

		//余弦定理からラジアン角度を算出します。
		B = Math.acos((side_a * side_a + side_c2 * side_c2 - side_b3 * side_b3) / (2 * side_a * side_c2));
		
		dx = ball3.x;
		dy = ball3.y;
		D = Math.atan2(dy, dx);
		
		B += D;

		ball5.xpos = Math.cos(B) * side_c2;
		ball5.ypos = Math.sin(B) * side_c2;

		Model.perspective(ball5);
		//頂点F ここまで

		//頂点G ここから
		//辺GE
		dx = ball5.x - ball4.x;
		dy = ball5.y - ball4.y;
		D = Math.atan2(dy, dx);

		var side_g  = Math.sqrt(dx*dx+dy*dy);

		//余弦定理からラジアン角度を導く
		B = Math.acos((side_f * side_f + side_g * side_g - side_e2 * side_e2) / (2 * side_f * side_g));
		
		B -= D;

		ball6.xpos = Math.cos(B) * side_f;
		ball6.ypos = Math.sin(B) * side_f;

		Model.perspective(ball6);
		//頂点G ここまで

		//辺EH
		//余弦定理からラジアン角度を算出します。
		B = Math.acos((side_h * side_h + side_g2 * side_g2 - side_e3 * side_e3) / (2 * side_h * side_g2));
		
		dx = -ball6.x;
		dy = -ball6.y;
		D = Math.atan2(dy, dx);

		B += D;

		ball7.xpos = Math.cos(B) * side_g2;
		ball7.ypos = Math.sin(B) * side_g2;

		Model.perspective(ball7);
		//頂点H ここまで

		//right_side start
		//頂点_B ここから
		Model.perspective(ball8);
		//頂点_B ここまで

		//頂点_C ここから
		//辺AC
		dx = ball1.x - ball8.x;
		dy = ball1.y - ball8.y;
		
		_side_c = Math.sqrt(dx*dx+dy*dy);

		D = Math.atan2(dy, dx);

		//余弦定理からラジアン角度を算出します。
		B = Math.acos((_side_c * _side_c + side_a * side_a - side_b * side_b) / (2 * _side_c * side_a));
		
		B += D;
		
		ball9.xpos = Math.cos(B) * side_a;
		ball9.ypos = Math.sin(B) * side_a;

		Model.perspective(ball9);
		//頂点_C ここまで

		//頂点E ここから
		//辺AE
		_side_e = _side_c;

		dx = ball1.x - ball8.x;
		dy = ball1.y - ball8.y;

		D = Math.atan2(dy, dx);
		
		//余弦定理からラジアン角度を算出します。
		B = Math.acos((side_a2 * side_a2 + _side_e * _side_e - side_b2 * side_b2) / (2 * side_a2 * _side_e));
		
		B -= D;

		ball10.xpos = Math.cos(B) * side_a2;
		ball10.ypos = -Math.sin(B) * side_a2;

		Model.perspective(ball10);
		//頂点E ここまで

		//頂点F ここから
		//辺BF
		dx = ball9.x// - _x_b;
		dy = ball9.y// - _y_b;
		D = Math.atan2(dy, dx);

		//余弦定理からラジアン角度を算出します。
		B = Math.acos((side_a * side_a + side_c2 * side_c2 - side_b3 * side_b3) / (2 * side_a * side_c2));
		
		B += D;

		ball11.xpos = Math.cos(B) * side_c2;
		ball11.ypos = Math.sin(B) * side_c2;

		Model.perspective(ball11);
		//頂点F ここまで

		//頂点G ここから
		//辺GE
		dx = ball11.x - ball10.x;
		dy = ball11.y - ball10.y;
		D = Math.atan2(dy, dx);

		var _side_g  = Math.sqrt(dx*dx+dy*dy);

		//余弦定理からラジアン角度を導く
		B = Math.acos((side_f * side_f + _side_g * _side_g - side_e2 * side_e2) / (2 * side_f * _side_g));
		
		B += D;

		ball12.xpos = Math.cos(B) * side_f;
		ball12.ypos = Math.sin(B) * side_f;

		Model.perspective(ball12);
		//頂点G ここまで

		//頂点H ここから
		dx = -ball12.x;
		dy = -ball12.y;

		D = Math.atan2(dy, dx);

		//余弦定理からラジアン角度を算出します。
		B = Math.acos((side_h * side_h + side_g2 * side_g2 - side_e3 * side_e3) / (2 * side_h * side_g2));
		
		B -= D;

		ball13.xpos = Math.cos(B) * side_g2;
		ball13.ypos = -Math.sin(B) * side_g2;

		Model.perspective(ball13);
		//頂点H ここまで
		//right_side end
	}

	View.init.prototype.rotateY = function()
	{
		ctx.clearRect(0, 0, offsetX, offsetY);
		
		/*

		*/
		Model.rotateY(ball0, angleY);
		Model.perspective(ball0);

		Model.rotateY(ball1, angleY);
		Model.perspective(ball1);

		Model.rotateY(ball2, angleY);
		Model.perspective(ball2);

		Model.rotateY(ball3, angleY);
		Model.perspective(ball3);

		Model.rotateY(ball4, angleY);
		Model.perspective(ball4);

		Model.rotateY(ball5, angleY);
		Model.perspective(ball5);

		Model.rotateY(ball6, angleY);
		Model.perspective(ball6);

		Model.rotateY(ball7, angleY);
		Model.perspective(ball7);
		/*

		*/

		/*

		*/
		Model.rotateY(ball8, angleY);
		Model.perspective(ball8);

		Model.rotateY(ball9, angleY);
		Model.perspective(ball9);

		Model.rotateY(ball10, angleY);
		Model.perspective(ball10);

		Model.rotateY(ball11, angleY);
		Model.perspective(ball11);

		Model.rotateY(ball12, angleY);
		Model.perspective(ball12);

		Model.rotateY(ball13, angleY);
		Model.perspective(ball13);

		/*

		*/
	}

	View.init.prototype.drawButtonLine = function()
	{
		ctx2.strokeStyle = "#000000";
		ctx2.lineWidth = 1;
		ctx2.beginPath();
		ctx2.moveTo(20, 335);
		ctx2.lineTo(380, 335);
		ctx2.moveTo(20, 380);
		ctx2.lineTo(380, 380);
		ctx2.stroke();
	}

	View.init.prototype.draw = function()
	{
		ctx.beginPath();
		ctx.arc(ball0.x+centerX, ball0.y+centerY, ball0.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball1.x+centerX, ball1.y+centerY, ball1.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball2.x+centerX, ball2.y+centerY, ball2.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball3.x + ball2.x+centerX, -ball3.y + ball2.y+centerY, ball3.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball4.x + ball2.x + centerX, ball4.y + ball2.y + centerY, ball4.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball5.x + ball2.x + centerX, -ball5.y + ball2.y + centerY, ball5.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball6.x + ball4.x + ball2.x + centerX, ball6.y + ball4.y + ball2.y + centerY, ball6.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball7.x + ball4.x + ball2.x + centerX, ball7.y + ball4.y + ball2.y + centerY, ball7.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.fillStyle = "#000000";
		ctx.beginPath();
		ctx.arc(ball8.x+centerX, ball8.y+centerY, ball8.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball9.x + ball8.x + centerX, ball9.y + ball8.y + centerY, ball9.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball10.x + ball8.x + centerX, ball10.y + ball8.y + centerY, ball10.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball11.x + ball8.x + centerX, ball11.y + ball8.y + centerY, ball11.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.beginPath();
		ctx.arc(ball12.x + ball10.x + ball8.x + centerX, ball12.y + ball10.y + ball8.y + centerY, ball12.radius, 0, Math.PI*2, false);
		ctx.fill();
		ctx.fillStyle = "#000000";
		ctx.beginPath();
		ctx.arc(ball13.x + ball10.x + ball8.x + centerX, ball13.y + ball10.y + ball8.y + centerY, ball13.radius, 0, Math.PI*2, false);
		ctx.fill();

		//線をつなげる
		ctx.strokeStyle = "#000000";
		ctx.lineWidth = 0;
		ctx.beginPath();
		ctx.moveTo(centerX, centerY);
		ctx.lineTo(ball1.x + centerX, ball1.y + centerY);
		ctx.lineTo(ball3.x + ball2.x + centerX, -ball3.y + ball2.y + centerY);
		ctx.moveTo(ball1.x + centerX, ball1.y + centerY);
		ctx.lineTo(ball4.x + ball2.x + centerX, ball4.y + ball2.y + centerY);
		ctx.moveTo(ball2.x + centerX, ball2.y + centerY);
		ctx.lineTo(ball4.x + ball2.x + centerX, ball4.y + ball2.y + centerY);
		ctx.moveTo(ball2.x + centerX, ball2.y + centerY);
		ctx.lineTo(ball3.x + ball2.x + centerX, -ball3.y + ball2.y + centerY);
		ctx.lineTo(ball5.x + ball2.x + centerX, -ball5.y + ball2.y + centerY);
		ctx.moveTo(ball2.x + centerX, ball2.y + centerY);
		ctx.lineTo(ball5.x + ball2.x + centerX, -ball5.y + ball2.y + centerY);
		ctx.lineTo(ball6.x + ball4.x + ball2.x + centerX, ball6.y + ball4.y + ball2.y + centerY);
		ctx.lineTo(ball4.x + ball2.x + centerX, ball4.y + ball2.y + centerY);
		ctx.lineTo(ball7.x + ball4.x + ball2.x + centerX, ball7.y + ball4.y + ball2.y + centerY);
		ctx.moveTo(ball6.x + ball4.x + ball2.x + centerX, ball6.y + ball4.y + ball2.y + centerY);
		ctx.lineTo(ball6.x + ball4.x + ball2.x + centerX, ball6.y + ball4.y + ball2.y + centerY);
		ctx.lineTo(ball7.x + ball4.x + ball2.x + centerX, ball7.y + ball4.y + ball2.y + centerY);
		ctx.stroke();

		/*
		//歩行の軌跡を描く
		ctx2.lineWidth = 0;
		ctx2.fillStyle = "#cccccc";
		ctx2.beginPath();
		ctx2.arc(ball7.x + ball4.x + ball2.x + centerX, ball7.y + ball4.y + ball2.y + centerY, 0.5, 0, Math.PI*2, false);
		ctx2.fill();
		*/
		
		//left
		ctx.strokeStyle = "#000000";
		ctx.lineWidth = 0;
		ctx.beginPath();
		
		ctx.moveTo(ball1.x+centerX, ball1.y+centerY);
		ctx.lineTo(ball9.x + ball8.x + centerX, ball9.y + ball8.y + centerY);
		ctx.moveTo(ball8.x+centerX, ball8.y+centerY);
		ctx.lineTo(ball9.x + ball8.x + centerX, ball9.y + ball8.y + centerY);
		ctx.lineTo(ball11.x + ball8.x + centerX, ball11.y + ball8.y + centerY);
		ctx.moveTo(ball1.x + centerX, ball1.y + centerY);
		ctx.lineTo(ball10.x + ball8.x + centerX, ball10.y + ball8.y + centerY);
		ctx.moveTo(ball8.x + centerX, ball8.y + centerY);
		ctx.lineTo(ball10.x + ball8.x + centerX, ball10.y + ball8.y + centerY);
		
		ctx.moveTo(ball8.x + centerX, ball8.y + centerY);
		ctx.lineTo(ball11.x + ball8.x + centerX, ball11.y + ball8.y + centerY);
		ctx.lineTo(ball12.x + ball10.x + ball8.x + centerX, ball12.y + ball10.y + ball8.y + centerY);
		ctx.lineTo(ball10.x + ball8.x + centerX, ball10.y + ball8.y + centerY);
		ctx.lineTo(ball13.x + ball10.x + ball8.x + centerX, ball13.y + ball10.y + ball8.y + centerY);
		ctx.moveTo(ball12.x + ball10.x + ball8.x + centerX, ball12.y + ball10.y + ball8.y + centerY);
		ctx.lineTo(ball13.x + ball10.x + ball8.x + centerX, ball13.y + ball10.y + ball8.y + centerY);
		
		ctx.stroke();
		
		/*
		//右側の歩行の軌跡を描く
		ctx2.lineWidth = 0;
		ctx2.fillStyle = "#cccccc";
		ctx2.beginPath();
		ctx2.arc(ball13.x + ball10.x + ball8.x + centerX, ball13.y + ball10.y + ball8.y + centerY, 0.5, 0, Math.PI*2, false);
		ctx2.fill();
		*/
	}
	
	//ロジックの処理を行うオブジェクトのグループ
	Model = 
	{
		//空のinit関数を作る
		init: function()
		{

		},

		button: function()
		{

		},

		ball: function()
		{
			//インスタンス変数
			this.x = 0;
			this.y = 0;
			this.z = 0;
			this.xpos = 0;
			this.ypos = 0;
			this.zpos = 0;
			this.radius = size;
		},

		rotateX: function(ball, angleX)
		{
			var cosX = Math.cos(angleX);
			var sinX = Math.sin(angleX);
			var y1 = ball.ypos * cosX - ball.zpos * sinX;
			var z1 = ball.zpos * cosX + ball.ypos * sinX;
			ball.ypos = y1;
			ball.zpos = z1;
		},

		rotateY: function(ball, angleY)
		{
			var cosY = Math.cos(angleY);
			var sinY = Math.sin(angleY);
			var x1 = ball.xpos * cosY - ball.zpos * sinY;
			var z1 = ball.zpos * cosY + ball.xpos * sinY;
			ball.xpos = x1;
			ball.zpos = z1;
		},

		rotateZ: function(ball, angleZ)
		{
			var cosZ = Math.cos(angleZ);
			var sinZ = Math.sin(angleZ);
			var x1 = ball.xpos * cosZ - ball.ypos * sinZ;
			var y1 = ball.ypos * cosZ + ball.xpos * sinZ;
			ball.xpos = x1;
			ball.ypos = y1;
		},

		perspective: function(ball)
		{
			//this.ball = ball;
			var scale = fl/(fl+ball.zpos);
			ball.x = ball.xpos*scale;
			ball.y = ball.ypos*scale;
			ball.z = ball.zpos;
			ball.radius = size * scale;
		}
	}
			
	//Modelの中の関数(init)にプロトタイプの変数や関数を定義します
	//プロトタイプには、インスタンスで使う共有の関数や変数を設定します
	Model.init.prototype.sliderStartHandler = function()
	{
		var name = this.getAttribute("Id");
    	var element = document.getElementById(name);
    	//element.style.backgroundPosition = "0 -780px";

		document.getElementById(name).removeEventListener(buttonStart, model.sliderStartHandler, false);
		document.getElementById(name).addEventListener(buttonMove, model.sliderMoveHandler, false);
		var ele = document.getElementById(name);
		sliderLeft = (ele.currentStyle || document.defaultView.getComputedStyle(ele,'')).left;
		sliderLeft = Number(sliderLeft.replace('px',''));
		
		if(Sandbox.prototype.g_mobiledevice === true)
		{
			event.preventDefault();
			var t = event.touches[0];
			sx = t.pageX;
		}
		else
		if(Sandbox.prototype.g_browsername === 'MSIE' || Sandbox.prototype.g_browsername === 'Opera')
        {
            sx = event.clientX + document.body.scrollLeft;
        }
		else
		{
			event.preventDefault();
			sx = event.x + document.body.scrollLeft;
		}
	};

	Model.init.prototype.sliderMoveHandler = function()
    {
    	var name = this.getAttribute("Id");

		if(Sandbox.prototype.g_mobiledevice === true)
		{
			event.preventDefault();
			var t = event.touches[0];
			mx = t.pageX - sx;
		}
		else
		if(Sandbox.prototype.g_browsername === 'MSIE' || Sandbox.prototype.g_browsername === 'Opera')
        {
            mx = event.clientX + document.body.scrollLeft - sx;
        }
		else
		{
			event.preventDefault();
			mx = event.x + document.body.scrollLeft - sx;
		}

		document.getElementById(name).style.left = (sliderLeft + mx) + 'px';
		
		var ele = document.getElementById(name);
		var left = (ele.currentStyle || document.defaultView.getComputedStyle(ele,'')).left;
		left = Number(left.replace('px',''));
		walkZ = (left - 200) * 0.001;
		//console.log("left: "+left);
		
		/*var ele = document.getElementById('review');
		var height = (ele.currentStyle || document.defaultView.getComputedStyle(ele,'')).width;
		height = Number(height.replace('px',''));
		*/
		//var top = (ele.currentStyle || document.defaultView.getComputedStyle(ele,'')).top;
		
		
		if(left > 370)
		{
			left = 370;
			document.getElementById(name).style.left = left + 'px';
		}
		else
		if(left < 20)
		{
			left = 20;
			document.getElementById(name).style.left = left + 'px';
		}
    };

    Model.init.prototype.sliderEndHandler = function()
    {
    	var name = this.getAttribute("Id");
    	var element = document.getElementById(name);
    	//element.style.backgroundPosition = "0 -180px";
    	//event.preventDefault();
		document.getElementById(name).addEventListener(buttonStart, model.sliderStartHandler, false);
		document.getElementById(name).removeEventListener(buttonMove, model.sliderMoveHandler, false);
    };

    // buttonY ここから
    Model.init.prototype.sliderStartHandlerY = function()
	{
		var name = this.getAttribute("Id");
    	var element = document.getElementById(name);
    	//element.style.backgroundPosition = "0 -780px";

		document.getElementById(name).removeEventListener(buttonStart, model.sliderStartHandlerY, false);
		document.getElementById(name).addEventListener(buttonMove, model.sliderMoveHandlerY, false);
		var ele = document.getElementById(name);
		sliderLeftY = (ele.currentStyle || document.defaultView.getComputedStyle(ele,'')).left;
		sliderLeftY = Number(sliderLeftY.replace('px',''));
		
		if(Sandbox.prototype.g_mobiledevice === true)
		{
			event.preventDefault();
			var t = event.touches[0];
			sxY = t.pageX;
		}
		else
		if(Sandbox.prototype.g_browsername === 'MSIE' || Sandbox.prototype.g_browsername === 'Opera')
        {
            sxY = event.clientX + document.body.scrollLeft;
        }
		else
		{
			event.preventDefault();
			sxY = event.x + document.body.scrollLeft;
		}
	};

	Model.init.prototype.sliderMoveHandlerY = function()
    {
    	var name = this.getAttribute("Id");

		if(Sandbox.prototype.g_mobiledevice === true)
		{
			event.preventDefault();
			var t = event.touches[0];
			mxY = t.pageX - sxY;
		}
		else
		if(Sandbox.prototype.g_browsername === 'MSIE' || Sandbox.prototype.g_browsername === 'Opera')
        {
            mxY = event.clientX + document.body.scrollLeft - sxY;
        }
		else
		{
			event.preventDefault();
			mxY = event.x + document.body.scrollLeft - sxY;
		}

		document.getElementById(name).style.left = (sliderLeftY + mxY) + 'px';
		
		var ele = document.getElementById(name);
		var left = (ele.currentStyle || document.defaultView.getComputedStyle(ele,'')).left;
		left = Number(left.replace('px',''));
		walkY = (left - 200) * 0.0001;
		//console.log("left: "+left);
		
		if(left > 370)
		{
			left = 370;
			document.getElementById(name).style.left = left + 'px';
		}
		else
		if(left < 20)
		{
			left = 20;
			document.getElementById(name).style.left = left + 'px';
		}
    };

    Model.init.prototype.sliderEndHandlerY = function()
    {
    	var name = this.getAttribute("Id");
    	var element = document.getElementById(name);
    	//element.style.backgroundPosition = "0 -180px";
    	//event.preventDefault();
		document.getElementById(name).addEventListener(buttonStart, model.sliderStartHandlerY, false);
		document.getElementById(name).removeEventListener(buttonMove, model.sliderMoveHandlerY, false);
    };
    // buttonY ここまで

	Model.ball.prototype.func = function()
	{
		var str = this.xpos + "," + this.ypos + "," + this.zpos + "," + this.radius;
		return str;
	};

	Model.init.prototype.ready = function()
	{
		//辺BC
		var dx = x_c_init - x_b;
		var dy = y_c_init - y_b;
		side_a = Math.sqrt(dx*dx+dy*dy);
		
		//辺AC
		dx = x_c_init - x_a;
		dy = y_c_init - y_a;
		side_b = Math.sqrt(dx*dx+dy*dy);
		
		//辺AE
		dx = x_e_init - x_a;
		dy = y_e_init - y_a;
		side_b2 = Math.sqrt(dx*dx+dy*dy);
		
		//辺BE
		dx = x_e_init - x_b;
		dy = y_e_init - y_b;
		side_a2 = Math.sqrt(dx*dx+dy*dy);
		
		//辺CF
		dx = x_c_init - x_f_init;
		dy = y_c_init - y_f_init;
		side_b3 = Math.sqrt(dx*dx+dy*dy);
		
		//辺BF
		dx = x_b - x_f_init;
		dy = y_b - y_f_init;
		side_c2 = Math.sqrt(dx*dx+dy*dy);
		
		//辺FG
		dx = x_g_init - x_f_init;
		dy = y_g_init - y_f_init;
		side_e2 = Math.sqrt(dx*dx+dy*dy);
		
		//辺EG
		dx = x_g_init - x_e_init;
		dy = y_g_init - y_e_init;
		side_f = Math.sqrt(dx*dx+dy*dy);
		side_h = side_f;
		
		//辺GH
		dx = x_g_init - x_h_init;
		dy = y_g_init - y_h_init;
		side_e3 = Math.sqrt(dx*dx+dy*dy);
		
		//辺EH
		dx = x_e_init - x_h_init;
		dy = y_e_init - y_h_init;
		side_g2 = Math.sqrt(dx*dx+dy*dy);
		
		//Canvasのエレメント要素を変数に代入する
		theCanvas = document.getElementById("viewArea");

		//Canvasタグで2次元描画を行ないます
		ctx = theCanvas.getContext("2d");
		
		//Canvasの中心座標を取得
		//centerX: Canvasタグの横幅の1/2を取得
		offsetX = (theCanvas.currentStyle || document.defaultView.getComputedStyle(theCanvas,'')).width;
		offsetX = Number(offsetX.replace('px',''));
		centerX =  offsetX / 2;
		//centerX =  offsetX - 55;
		vpX = centerX; //x座標の消失点
		
		//centerY: Canvasタグの高さの1/2を取得
		offsetY = (theCanvas.currentStyle || document.defaultView.getComputedStyle(theCanvas,'')).height;
		offsetY = Number(offsetY.replace('px',''));
		//centerY =  offsetY / 2;
		vpY = offsetY/2; //y座標の消失点
		centerY = 100;

		//Canvasのエレメント要素を変数に代入する
		theCanvas2 = document.getElementById("viewArea2");

		//Canvasタグで2次元描画を行ないます
		ctx2 = theCanvas2.getContext("2d");
	};

	//ボタンタイプ
    Model.init.prototype.setButton = function()
    {
        if(Sandbox.prototype.g_mobiledevice === true)
        {
            buttonStart = 'touchstart';
            buttonMove = 'touchmove';
            buttonEnd = 'touchend';
        }
        else
        {
            buttonStart = 'mousedown';
            buttonMove = 'mousemove';
            buttonEnd = 'mouseup';
        }

        //window.alert('ブラウザ: ' + Sandbox.prototype.g_browsername);
        console.log('ブラウザ: ' + Sandbox.prototype.g_browsername);
    };

	
	
	//Modelの中のInit関数のインスタンスを生成
	var model = new Model.init();

	//Model関数のプロトタイプにあるready関数を呼び出します
	model.ready();
	model.setButton();
	
	//model.sliderEndHandler();



	var ball0 = new Model.ball();
	ball0.xpos = 0;
	ball0.ypos = 0;

	var ball1 = new Model.ball();

	var ball2 = new Model.ball();
	ball2.xpos = x_b;
	ball2.ypos = y_b;

	var ball3 = new Model.ball();

	var ball4 = new Model.ball();

	var ball5 = new Model.ball();

	var ball6 = new Model.ball();

	var ball7 = new Model.ball();

	var ball8 = new Model.ball();
	ball8.xpos = -x_b;
	ball8.ypos = y_b;

	var ball9 = new Model.ball();

	var ball10 = new Model.ball();

	var ball11 = new Model.ball();

	var ball12 = new Model.ball();

	var ball13 = new Model.ball();
	
	//Viewの中のInit関数のインスタンスを生成
	var view = new View.init();

	view.button();
	view.drawButtonLine();

	//View関数のプロトタイプにあるanimation関数を呼び出します
	angleZ = 45 * Math.PI/180;
	ball1.xpos = Math.cos(angleZ) * y_oa;
	ball1.ypos = Math.sin(angleZ) * y_oa;


	ball1.xpos = Math.cos(angleZ) * y_oa;
	ball1.ypos = Math.sin(angleZ) * y_oa;

	function animation()
	{
		ball0.xpos = 0;
		ball0.ypos = 0;
		ball0.zpos = 0;
		ball0.radius = size;

		//angleZ += 1 * Math.PI/180;
		angleZ -= walkZ; //0.05
		ball1.xpos = Math.cos(angleZ) * y_oa;
		ball1.ypos = Math.sin(angleZ) * y_oa;
		ball1.zpos = 0;

		ball2.xpos = x_b;
		ball2.ypos = y_b;
		ball2.zpos = 0;

		ball3.xpos = 0;
		ball3.ypos = 0;
		ball3.zpos = 0;

		ball4.xpos = 0;
		ball4.ypos = 0;
		ball4.zpos = 0;

		ball5.xpos = 0;
		ball5.ypos = 0;
		ball5.zpos = 0;

		ball6.xpos = 0;
		ball6.ypos = 0;
		ball6.zpos = 0;

		ball7.xpos = 0;
		ball7.ypos = 0;
		ball7.zpos = 0;

		ball8.xpos = -x_b;
		ball8.ypos = y_b;
		ball8.zpos = 0;

		ball9.xpos = 0;
		ball9.ypos = 0;
		ball9.zpos = 0;

		ball10.xpos = 0;
		ball10.ypos = 0;
		ball10.zpos = 0;

		ball11.xpos = 0;
		ball11.ypos = 0;
		ball11.zpos = 0;

		ball12.xpos = 0;
		ball12.ypos = 0;
		ball12.zpos = 0;

		ball13.xpos = 0;
		ball13.ypos = 0;
		ball13.zpos = 0;

		ctx.clearRect(0, 0, offsetX, offsetY);

		//View関数のプロトタイプにあるanimation関数を呼び出します
		view.pointInit();
		
		//angleY += 1 * Math.PI/180; //45 * Math.PI/180
		angleY += walkY;

		view.animation();
		view.draw();
		

		requestAnimationFrame(animation);
	}
	animation();
}

// 各ブラウザ対応
//Safari対応で、一番外側に書く
(function()
{
    var requestAnimationFrame = window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function(callback)
            {
                setTimeout(callback, 1000 / 60);
            };

    var cancelAnimationFrame = window.cancelAnimationFrame ||
            window.webkitCancelRequestAnimationFrame ||
            window.mozCancelRequestAnimationFrame ||
            window.oCancelRequestAnimationFrame ||
            window.msCancelRequestAnimationFrame ||
            function(id)
            {
                clearTimeout(id);
            };

    window.requestAnimationFrame = requestAnimationFrame;
    window.cancelAnimationFrame = cancelAnimationFrame;
})();

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です