# **ゼミナール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のボタンで操作するブロック崩しを作成することができた
しかし、難易度が一定なので、ボールの速度などを変えることもしてみたい