# **ゼミナールB** ### **今回の目標** ブロック崩しゲームにMicro:bitの要素を増やす ### ブロック崩し ・パドルの移動を傾きで制御する ・ボタンを押すと一定回数だけパドルの長さが伸びる ・ボタンを押すとパドルの移動速度が上がる 以上の3つに取り組む ### 方法 ・パドルの移動制御をボタンから加速度に切り替える ・ボタンAを押すとパドルが伸びるようにする  ボールがパドルに3回当たると元に戻る  パドルを伸ばす機能は3回にする ・パドルの移動速度を、ボタンBを押している間だけ速くする ### プログラム ``` <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>ブロック崩し</title> </head> <body> <canvas id = "myCanvas" width="470" height="320"></canvas> <p> <button onclick="connect()">接続する</button> <button id="startButton" onclick="gameStart();">Start</button> <button onclick="disconnect()">切断する</button> </p> <script> const UUID_ACCELEROMETER_SERVICE = 'e95d0753-251d-470a-a062-fa1922dfa9a8' const UUID_ACCELEROMETER_SERVICE_CHARACTERISTIC_DATA = 'e95dca4b-251d-470a-a062-fa1922dfa9a8' const UUID_ACCELEROMETER_SERVICE_CHARACTERISTIC_PERIOD = 'e95dfb24-251d-470a-a062-fa1922dfa9a8' 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' const INTERVAL = 10; 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 = 5; let x = canvas.width/2; let y = canvas.height-30; let dx = 3; let dy = -3; let paddleHeight = 10; let paddleWidth = 100; let paddleX = (canvas.width-paddleWidth)/2; let brickRowCount = 10; let brickColumnCount = 6; let brickWidth = 35; let brickHeight = 10; let brickPadding = 7; let brickOffsetTop = 30; let brickOffsetLeft = 30; let score = 0; let lives = 3; let long = 3; let longmode = 0; let wt = 500; let accelX; 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_ACCELEROMETER_SERVICE, UUID_BUTTON_SERVICE]}, { namePrefix: "BBC micro:bit" } ]} ); server = await device.gatt.connect(); service_accel = await server.getPrimaryService(UUID_ACCELEROMETER_SERVICE); char_accel = await service_accel.getCharacteristic(UUID_ACCELEROMETER_SERVICE_CHARACTERISTIC_DATA); char_accelPeriod = await service_accel.getCharacteristic(UUID_ACCELEROMETER_SERVICE_CHARACTERISTIC_PERIOD); await char_accelPeriod.writeValue(new Uint16Array([INTERVAL])); await char_accel.startNotifications(); 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(); } if(score % 15 == 0) { if(dx > 0){ dx = dx + 0.5; }else{ dx = dx - 0.5; } if(dx > 0){ dy = dy + 0.5; }else{ dy = dy - 0.5; } } if(score == 40) { paddleWidth = 80; } } } } } } 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"; if(score >= 40) { ctx.fillStyle = "yellow"; } 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 drawlong() { ctx.font = "16px Arial"; ctx.fillStyle = "white"; ctx.fillText("Long: "+long, canvas.width/2-20, 20); } function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawBack(canvas, ctx); drawBricks(); drawBall(); drawPaddle(); drawScore(); drawLives(); drawlong(); 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; if(longmode > 0) { longmode -= 1; if(longmode == 0) { paddleWidth -= 40; if(paddleWidth > 70) { ctx.fillStyle = "blue" }else{ ctx.fillStyle = "yellow" } } } } else { lives--; if(!lives) { alert("GAME OVER"); document.location.reload(); char_accel.removeEventListener('characteristicvaluechanged', onAccelerationChanged); char_buttonA.removeEventListener('characteristicvaluechanged', ButtonAState); char_buttonB.removeEventListener('characteristicvaluechanged', ButtonBState); cancelAnimationFrame(animeID); }else { x = canvas.width/2; y = canvas.height-30; dx = 3; dy = -3; paddleX = (canvas.width-paddleWidth)/2; } } } let PaddleSpeed = 4; if(buttonB == 1) { PaddleSpeed = 6; }else{ PaddleSpeed = 4; } if(accelX > 0 && paddleX < canvas.width-paddleWidth) { paddleX += PaddleSpeed; }else if(accelX < 0 && paddleX > 0) { paddleX -= PaddleSpeed; } if(buttonA == 1 && long > 0 && longmode < 1) { paddleWidth += 40; long -= 1; longmode = 3; } 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; char_accel.addEventListener('characteristicvaluechanged', onAccelerationChanged); char_buttonA.addEventListener('characteristicvaluechanged', ButtonAState); char_buttonB.addEventListener('characteristicvaluechanged', ButtonBState); start = undefined; if (animeID != undefined) { cancelAnimationFrame(animeID); } animeID = requestAnimationFrame(draw); } function onAccelerationChanged(event) { accelX = event.target.value.getInt16(0, true) / 1000 * wt; } function ButtonAState(event) { buttonA = event.target.value.getUint8(0); } function ButtonBState(event) { buttonB = event.target.value.getUint8(0); } </script> </body> </html> ``` ### 結果 パドルを傾きで制御することで、操作が難しくなったので、パドルの長さやボールの速度を変更し、簡単化した。 目標の3つを達成することで、Micro:bitの機能をより生かしたゲームを作成することができた。