---
# System prepended metadata

title: '**ゼミナールB**'

---

# **ゼミナール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を傾けると、ボールが移動するプログラムを作成することができた
加速度を用いて図形を動かすことができたので、次はゲーム性のあるプログラムの作成に挑戦したい