LEDアレイへの表示とボタンの操作については完璧に理解できているはずです。集大成として、みんな大好き、シューティングゲームを作ります。
全体の構造を作る
ゲームの骨格となる全体の構造を作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include <Adafruit_Microbit.h> Adafruit_Microbit_Matrix microbit; unsigned long time = 0; //この配列要素を1にするとLEDが点灯する。 char LED[5][5] = { {0,0,0,0,0}, {0,1,1,1,0}, {0,1,0,1,0}, {0,1,1,1,0}, {0,0,0,0,0}}; void setup() { //シリアル通信を開始 Serial.begin(9600); while (!Serial); //Adafruitライブラリを初期化 microbit.begin(); } void updateDisplay() { for(int y=0;y<5;y++){ for(int x=0;x<5;x++){ microbit.drawPixel(x,y,LED[y][x]); } } } void loop(){ //プログラム開始時からの経過時間(ミリ秒) time = millis(); Serial.print("Time: "); Serial.println(time); //現在の状態を表示 updateDisplay(); delay(50); } |
LEDアレイの表示には Adafruit のライブラリを使いますが、直接その関数をコールするのは面倒なので、表示内容を制御するのに LED[5][5] という配列を使うことにしました。ゲームのメインルーチンではこの配列を操作して、updateDisplay() で表示します。変数 time にはプログラムが開始されてからの経過時間をミリ秒単位で持ちます。シリアル通信でデバッグするような状況もあると思われるので設定しておきます。メインの loop() は50ミリ秒周期で回して、そのたびに表示内容を更新する仕組みにしました。
課題1
LED[5][5] の初期値として入れてある四角が表示されることを確認してください。シリアルモニタを起動して、上記のプログラムで書き出している時間の経過を確認してください。プログラム全体の動作で分からないことがあれば Serial.print() または Serial.println() を使って確認してください。
敵を動かす
LEDの1行目(y=0の行)にLEDをひとつ点灯して左右に移動させましょう。これが「敵」です。さきほどのプログラムを次のように改変してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
(中略) //この配列要素を1にするとLEDが点灯する。初期値はすべてオフ。 char LED[5][5] ={ {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}}; int target_position = 0; //敵の場所(0~4) int target_direction = 1; //敵の移動方向(1なら右、-1なら左) unsigned long lasttime=-1; //最後に移動した時刻を覚えておく void showTarget() { if(time-lasttime<300) return; //300ミリ秒経過するまで何もしない lasttime+=300; LED[0][target_position]=0; //いま光っている場所を消す target_position += target_direction; //場所をひとつ移動 //端に到達したら向きを変える if(target_position==0){ target_direction = 1; }else if(4==target_position){ target_direction = -1; } LED[0][target_position]=1; //新しい場所を点灯 } void setup() { (中略) void loop(){ (中略) showTarget(); //現在の状態を表示 updateDisplay(); delay(50); } |
敵(つまり1行目で光っているLED)の場所と移動方向を覚えるための変数を定義します。メインの loop() の動作周期で移動させるのは速すぎるので、300ミリ秒毎に移動させることにしました。その制御に lasttime という変数を使っています。この関数 showTarget() をメイン loop() から呼ぶことを忘れないでください。
自分の位置を移動して、表示する
自分の位置(自分の飛行機、宇宙船 etc.)をLEDの5行目(y=4の行)にLEDをひとつ点灯して示し、Aボタン・Bボタンで左右に移動させます。これは演習6で作りましたので(回答例を参照)、必要なソースコードをいま作っているプログラムにコピペして合体させるだけです。プログラミングの練習のため、自分でやってみてください。
演習6ではLEDをオンするために loop() の中で
1 2 3 |
microbit.drawPixel(my_position, y, LED_ON); delay(100); microbit.drawPixel(my_position, y, LED_OFF); |
のように書きましたが、今回は配列 LED[5][5] を操作してLEDをオン・オフしますので、次のようにしましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
(中略) int old_position = 2; void showMyPosition() { LED[4][old_position] = 0; LED[4][my_position] = 1; old_position = my_position; } void loop(){ (中略) showTarget(); showMyPosition(); //現在の状態を表示 updateDisplay(); delay(50); } |
showMyPosition() は自分の位置のLEDを光らせる関数です。これを loop() の中からコールします。
課題2
ここまでできれば、LEDアレイの上部に敵機が左右に動いて、最下段には自機がA/Bボタンでコントロールできているはずです。もしできてなかったらデバッグしてください。
弾を撃つ
AボタンとBボタンが同時に押されたら弾を発射しましょう。
1 2 3 4 5 6 7 |
void shoot() { for(int y=3;0<=y;y--){ microbit.drawPixel(my_position,y,1); delay(100); microbit.drawPixel(my_position,y,0); } } |
弾を撃つ関数です。my_positionから上方向に順にLEDを光らせます。光らせるタイミングはメインの loop() とは独立しているので LED[5][5] を操作するのではなく microbit.drawPixel() を直接コールしています。
AボタンとBボタンが同時押しは loop() の中でこのように検出できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
if (button_A && button_B) { button_A = 0; button_B = 0; // 3ms待ってボタンAが立ち下がってなければチャタリングと判断 delay(3); if (digitalRead(PIN_BUTTON_A) == HIGH || digitalRead(PIN_BUTTON_B) == HIGH) { Serial.println("CHATTERING!"); return; } shoot(); Serial.println("SHOOT!"); } |
課題3
以上のソースコードをまとめれば、シューティングゲームの基本部分は完成です。もし動作がおかしければデバッグして修正してください。
「とりあえず完成バージョン」はこちら
課題4
「とりあえず完成バージョン」を元にして、自分のゲームを作ってください。例えば、敵の動きがだんだん早くなる、敵が下に降りてくる、弾が命中したら火花を表示する、等々。
コメント