以下が、ブロック崩しアプリの実装例です。
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ブロック崩し</title>
<style>
#canvas {
display: block;
margin: 0 auto;
border: 1px solid #ccc;
background-color: #eee;
}
</style>
</head>
<body>
<h1>ブロック崩し</h1>
<canvas id="canvas" width="480" height="320"></canvas>
<script>
// キャンバスのコンテキストを取得
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// ボールの情報
var ball = {
radius: 10,
x: canvas.width/2,
y: canvas.height-30,
dx: 3,
dy: -3
};
// パドルの情報
var paddle = {
width: 75,
height: 10,
x: (canvas.width-75)/2,
y: canvas.height-10
};
// ブロックの情報
var brickRowCount = 3;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
// スコアの初期値
var score = 0;
// ブロックの配列
var bricks = [];
for(var c=0; c<brickColumnCount; c++) {
bricks[c] = [];
for(var r=0; r<brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}
// キーイベントのリスナーを追加
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
// キーを離したときの処理
function keyDownHandler(e) {
if(e.keyCode == 39) { // right
rightPressed = true;
}
else if(e.keyCode == 37) { // left
leftPressed = true;
}
}
// キーを押したときの処理
function keyUpHandler(e) {
if(e.keyCode == 39) { // right
rightPressed = false;
}
else if(e.keyCode == 37) { // left
leftPressed = false;
}
}
// 衝突判定
function collisionDetection() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(b.status == 1) {
if(ball.x > b.x && ball.x < b.x+brickWidth && ball.y > b.y && ball.y < b.y+brickHeight) {
ball.dy = -ball.dy;
b.status = 0;
score++;
if(score == brickRowCount*brickColumnCount) {
alert("Congratulations! You won!\n(プログラマーがビールを奢ります)");
document.showToast("再読み込みしてください");
}
}
}
}
}
}
// 描画処理
function draw() {
// キャンバスの内容をクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ブロックの描画
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
if(bricks[c][r].status == 1) {
var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
// ボールの描画
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
// パドルの描画
ctx.beginPath();
ctx.rect(paddle.x, paddle.y, paddle.width, paddle.height);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
// スコアの描画
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: "+score, 8, 20);
// パドルの移動
if(rightPressed && paddle.x < canvas.width-paddle.width) {
paddle.x += 7;
}
else if(leftPressed && paddle.x > 0) {
paddle.x -= 7;
}
// ボールの移動
ball.x += ball.dx;
ball.y += ball.dy;
// 壁の衝突判定
if(ball.x + ball.dx > canvas.width-ball.radius || ball.x + ball.dx < ball.radius) {
ball.dx = -ball.dx;
}
if(ball.y + ball.dy < ball.radius) {
ball.dy = -ball.dy;
}
else if(ball.y + ball.dy > canvas.height-ball.radius) {
if(ball.x > paddle.x && ball.x < paddle.x + paddle.width) {
ball.dy = -ball.dy;
}
else {
alert("Game Over\n(プログラマーがお茶を奢ります)");
document.showToast("再読み込みしてください");
}
}
// ブロックとの衝突判定
collisionDetection();
// 次のフレームの描画処理
requestAnimationFrame(draw);
}
// 初期描画
draw();
</script>
</body>
</html>
```
ジョークを盛り込んでみました。実際のアプリだと、勝っても負けても何も起こりませんが、このアプリでは勝利時に「(プログラマーがビールを奢ります)」、敗北時に「(プログラマーがお茶を奢ります)」というメッセージを表示するようにしています。