# **ゼミナールB**
### **今回の目標**
Micro:bitの加速度センサを利用してボールを動かすことに挑戦して、canvasの使い方を学ぶ
### 加速度を用いたボールの操作
microbitを傾けると、その加速度センサーの値に応じてボールが動くプログラムを作成する
参考資料
・山中さんの「図形をMicro:bitからコントロール(1週目)」のメモ(ありがとうございます)
・[requestAnimationFrameの仕組みと使い方!うまく使ってパフォーマンスを改善しよう!](https://blog.leap-in.com/use-requestanimtionframe/)
・[thisって何?使い方を覚えて、JavaScriptをもっと楽しく使おう!](https://www.sejuku.net/blog/29389)
・[【JavaScript入門】undefined徹底解説!使い方や判定方法まとめ](https://www.sejuku.net/blog/28461)
・[ボールを動かす](https://developer.mozilla.org/ja/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball)
・[ボールを壁で跳ね返させる](https://developer.mozilla.org/ja/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls)
・[クラス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes)
### プログラム
```
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>ボールの操作</title>
</head>
<body>
<canvas id = "myCanvas" width="500" height="500"></canvas>
<p>
<button onclick="connect()">接続する</button>
<button onclick="gameStart()">操作開始</button>
<button onclick="disconnect()">切断する</button>
</p>
<script>
class Circle {
constructor(canvas, context, x, y, r, color, accelX, accelY, velX, velY) {
this.canvas = canvas;
this.context = context;
this.x = x;
this.y = y;
this.r = r;
this.color = color;
this.accelX = accelX;
this.accelY = accelY;
this.velX = velX;
this.velY = velY;
}
drawCircle() {
this.context.beginPath();
this.context.arc(this.x, this.y, this.r, 0, 2 * Math.PI, true);
this.context.fillStyle = this.color;
this.context.fill();
}
setPoint(r) {
this.x = this.canvas.width / 2;
this.y = this.canvas.height / 2;
this.r = r;
}
SpeedReset () {
this.accelX = this.accelY = 0;
this.velX = this.velY = 0;
}
update(accelX1, accelY1, dt) {
let velX0 = this.velX;
let velY0 = this.velY;
this.velX += (this.accelX + accelX1) * dt / 2;
this.velY += (this.accelY + accelY1) * dt / 2;
this.accelX = accelX1;
this.accelY = accelY1;
this.x += (velX0 + this.velX) * dt / 2;
this.y += (velY0 + this.velY) * dt / 2;
if (this.canvas.width - this.r < this.x) {
this.x = this.canvas.width - this.r;
this.velX *= -0.5;
} else if (this.x < this.r) {
this.x = this.r;
this.velX *= -0.5;
}
if (this.canvas.height - this.r < this.y) {
this.y = this.canvas.height - this.r;
this.velY *= -0.5;
} else if (this.y < this.r) {
this.y = this.r;
this.velY *= -0.5;
}
}
}
function drawBack(canvas, context) {
context.beginPath();
context.rect(0,0,canvas.width, canvas.height);
context.fillStyle = "black";
context.fill();
}
function clearCanvas(canvas, context) {
context.clearRect(0,0,canvas.width, canvas.height);
}
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 INTERVAL = 10;
let server = null;
let device = null;
let service_accel = undefined;
let char_accel = null;
let char_accelPeriod = null;
let animeID;
let start;
let previous;
let wt = 100;
let accelX, accelY;
let canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
let ball = new Circle(canvas,ctx,0,0,30,"white",0,0,0,0);
async function connect() {
device = await navigator.bluetooth.requestDevice({
filters: [
{services: [UUID_ACCELEROMETER_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();
alert("接続が完了しました");
}
function game (timestamp) {
if (start == undefined) {
start = timestamp;
previous = timestamp;
}
let dt = (timestamp - previous) / 1000;
previous = timestamp;
clearCanvas(canvas, ctx);
drawBack(canvas, ctx);
ball.update(accelX, accelY, dt);
ball.drawCircle();
animeID = requestAnimationFrame(game);
}
async function gameStart() {
ball.SpeedReset();
ball.setPoint(30);
accelX = accelY = 0;
char_accel.addEventListener('characteristicvaluechanged', onAccelerationChanged);
start = undefined;
if (animeID != undefined) {
cancelAnimationFrame(animeID);
}
animeID = requestAnimationFrame(game);
}
function onAccelerationChanged(event) {
accelX = event.target.value.getInt16(0, true) / 1000 * wt;
accelY = event.target.value.getInt16(2, true) / 1000 * wt;
}
function disconnect() {
cancelAnimationFrame(animeID);
if (!device || !device.gatt.connected){
return;
}
device.gatt.disconnect();
alert("切断しました。");
}
</script>
</body>
</html>
```
### 結果
microbitを傾けると、ボールが移動するプログラムを作成することができた
加速度を用いて図形を動かすことができたので、次はゲーム性のあるプログラムの作成に挑戦したい