# **ゼミナールB** ### **今回の目標** Micro:bitを利用したブロック崩しゲームの作成に挑戦する ### ブロック崩し 下記のサイトを参考に、Micro:bitのボタンによってパドルを操作できるようにした 参考資料 ・[純粋な JavaScript を使ったブロック崩しゲーム](https://developer.mozilla.org/ja/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript) ### プログラム ``` <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>brock</title> </head> <body> <canvas id = "myCanvas" width="480" height="320"></canvas> <p> <button onclick="connect()">接続する</button> <button id="startButton" onclick="gameStart();">Start</button> <button onclick="disconnect()">切断する</button> </p> <script> const UUID_BUTTON_SERVICE = 'e95d9882-251d-470a-a062-fa1922dfa9a8' const UUID_BUTTON_SERVICE_CHARACTERISTIC_A = 'e95dda90-251d-470a-a062-fa1922dfa9a8' const UUID_BUTTON_SERVICE_CHARACTERISTIC_B = 'e95dda91-251d-470a-a062-fa1922dfa9a8' let server = null; let device = null; let service_button = null; let char_buttonA = null; let char_buttonB = null; let buttonA, buttonB; let animeID; let canvas = document.getElementById("myCanvas"); let ctx = canvas.getContext("2d"); let ballRadius = 10; let x = canvas.width/2; let y = canvas.height-30; let dx = 3; let dy = -3; let paddleHeight = 10; let paddleWidth = 75; let paddleX = (canvas.width-paddleWidth)/2; let brickRowCount = 5; let brickColumnCount = 3; let brickWidth = 75; let brickHeight = 20; let brickPadding = 10; let brickOffsetTop = 30; let brickOffsetLeft = 30; let score = 0; let lives = 3; let bricks = []; for(let c=0; c<brickColumnCount; c++) { bricks[c] = []; for(let r=0; r<brickRowCount; r++) { bricks[c][r] = { x: 0, y: 0, status: 1 }; } } async function connect() { device = await navigator.bluetooth.requestDevice({ filters: [ {services: [UUID_BUTTON_SERVICE]}, { namePrefix: "BBC micro:bit" } ]} ); server = await device.gatt.connect(); service_button = await server.getPrimaryService(UUID_BUTTON_SERVICE); char_buttonA = await service_button.getCharacteristic(UUID_BUTTON_SERVICE_CHARACTERISTIC_A); char_buttonB = await service_button.getCharacteristic(UUID_BUTTON_SERVICE_CHARACTERISTIC_B); await char_buttonA.startNotifications(); await char_buttonB.startNotifications(); alert("接続が完了しました"); startButton.disabled = false; } function disconnect() { cancelAnimationFrame(animeID); startButton.disabled = true; if (!device || !device.gatt.connected){ return; } device.gatt.disconnect(); alert("切断しました"); } function collisionDetection() { for(let c=0; c<brickColumnCount; c++) { for(let r=0; r<brickRowCount; r++) { let b = bricks[c][r]; if(b.status == 1) { if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) { dy = -dy; b.status = 0; score++; if(score == brickRowCount*brickColumnCount) { alert("YOU WIN, CONGRATS!"); document.location.reload(); } } } } } } function drawBack(canvas, context) { context.beginPath(); context.rect(0,0,canvas.width, canvas.height); context.fillStyle = "black"; context.fill(); } function drawBall() { ctx.beginPath(); ctx.arc(x, y, ballRadius, 0, Math.PI*2); ctx.fillStyle = "white"; ctx.fill(); ctx.closePath(); } function drawPaddle() { ctx.beginPath(); ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight); ctx.fillStyle = "blue"; ctx.fill(); ctx.closePath(); } function drawBricks() { for(let c=0; c<brickColumnCount; c++) { for(let r=0; r<brickRowCount; r++) { if(bricks[c][r].status == 1) { let brickX = (r*(brickWidth+brickPadding))+brickOffsetLeft; let brickY = (c*(brickHeight+brickPadding))+brickOffsetTop; bricks[c][r].x = brickX; bricks[c][r].y = brickY; ctx.beginPath(); ctx.rect(brickX, brickY, brickWidth, brickHeight); ctx.fillStyle = "red"; ctx.fill(); ctx.closePath(); } } } } function drawScore() { ctx.font = "16px Arial"; ctx.fillStyle = "white"; ctx.fillText("Score: "+score, 8, 20); } function drawLives() { ctx.font = "16px Arial"; ctx.fillStyle = "white"; ctx.fillText("Lives: "+lives, canvas.width-65, 20); } function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawBack(canvas, ctx); drawBricks(); drawBall(); drawPaddle(); drawScore(); drawLives(); collisionDetection(); if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) { dx = -dx; } if(y + dy < ballRadius) { dy = -dy; } else if(y + dy > canvas.height-ballRadius) { if(x > paddleX && x < paddleX + paddleWidth) { dy = -dy; } else { lives--; if(!lives) { alert("GAME OVER"); document.location.reload(); char_buttonA.removeEventListener('characteristicvaluechanged', ButtonAState); char_buttonB.removeEventListener('characteristicvaluechanged', ButtonBState); cancelAnimationFrame(animeID); }else { x = canvas.width/2; y = canvas.height-30; dx = 4; dy = -4; paddleX = (canvas.width-paddleWidth)/2; } } } if(buttonB == 1 && paddleX < canvas.width-paddleWidth) { paddleX += 7; } else if(buttonA == 1 && paddleX > 0) { paddleX -= 7; } x += dx; y += dy; animeID = requestAnimationFrame(draw); } async function gameStart() { x = canvas.width/2; y = canvas.height-30; dx = 3; dy = -3; buttonA = 0; buttonB = 0; paddleX = (canvas.width-paddleWidth)/2; ballRadius = 10; brickRowCount = 5; brickColumnCount = 3; brickWidth = 75; brickHeight = 20; brickPadding = 10; brickOffsetTop = 30; brickOffsetLeft = 30; score = 0; lives = 3; bricks = []; for(let c=0; c<brickColumnCount; c++) { bricks[c] = []; for(let r=0; r<brickRowCount; r++) { bricks[c][r] = { x: 0, y: 0, status: 1 }; } } char_buttonA.addEventListener('characteristicvaluechanged', ButtonAState); char_buttonB.addEventListener('characteristicvaluechanged', ButtonBState); start = undefined; if (animeID != undefined) { cancelAnimationFrame(animeID); } animeID = requestAnimationFrame(draw); } function ButtonAState(event) { buttonA = event.target.value.getUint8(0); } function ButtonBState(event) { buttonB = event.target.value.getUint8(0); } </script> </body> </html> ``` ### 結果 Micro:bitのボタンで操作するブロック崩しを作成することができた しかし、難易度が一定なので、ボールの速度などを変えることもしてみたい