# **ゼミナール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の機能をより生かしたゲームを作成することができた。