今日のエッセイ

気まぐれゲーム作りです。

ゲームの王道ブロック崩しです。
パドルを左右に動かしてボールを弾き、上のブロックを消していきます。
とてもシンプルですが、プログラミングすると奥が深いです。

ゲームをスタートすると、パドルの上にボールが少し浮いた形で乗っています。
左右に動かして、好きな位置でスペースキーを押すと、ボールが発射されます。
後は、ボールが落ちないように、パドルで弾くだけです。

左上はスコア表示で、ブロックが一つ消えるごとに100点入ります。
右上はゲームレベルです。
ブロックを全て消すと、ブロックがリセットされて、戻ります。
その時にレベル表示が変わり、ボールのスピードがアップします。

ボールが落ちない限りゲームが続き、落ちるとゲームが止まってゲームオーバーです。
その時にハイスコアが表示されます。

タイトル:「Block-Breaker's」


ゲームのオープニング画面


ゲーム画面


ゲームオーバー画面


プログラムはJavaScriptです。
HTMLの中に埋め込む形です。
<script>タグ内がJavaScriptとなります。
画像ファイルがなくても遊べます。

		function resetGame() { //ゲームをリセットする
			// ballをリセットする
			ball.x = canvas.width / 2;
			ball.y = 440; 
			ball.speedX = speed; //speedX:5
			ball.speedY = speed; //speedY:-5

			// paddleをリセットする
			paddle.x = canvas.width / 2 - paddle.width / 2;
			paddle.y = 460;

			// blockをリセットする
			blocks = [];
			for (var row = 0; row < 3; row++) {
				for (var col = 0; col < 10; col++) {
					blocks.push({
						x: col * blockWidth + 10,
						y: row * blockHeight + 50,
						width: blockWidth,
						height: blockHeight,
						color: getRandomColor(),
						visible: true
					});
				}
			}
                  count = 30;
                  space = false;
		}

ゲームをリセットするコードです。
スタート時にボールやパドルの位置をセットします。

		function resetBlock() { //blockをリセットする

			
			for (var row = 0; row < 3; row++) {
				for (var col = 0; col < 10; col++) {
					blocks.push({
						x: col * blockWidth + 10,
						y: row * blockHeight + 50,
						width: blockWidth,
						height: blockHeight,
						color: getRandomColor(),
						visible: true
					});
				}
			}
                  count = 30;
		}

blockを全部消去した後に再度セットする関数です。
変数countは、blockの数を表しています。

	function moveBall() { //ボールの動き
		ball.x += ball.speedX;
		ball.y += ball.speedY;

		// ボールが左右の壁に当たった時の判定
		if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) {
			ball.speedX = -ball.speedX;
		}

		// ボールが上の壁に当たった時の判定
		if (ball.y - ball.radius < 0) {
			ball.speedY = -ball.speedY;
		}

		// ボールが下の壁に当たった時の判定
		if (ball.y + ball.radius > canvas.height) {
			drawGameend(); //ゲームオーバー表示
			clearinterval(); //ゲームを止める時
			//ball.speedY = -ball.speedY; //落下無し無限ラリー
		}
	}

ボールの動きを設定する関数です。
clearinterval()はゲームを止める関数です。
ball.speedY=-ball.speedYを使うと落下しても跳ね返り、無限にラリーができます。
練習用です。
どんどん上がっていくスピードを体感してみてください。
これを使う時は、clearinterval()とdrawGameend()をコメントアウトします。

		function movePaddle() { //paddleの動き
		if (leftKeyDown) { //left key
			paddle.x -= paddle.speed;
			if(space==false){ball.x -= paddle.speed;}
			if (paddle.x < 0) {
				paddle.x = 0;
				if(space==false){ball.x=paddle.width/2;}
			}
		}

		if (rightKeyDown) { //right key
			paddle.x += paddle.speed;
			if(space==false){ball.x += paddle.speed;}
			if (paddle.x + paddle.width > canvas.width) {
				paddle.x = canvas.width - paddle.width;
				if(space==false){ball.x=canvas.width-paddle.width/2;}
			}
		}
		if (spaceKeyDown) { //space key
                        ball.speedX=speed+sp;
                        ball.speedY=-speed+sp;                                   
		}

	}

パドルの動きを設定する関数です。
ボールを発射するまでは、パドルについていくようになっています。

	function checkCollisions() { //衝突判定
		// ボールがパドルに当たった時の判定
		if (collision(ball, paddle)) {
			ball.speedY = -ball.speedY;
		}
            
		// ボールがブロックに当たった時の判定
		for (var i = 0; i < blocks.length; i++) {
			if (collision(ball, blocks[i]) && blocks[i].visible) {
				ball.speedY = -ball.speedY;
				blocks[i].visible = false;
				score+=100;
				count-=1; //blockの個数判定
				
				if(count == 0){ //blockを全部消した後の処理
				setTimeout(resetBlock, 1500); //指定ミリ秒後にblockを表示する
				lv += 1;
				if(ball.speedX < 0){ //ballのスピード調整
				ball.speedX -= 1;}
				else{ball.speedX += 1;}
				
				if(ball.speedY > 0){
				ball.speedY +=1;}
				else{ball.speedY -= 1;}
				}
			}
		}
	}

衝突判定についての関数です。

全体のソースコードです。

<!DOCTYPE html>
<html>
<head>
	<title>Block-Breaker's</title>
	<style>
		#gameCanvas {
			border: 2px solid #FFAA00; 
			background-color: #FFFF88;
		}
	</style>
</head>
<body onload="startGame()">
	<canvas id="gameCanvas" width="520" height="480"></canvas>
	<script>
		var canvas;
		var context;

		var ball = {//speedX:5,speedY:5
			x: 320,
			y: 240,
			radius: 10,
			speedX: 5,
			speedY: 5
		};

		var paddle = {
			x: 250,
			y: 460,
			width: 100,
			height: 20,
			speed: 15//speed:10
		};

		var blocks = [];
		var blockWidth = 50;
		var blockHeight = 20;

		var score = 0;
		var count = 30;
		var space = false;
		var clear = false;
		var speed = 0;
		var sp = 5;
		var lv = 1;


		function startGame() {
			canvas = document.getElementById("gameCanvas");
			context = canvas.getContext("2d");

			document.addEventListener("keydown", handleKeyDown);
			document.addEventListener("keyup", handleKeyUp);

			resetGame();
			setInterval(updateGame, 20);
		}

		function resetGame() { //ゲームをリセットする
			// ballをリセットする
			ball.x = canvas.width / 2;
			ball.y = 440; 
			ball.speedX = speed; //speedX:5
			ball.speedY = speed; //speedY:-5

			// paddleをリセットする
			paddle.x = canvas.width / 2 - paddle.width / 2;
			paddle.y = 460;

			// blockをリセットする
			blocks = [];
			for (var row = 0; row < 3; row++) {
				for (var col = 0; col < 10; col++) {
					blocks.push({
						x: col * blockWidth + 10,
						y: row * blockHeight + 50,
						width: blockWidth,
						height: blockHeight,
						color: getRandomColor(),
						visible: true
					});
				}
			}
                  count = 30;
                  space = false;
		}
		
		function resetBlock() { //blockをリセットする

			
			for (var row = 0; row < 3; row++) {
				for (var col = 0; col < 10; col++) {
					blocks.push({
						x: col * blockWidth + 10,
						y: row * blockHeight + 50,
						width: blockWidth,
						height: blockHeight,
						color: getRandomColor(),
						visible: true
					});
				}
			}
                  count = 30;
		}

		function updateGame() { //ゲームの更新
			context.clearRect(0, 0, canvas.width, canvas.height);

			drawBall();
			drawPaddle();
			drawBlocks();
			drawScore();
			drawLv();

			moveBall();
			movePaddle();
			checkCollisions();
		}

		function drawBall() { //ballを描画
			context.beginPath();
			context.arc(ball.x, ball.y, ball.radius, 0, 2 * Math.PI);
			context.fillStyle = "#FFBB99";
			context.fill();
			context.closePath();
		}

		function drawPaddle() { //paddleを描画
			context.fillStyle = "#00FF99";
			context.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
		}

		function drawBlocks() { //blockを描画
			for (var i = 0; i < blocks.length; i++) {
				if (blocks[i].visible) {
             context.fillStyle = blocks[i].color;
       context.fillRect(blocks[i].x, blocks[i].y, blocks[i].width, blocks[i].height);
                                            }
                                            }
                                            }
	function drawScore() { //スコア表示
		context.fillStyle = "#00AAFF";
		context.font = "30px Arial";
		context.fillText("1P:" + score, 10, 25);
	}
	
	function drawGameend() { //ゲームオーバーの表示
		context.fillStyle = "#FFAAAA";
		context.font = "30px Arial";
		context.fillText("Game Over. Your Hi score is "+ score, 30, 220);
	}
	
	function drawLv() { //ゲームレベル表示
		context.fillStyle = "#00FF88";
		context.font = "30px Arial";
		context.fillText("Lv: "+ lv, 430, 25);
	}

	function moveBall() { //ボールの動き
		ball.x += ball.speedX;
		ball.y += ball.speedY;

		// ボールが左右の壁に当たった時の判定
		if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) {
			ball.speedX = -ball.speedX;
		}

		// ボールが上の壁に当たった時の判定
		if (ball.y - ball.radius < 0) {
			ball.speedY = -ball.speedY;
		}

		// ボールが下の壁に当たった時の判定
		if (ball.y + ball.radius > canvas.height) {
			drawGameend(); //ゲームオーバー表示
			clearinterval(); //ゲームを止める時
			//ball.speedY = -ball.speedY; //落下無し無限ラリー
		}
	}

	function movePaddle() { //paddleの動き
		if (leftKeyDown) { //left key
			paddle.x -= paddle.speed;
			if(space==false){ball.x -= paddle.speed;}
			if (paddle.x < 0) {
				paddle.x = 0;
				if(space==false){ball.x=paddle.width/2;}
			}
		}

		if (rightKeyDown) { //right key
			paddle.x += paddle.speed;
			if(space==false){ball.x += paddle.speed;}
			if (paddle.x + paddle.width > canvas.width) {
				paddle.x = canvas.width - paddle.width;
				if(space==false){ball.x=canvas.width-paddle.width/2;}
			}
		}
		if (spaceKeyDown) { //space key
                        ball.speedX=speed+sp;
                        ball.speedY=-speed+sp;                                   
		}

	}

	function checkCollisions() { //衝突判定
		// ボールがパドルに当たった時の判定
		if (collision(ball, paddle)) {
			ball.speedY = -ball.speedY;
		}
            
		// ボールがブロックに当たった時の判定
		for (var i = 0; i < blocks.length; i++) {
			if (collision(ball, blocks[i]) && blocks[i].visible) {
				ball.speedY = -ball.speedY;
				blocks[i].visible = false;
				score+=100;
				count-=1; //blockの個数判定
				
				if(count == 0){ //blockを全部消した後の処理
				setTimeout(resetBlock, 1500); //指定ミリ秒後にblockを表示する
				lv += 1;
				if(ball.speedX < 0){ //ballのスピード調整
				ball.speedX -= 1;}
				else{ball.speedX += 1;}
				
				if(ball.speedY > 0){
				ball.speedY +=1;}
				else{ball.speedY -= 1;}
				}
			}
		}
	}

	function collision(object1, object2) {
	if (object1.x < object2.x + object2.width && object1.x + object1.radius * 2 > object2.x &&object1.y < object2.y + object2.height && object1.y + object1.radius * 2 > object2.y) {
			return true;
		} else {
			return false;
		}
	}

	function getRandomColor() { //ランダムでblockの色を決定する
		var letters = "0123456789ABCDEF";
		var color = "#";
		for (var i = 0; i < 6; i++) {
			color += letters[Math.floor(Math.random() * 16)];
		}
		return color;
	}

	var leftKeyDown = false;
	var rightKeyDown = false;
	var spaceKeyDown = false;

	function handleKeyDown(event) { //Keyを押した時
	//kyecode 37:Left 39:Right 38:Up 40:Down 32:Space
		if (event.keyCode == 37) { // Key Left
			leftKeyDown = true;
		} else if (event.keyCode == 39) { // Key Right
			rightKeyDown = true;
		} else if (event.keyCode == 32) { // Key Space
			spaceKeyDown = true;
			space = true;
		}
	}

	function handleKeyUp(event) { //Keyを離した時
		if (event.keyCode == 37) { // Key Left
			leftKeyDown = false;
		} else if (event.keyCode == 39) { // Key Right
			rightKeyDown = false;
		} else if (event.keyCode == 32) { // Key Space
			spaceKeyDown = false;
		}
	}
</script>