canvasで少しずつ作るブロック崩し(2/5)
前回はマウスで動くバーを作成しました。今回はボールを打てるようにしていきます。
バーとボール
追加要素
ボールの描画と座標の更新処理、壁、床・天井、バーと接触時にボールを反発させる処理を追加しました。
var BALL = { 'X' : 0, // ボールのX座標 'Y' : 0, // ボールのY座標 'Vx' : 100, // ボール速度(X成分) 'Vy' : 0, // ボール速度(Y成分) 'Vy0' : 100, // ボールの最低速度 'E' : 0.7, // 床の反発係数 'E0' : 10, // 反発時のバタつき防止 'RADIUS' : 5, // ボールの半径 }; var FIELD = { 'GRAVITY' :588, // 重力加速度(0.9 * FPS) 'FPS' : 60, // frame per second }; // ボールの座標更新 function calcBallPosition() { // 縦計算 BALL.Vy += FIELD.GRAVITY * (1/FIELD.FPS); BALL.Y += BALL.Vy * (1/FIELD.FPS); // 床・天井接触 if (BALL.Y <= 0 || height <= BALL.Y) { if (BALL.Y <= 0) { BALL.Y = BALL.E0; BALL.Vy = BALL.Vy * BALL.E * (-1) } else { BALL.Y = height-BALL.E0; BALL.Vy = BALL.Vy * BALL.E * (-1) - BALL.Vy0; } } // 横計算 BALL.X += BALL.Vx * (1/FIELD.FPS); // 壁接触 if (BALL.X <= 0 || width <= BALL.X) { if (BALL.X <= 0) { BALL.X = BALL.E0; } else { BALL.X = width - BALL.E0; } BALL.Vx = BALL.Vx * (-1); } // バー接触 if (BAR.X <= BALL.X && BALL.X <= BAR.X + BAR.WIDTH) { if (Math.abs(BALL.Y - (height - BAR.UNDER)) <= BAR.HEIGHT) { BALL.Y += - BALL.E0; BALL.Vy = BALL.Vy * (-1) - BALL.Vy0; } } }; // ボールの描画 function drawBall() { // ボールの座標更新 //calcBallPosition() ctx.save(); ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; ctx.fillRect(0, 0, width, height); // 円の描画設定 ctx.beginPath(); ctx.arc(BALL.X, BALL.Y, BALL.RADIUS, 0, 2*Math.PI, true); ctx.closePath(); // 色設定 hue += 0.5; ctx.strokeStyle = 'hsl(' + hue + ', 50%, 50%)'; ctx.fillStyle = 'hsl(' + hue + ', 50%, 50%)'; ctx.shadowColor = 'hsl(' + hue + ', 50%, 50%)'; ctx.shadowBlur = 10; // 描画実行 ctx.stroke(); ctx.fill(); ctx.restore(); };
ソースコード
<html> <head> <meta charset="UTF-8"> <script type="text/javascript"> (function() { var canvas; var ctx; var width; var height; var mouseX; var mouseY; var BAR = { 'HEIGHT' : 10, // バーの高さ 'WIDTH' : 50, // バーの幅 'UNDER' : 20, // バーのY座標(床からの高さ) 'X' : 0, // バーのX座標 }; var BALL = { 'X' : 0, // ボールのX座標 'Y' : 0, // ボールのY座標 'Vx' : 100, // ボール速度(X成分) 'Vy' : 0, // ボール速度(Y成分) 'Vy0' : 100, // ボールの最低速度 'E' : 0.7, // 床の反発係数 'E0' : 10, // 反発時のバタつき防止 'RADIUS' : 5, // ボールの半径 }; var FIELD = { 'GRAVITY' :588, // 重力加速度(0.9 * FPS) 'FPS' : 60, // frame per second }; // 初期化処理 function initialize() { canvas = document.getElementById('canvas'); if(!canvas && !canvas.getContext) { return false; } ctx = canvas.getContext('2d'); width = ctx.canvas.width ; height = ctx.canvas.height; // バーの初期位置は中心 mouseX = width/2; BAR.X = mouseX; // ボールの初期位置は中心 BALL.X = width/2; BALL.Y = height/2; canvas.addEventListener('mousemove', getMousePosition, false); setInterval(drawBar, 1000/FIELD.FPS); setInterval(drawBall, 1000/FIELD.FPS); setInterval(calcBallPosition, 1000/FIELD.FPS); }; // マウス座標の更新 function getMousePosition(e) { var rect = e.target.getBoundingClientRect(); mouseX = Math.floor(e.clientX - rect.left); mouseY = Math.floor(e.clientY - rect.top); }; // ボール位置計算 function calcBallPosition() { // 縦計算 BALL.Vy += FIELD.GRAVITY * (1/FIELD.FPS); BALL.Y += BALL.Vy * (1/FIELD.FPS); // 床・天井接触 if (BALL.Y <= 0 || height <= BALL.Y) { if (BALL.Y <= 0) { BALL.Y = BALL.E0; BALL.Vy = BALL.Vy * BALL.E * (-1) } else { BALL.Y = height-BALL.E0; BALL.Vy = BALL.Vy * BALL.E * (-1) - BALL.Vy0; } } // 横計算 BALL.X += BALL.Vx * (1/FIELD.FPS); // 壁接触 if (BALL.X <= 0 || width <= BALL.X) { if (BALL.X <= 0) { BALL.X = BALL.E0; } else { BALL.X = width - BALL.E0; } BALL.Vx = BALL.Vx * (-1); } // バー接触 if (BAR.X <= BALL.X && BALL.X <= BAR.X + BAR.WIDTH) { if (Math.abs(BALL.Y - (height - BAR.UNDER)) <= BAR.HEIGHT) { BALL.Y += - BALL.E0; BALL.Vy = BALL.Vy * (-1) - BALL.Vy0; } } }; var hue = 0.5; function drawBall() { // ボールの座標更新 //calcBallPosition() ctx.save(); ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; ctx.fillRect(0, 0, width, height); // 円の描画設定 ctx.beginPath(); ctx.arc(BALL.X, BALL.Y, BALL.RADIUS, 0, 2*Math.PI, true); ctx.closePath(); // 色設定 hue += 0.5; ctx.strokeStyle = 'hsl(' + hue + ', 50%, 50%)'; ctx.fillStyle = 'hsl(' + hue + ', 50%, 50%)'; ctx.shadowColor = 'hsl(' + hue + ', 50%, 50%)'; ctx.shadowBlur = 10; // 描画実行 ctx.stroke(); ctx.fill(); ctx.restore(); }; function drawBar() { var delay = 1; BAR.X = (mouseX + delay * BAR.X) / (delay+1); ctx.save(); ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; ctx.fillRect(0, 0, width, height); // 色設定 ctx.fillStyle = 'rgb(255,255,0)'; // 円の描画設定 ctx.fillRect(BAR.X, height-BAR.UNDER, BAR.WIDTH, BAR.HEIGHT); // 描画実行 ctx.stroke(); ctx.fill(); ctx.restore(); }; // 初期化イベント window.addEventListener('load', initialize, false); } ) (); </script> </head> <body> <canvas id='canvas' width=500 height=300></canvas> </body> </html>
後はブロックを作ればひとまず形になりそう。
関連ページ
canvasで少しずつ作るブロック崩し(1/5) - Segmentation Fault
canvasで少しずつ作るブロック崩し(3/5) - Segmentation Fault
canvasで少しずつ作るブロック崩し(その4) - Segmentation Fault
canvasで少しずつ作るブロック崩し(5/5) - Segmentation Fault