HTML5 の canvas を練習するために作りました。
マウスでキャンバス上のボールを転がすアプリです。
使い方
キャンバス上を適当にクリックすると、赤いボールがクリックされた方向へ転がります。
ボールは徐々に減速し、最後には止まります。
使用している技術
html5 の canvas
javascript
【バグ】
以下、ソースを掲載します。
<!DOCTYPE html>
<html lang = "ja" >
<head>
<meta charset = "UTF-8">
<title> アニメーションサンプル </title>
<style type = "text/css">
<!-- キャンバスの定義 -->
#id_canvas
{
position : absolute;
top : 0px;
left : 0px;
z-index : 1;
}
</style>
<script src = "./utility.js" ></script>
<script type = "text/javascript" >
// --------------------------
// ---- コールバック関数 ----
// --------------------------
// マウスクリック時に呼ばれる関数
mouseClkEv = function mouseClickEvent( e_ )
{
var rect = e_.target.getBoundingClientRect();
var mouseClickX = e_.clientX - rect.left;
var mouseClickY = e_.clientY - rect.top;
ball.dirTo( mouseClickX, mouseClickY );
ball.addVelocity( 10 );
}
// マウスが動いた時に呼ばれる関数
mouseMoveEv = function mouseMoveEvent( e_ )
{
canvas = document.getElementById("id_canvas");
context = canvas.getContext("2d");
var rect = e_.target.getBoundingClientRect();
var mouseMoveX = e_.clientX - rect.left ;
var mouseMoveY = e_.clientY - rect.top ;
textArea = document.getElementById("coodination");
textArea.innerHTML = "("
+ mouseMoveX
+ ", "
+ mouseMoveY
+ ")";
}
// キャンバスを再描画する関数
function redrawAll( _obstacles, _ball )
{
canvas = document.getElementById("id_canvas");
context = canvas.getContext("2d");
context.clearRect( 0, 0, width + 10, height + 10 );
drawAll( _obstacles, _ball );
}
function drawAll( _obstacles, _ball )
{
drawObstacles( _obstacles );
drawBall( _ball );
}
function drawWalls( _walls )
{
canvas = document.getElementById("id_canvas");
context = canvas.getContext("2d");
context.beginPath();
context.strokeStyle = "rgba(0, 0, 0, 0.5)";
for( i = 0; i < _walls.length; i++ )
{
context.moveTo(
_walls[i].tailX_, _walls[i].tailY_
);
context.lineTo(
_walls[i].headX_, _walls[i].headY_
);
}
context.stroke();
}
function drawObstacles( _obstacles )
{
for( j = 0; j < _obstacles.length; j++ )
{ drawWalls( _obstacles[j] ); }
}
function drawBall( ball_ )
{
canvas = document.getElementById("id_canvas");
context = canvas.getContext("2d");
context.beginPath();
context.strokeStyle = "rgba(255, 0, 0, 0.5)";
context.arc(
ball_.curX_,
ball_.curY_,
5,
0,
360
);
context.stroke();
}
// ----------------------------
// ---- アニメーション関連 ----
// ----------------------------
// 0.1 秒毎に呼び出される関数
// 0.1 秒毎に ball 動かし, 衝突判定と再描画をします.
// ball は 0.1 秒毎に少しずつ減速します.
var delta = 0.1;
function action()
{
ball.gensoku( delta ); // 減速
ball.moveTo( delta ); // 動かす
collision( obstacles, ball, delta ); // 衝突判定
redrawAll( obstacles, ball ); // 再描画
}
onload = function init()
{
drawAll( obstacles, ball );
// キャンバスへのマウスイベントの登録
canvas = document.getElementById("id_canvas");
context = canvas.getContext();
canvas.addEventListener( "click", mouseClkEv, false );
canvas.addEventListener( "mousemove", mouseMoveEv, false );
// 100 ミリ秒毎に, action() 関数が呼ばれるに, 関数を登録.
setInterval( "action()", 1000 * delta );
}
// インスタンスの定義
// 障害物の生成
var obstacles = new Array(0);
// 外壁の生成
var width = 500;
var height = 500;
var field = new Array(4);
field[0] = new Wall( 0, 0, 0, height );
field[1] = new Wall( 0, height, width, height );
field[2] = new Wall( width, height, width, 0 );
field[3] = new Wall( width, 0, 0, 0 );
obstacles.push( field );
// ボールの生成
// 初期位置は 250, 250
var ball = new Ball( 250, 250 );
</script>
</head>
<body>
キャンバス↓
<div id = "coodination" ></div>
<canvas id = "id_canvas" width = 1200 height = 1200 ></canvas>
<menu type = "toolbar">
</body>
</html>
// 壁にボールが当たって跳ね返る処理を記述したコードです。
// HTML5 の機能とは関係ないのですが, 掲載いたします。
// ----------------------
// ---- 数学いろいろ ----
// ----------------------
function normalize( _x, _y )
{
d = Math.sqrt( innerProduct( _x, _y, _x, _y ) );
var ret = new Array(2);
ret[0] = _x / d;
ret[1] = _y / d;
return ret;
}
function computeNormalVector( _x, _y, _theta )
{
var ret = new Array(2);
ret[0] = Math.cos( _theta ) * _x + Math.sin( _theta ) * _y;
ret[1] = - Math.sin( _theta ) * _x + Math.cos( _theta ) * _y;
return normalize( ret[0], ret[1] );
}
function innerProduct( _ux, _uy, _vx, _vy )
{ return ( _ux * _vx ) + ( _uy * _vy ); }
function computeRadian( _t ) { return _t * Math.PI / 180.0; }
// ABC が左回りならば, 正となる符号付き面積.
function signedArea(
_ax, _ay,
_bx, _by,
_cx, _cy
)
{
temp1 = ( _bx - _ax ) * ( _cy - _ay );
temp2 = ( _cx - _ax ) * ( _by - _ay );
return temp1 - temp2;
}
function isIntersected(
_ax, _ay,
_bx, _by,
_cx, _cy,
_dx, _dy
)
{
abc = signedArea( _ax, _ay, _bx, _by, _cx, _cy );
abd = signedArea( _ax, _ay, _bx, _by, _dx, _dy );
cda = signedArea( _cx, _cy, _dx, _dy, _ax, _ay );
cdb = signedArea( _cx, _cy, _dx, _dy, _bx, _by );
temp1 = abc * abd;
temp2 = cda * cdb;
if( ( temp1 < 0.0 ) && ( temp2 < 0.0 ) )
{ return true; }
else
{ return false; }
}
function intersection(
_ax, _ay,
_bx, _by,
_cx, _cy,
_dx, _dy
)
{
var n = new Array(2);
var m = new Array(2);
var a = new Array(2);
var b = new Array(2);
n = normalize( _ax - _bx, _ay - _by );
a[0] = _ax; a[1] = _ay;
m = normalize( _cx - _dx, _cy - _dy );
b[0] = _cx; b[1] = _cy;
beta = ( ( n[1] * ( a[0] - b[0] ) ) - ( n[0] * ( a[1] - b[1] ) ) )
/ ( ( n[1] * m[0] ) - ( n[0] * m[1] ) );
var ret = new Array(2);
ret[0] = ( m[0] * beta ) + b[0];
ret[1] = ( m[1] * beta ) + b[1];
return ret;
}
// ----------------
// ---- ボール ----
// ----------------
function Ball( _startX, _startY )
{
this.curX_ = _startX;
this.curY_ = _startY;
this.preX_ = _startX;
this.preY_ = _startY;
this.dirX_ = 1;
this.dirY_ = 0;
this.velocity_ = 0.0; // 速度( pix/sec )
this.acceleration_ = -4; // 加速度( pix/sec^2 )
this.dirTo = function( _x, _y )
{
var temp = new Array(2);
temp = normalize( _x - this.curX_, _y - this.curY_ );
this.dirX_ = temp[0];
this.dirY_ = temp[1];
}
this.moveTo = function( sec_ )
{
this.preX_ = this.curX_;
this.preY_ = this.curY_;
this.curX_ += this.dirX_ * sec_ * this.velocity_;
this.curY_ += this.dirY_ * sec_ * this.velocity_;
}
this.gensoku = function( sec_ )
{
if( this.velocity_ > 0 )
{ this.velocity_ += sec_ * this.acceleration_; }
}
this.addVelocity = function( iV_ )
{
this.velocity_ += iV_;
}
}
// ------------
// ---- 壁 ----
// ------------
function Wall( _tailX, _tailY, _headX, _headY )
{
this.tailX_ = _tailX;
this.tailY_ = _tailY;
this.headX_ = _headX;
this.headY_ = _headY;
this.collision = function( _ball )
{
var normalVector = new computeNormalVector(
this.headX_ - this.tailX_,
this.headY_ - this.tailY_,
computeRadian( 90.0 ) );
var tempVector = new Array(2);
tempVector[0] = -_ball.dirX_;
tempVector[1] = -_ball.dirY_;
var a = innerProduct(
normalVector[0],
normalVector[1],
tempVector[0],
tempVector[1] );
_ball.dirX_ = ( 2.0 * a * normalVector[0] ) - tempVector[0];
_ball.dirY_ = ( 2.0 * a * normalVector[1] ) - tempVector[1];
}
}
function collision( _obstacles, _ball, _sec )
{
for( j = 0; j < _obstacles.length; j++ )
{
for( i = 0; i < _obstacles[j].length; i++ )
{
temp = isIntersected(
_ball.preX_, _ball.preY_,
_ball.curX_, _ball.curY_,
_obstacles[j][i].tailX_, _obstacles[j][i].tailY_,
_obstacles[j][i].headX_, _obstacles[j][i].headY_
);
if( temp == true )
{
_obstacles[j][i].collision( _ball );
var intCoord = new Array(2);
intCoord = intersection(
_ball.preX_,_ball.preY_,
_ball.curX_,_ball.curY_,
_obstacles[j][i].tailX_, _obstacles[j][i].tailY_,
_obstacles[j][i].headX_, _obstacles[j][i].headY_
);
_ball.curX_ = intCoord[0];
_ball.curY_ = intCoord[1];
_ball.preX_ = intCoord[0];
_ball.preY_ = intCoord[1];
}
}
}
}
- jsでオブジェクトとか初めて見たから新鮮… オブジェクト内のメソッドってこんな風に書くのか! -- たかぎ (2012-04-23 22:55:50)
- ありがとうございます!実は、僕も初めてオブジェクト使って書いてみました^^ -- 鈴木泰斗 (2012-04-26 22:41:04)
最終更新:2012年04月26日 22:41