Arduboyで弾幕的なものを その2
sin,cos関数は重かろうということで、テーブルから求めるようにしてみた。
Arduboyの解像度だと、一周64方向もあれば十分かな?
まずは、Pythonでsinテーブル(64方向分)を作成。
import math for i in range(64): v = math.sin(i / 64 * 2 * math.pi) print(str(v) + ',')
sinからcosを求める変形公式があります。(数学Iで習うようです)
sin(90 + θ) = cosθ
つまり、sinテーブルがあれば、cosは求められるということですね。
今回は一周を64方向に決めたので、90°は16ということになり、
sinテーブルを16ずらすと、cosが求まります。
float getCos(int16_t angle) { return getSin(16 + angle); }
#include <Arduboy2.h> Arduboy2 arduboy; #define BOSS_SHOT 10 typedef struct CharaData { float x, y; float vx, vy; int life; }; CharaData boss; CharaData bossShot[BOSS_SHOT]; uint16_t counter; int16_t angle; // 64方向 const float sinTbl[] PROGMEM = { 0.0, 0.0980171403295606, 0.19509032201612825, 0.29028467725446233, 0.3826834323650898, 0.47139673682599764, 0.5555702330196022, 0.6343932841636455, 0.7071067811865475, 0.7730104533627369, 0.8314696123025451, 0.8819212643483549, 0.9238795325112867, 0.9569403357322089, 0.9807852804032304, 0.9951847266721968, 1.0, 0.9951847266721969, 0.9807852804032304, 0.9569403357322089, 0.9238795325112867, 0.881921264348355, 0.8314696123025455, 0.7730104533627371, 0.7071067811865476, 0.6343932841636455, 0.5555702330196022, 0.4713967368259978, 0.38268343236508984, 0.29028467725446233, 0.19509032201612858, 0.09801714032956084, 1.2246467991473532e-16, -0.09801714032956059, -0.19509032201612836, -0.29028467725446216, -0.38268343236508967, -0.47139673682599764, -0.555570233019602, -0.6343932841636453, -0.7071067811865475, -0.7730104533627367, -0.8314696123025452, -0.8819212643483549, -0.9238795325112865, -0.9569403357322088, -0.9807852804032303, -0.9951847266721969, -1.0, -0.9951847266721969, -0.9807852804032304, -0.9569403357322089, -0.9238795325112866, -0.881921264348355, -0.8314696123025456, -0.7730104533627369, -0.7071067811865477, -0.6343932841636459, -0.5555702330196022, -0.4713967368259979, -0.3826834323650904, -0.29028467725446244, -0.19509032201612872, -0.09801714032956052, }; float getSin(int16_t angle) { int16_t n = angle % 64; return pgm_read_float(sinTbl + n); } float getCos(int16_t angle) { return getSin(16 + angle); } void setup() { arduboy.begin(); arduboy.setFrameRate(60); arduboy.clear(); // ボス(三角形)を画面中央に表示する boss.x = 128 / 2; boss.y = 64 / 2; } void loop() { if (!arduboy.nextFrame()) return; arduboy.pollButtons(); arduboy.clear(); // ボス(三角形) arduboy.drawTriangle(boss.x, boss.y - 8.f, boss.x - 8.f, boss.y + 8.f, boss.x + 8.f, boss.y + 8.f); // 弾の作成 if (++counter % 10 == 0) { for (int8_t i = 0; i < BOSS_SHOT; i++) { CharaData *p = &bossShot[i]; if (p->life == 0) { // 弾を使用中にする p->life = 1; // 弾の初期位置をボスの中央にする p->x = boss.x; p->y = boss.y + 2.f; ++angle; // 弾の移動方向を求める p->vx = getCos(angle); p->vy = getSin(angle); break; } } } // 弾の表示 for (int16_t i = 0; i < BOSS_SHOT; i++) { CharaData *p = &bossShot[i]; if (p->life > 0) { // 弾の移動 p->x += p->vx; p->y += p->vy; // 画面外の弾を消す if (p->x < 0.f || 128.f < p->x || p->y < 0.f || 64.f < p->y) p->life = 0; arduboy.fillCircle(p->x, p->y, 2); } } arduboy.display(); }