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