フルカラーLEDのWS2812Bを10個使い、LEDの光をボールに見立てたスカッシュゲームです。
今回は、IchigoJam R(IchigoJam&ESPJUICE)を使ってプログラムしました。
フルカラーLEDは、IchigoJam&ESPJUCEのオプション教材である、カラーLEDユニットを使用しました。
一番手前のLEDが光った時に、IchigoJam のタクトスイッチ(SW2)を押して打ち返します。
空振りなどで打ち損じたときはゲームオーバーです。

フルカラーLEDの使い方は、テキスト「LEDでナナイロづくり」や「ナナイロイルミネーション」を参考にしてください。
このスカッシュゲームを元に作成した、「フルカラーLEDルーレット」もあります。
‘simpleSQUASH フルカラーLEDスカッシュ
30 CLV:W=20:Q=10
100 @MAIN
110 [ABS(P)*3]=0
130 P=P+1
140 IF P==Q P=2-Q:BEEP30
150 [ABS(P)*3]=50
160 WS.LED Q
180 IF P!=0 WAIT W:GOTO@MAIN
190 IF BTN()==1 GOTO@GAMEOVER
210 CLT
220 @HIT
230 IF BTN()==1 BEEP5:GOTO@MAIN
240 IF TICK()<W GOTO@HIT
250 @GAMEOVER
260 BEEP100,120
■変数の説明■
W ボール移動時間(ボールスピード)
ボールが動く際の待ち時間(WAIT値)を指定します。
値を大きくするとボールスピードが遅くなり、小さくすると早くなります。
このスカッシュプログラムでは、W=20ですので、20/60秒≒約0.3秒毎 にボールを動かします。
Q フルカラーLEDの個数
WS2812Bの使用個数を指定します。
定数*1として、WS.LED命令のパラメータや、打球位置、壁判定などに使用します。
IchigoJam配列の制限があるので30個以内で使ってください。
P 現在のボール位置※2
ボールの位置が入り、この場所のLEDが点灯します。
一番手前のLEDがボールを打つ位置で、値は0です。
ボールを跳ね返す奥の壁の位置は +9( -9 )です。
[] WS.LED用GRB値
配列は全てWS.LED命令で使用され、フルカラーLEDを点灯するためのGRB値が入ります。
配列[0][1][2]には、フルカラーLED1番目のG・R・Bの輝度(0~255の範囲)が入り、
[3][4][5]には2番目、[6][7][8]には3番目となるようように指定していきます。
WS.LEDの使い方は、キラキラIoTプログラミングワークショップ WS.LEDサンプル集
を参照してください。
※1 定数として使う場合には、プログラム実行中に値を変えないようにします。
定数としておくと、LED個数が違うWS2812Bを取り付けても、30行目の初期化のところの一箇所を修正するだけで済みます。
■プログラムの説明■
30行目 CLV:W=20:Q=10
使用する変数の初期化をします。
▪️変数の説明▪️を参照してください
100行目 @MAIN
ボールを打って、壁から戻ってくるまでを繰り返す、メイン処理です。
110行目 [ABS(P)*3]=0
前のボール位置※2を、消灯に設定します。
130行目 P=P+1
ボール位置を移動※2します。
140 IF P==Q P=2-Q:BEEP30
ボール位置が端(壁)を越えたら、方向を反転※2します。
今回のスカッシュプログラムでは、変数Pが+10のときに、-8に書き換えます。
BEEP30で音を鳴らして、壁から跳ね返った効果を出します。
150行目 [ABS(P)*3]=50
新しいボール位置※2に、緑色(輝度50)を設定します。
160行目 WS.LED Q
フルカラーLEDを、配列に設定した値で点灯します。
この行を実行すると、フルカラーLEDを点灯する毎にボールが動いて見えます。
180行目 IF P!=0 WAIT W:GOTO@MAIN
ボール位置が一番手前の打球位置でなければ(変数Pが0以外ならば)、
@MAIN処理に戻りボール移動※2を続けます。
ボール位置が打球位置にあるならば(変数Pが0ならば)、次の行の処理に進みます。
190行目 IF BTN()==1 GOTO@GAMEOVER
不正対策の処理です。
ボールが打球位置に来る前からタクトスイッチを押し続けていれば、
空振りにして、@GAMEOVER 処理に行きます。
210行目 CLT
220行目 @HIT
230行目 IF BTN()==1※3 BEEP 5:GOTO@MAIN
240行目 IF TICK()<W GOTO@HIT
打球判定の処理※3を行います。
240行目の制限時間内(ボールスピード時間)に、230行目でタクトスイッチが押されれば、
打ち返し成功となり、高いBEEP音を鳴らして@MAIN処理に戻り、ボール移動を続けます。
打ち損じたときは、次の行に進みます。
250行目 @GAMEOVER
260行目 BEEP 100,120
ゲームオーバーの処理を行います。
BEEP音を低く長く鳴らします。
この行の後にはプログラムがないので、終了してコマンドプロンプトで終わります。
※2 ボール移動は変数Pの正負を利用して動かします。
Pの値は、1,2,3,4,5,6,7,8,9,-8,-7,-6,-5,-4,-3,-2,-1,0 のように変化していき、
値が正数ならボールが壁に近づく動きとなり、負数なら壁から帰ってくる動きとなります。
Pの値を配列の添え字にするときは、ABS(P)のように絶対値で使用します。
次のプログラムを追加して実行すると、ボールの動きとPの値の変化がわかります。
155 PRINT P
下図も参考にしてください。

※3 220〜240行目の打球判定処理は、1行にまとめることができます。
220 IF BTN() BEEP5:GOTO@MAIN:ELSE IF TICK()<W CONT
BTN命令は、ボタンが押されていると1、押されていなければ0を返します。
IchigoJam BASIC では、条件式の結果が0以外は真、0は偽として扱われます。
他のIchigoJam説明では「1か0」と書かれている場合がありますが、実際には、-1でも1000も真となります。
IF BTN() THEN a ELSE b は、
IF BTN()==1 THEN a ELSE b または、
IF BTN()!=0 THEN a ELSE b と同じ結果を実行します。
いずれも、ボタンが押されていれば a、押されていなければ b、を実行します。
CONT命令は、中断した行を再実行するものですが、実際には同じ行を繰り返します。
220 ….. IF TICK()<W CONT は、
220 ….. IF TICK()<W FOTO220 と同じ結果になります。
■応用と改良■
1.ボールの色を好きな色にする
・140行目でボールの色を決めています。
緑、赤、青の輝度の組み合わせで色が決まり、値は0から255の範囲です。
150 [ABS(P)*3]=緑の輝度(G)
151 [ABS(P)*3+1]=赤の輝度(R)
152 [ABS(P)*3+2]=青の輝度(B)
・LET命令を使うと、LEDひとつ分の色設定をまとめてすることもできます。
緑なら、
150 LET[ABS(P)*3],50,0,0
赤なら、
150 LET[ABS(P)*3],0,50,0
マゼンダなら、
150 LET[ABS(P)*3],0,50,50
明るい青なら、
150 LET[ABS(P)*3],0,100,0
眩しいホワイトなら、
150 LET[ABS(P)*3],255,255,255
のようにプログラムします。
・色設定サブルーチンの仕組みを利用すると、虹色のボールにすることもできます。
150 C=C+1:LET[ABS(P)*3],C&1*50,C>>1&1*50,C>>2&1*50:IFC>6C=0
いずれの方法も、110行目でボールを全消灯しておく必要があります。
110 LET[ABS(P)*3],0,0,0
2.再ゲームを可能にする
ゲームオーバーの後に、再ゲームできるようにします。
つぎの追加プログラムは、ボタンが押されるまで、フルカラーLEDの全点滅を繰り返します。
260 BEEP100,120:WAIT120
261 IF [1] [1]=0 ELSE [1]=100
262 WS.LED1,Q
263 IF BTN() RUN
264 WAIT30:GOTO261
3.ボールの残像を残す
配列の値を0にすることでLEDの光を消灯しますが、徐々に小さくしていくことで、
ボールの動きに残像を残すことができます。
具体的には、すべての配列の値(輝度)を、2で割っていくのです。
次のようにプログラムを変更します。
110 FOR J=0 TO Q*3:[J]=[J]/2:NEXT
ボールは最初に緑色の輝度50で点灯しますので、
50,25,12,6,3,2,1,0,0,・・・・
というように、輝度を落としていきます。
このようになると、ボールの後ろのLED3~4個に残像が残るようになります。
ほんとうは、1.3など、2よりも小さい小数で割れば、長い残像になるのですが、IchigoJamでは小数が使えません。
そこで、輝度[J]を10倍して割ることで、さらに残像を長く残すようにします。
110 FOR J=0 TO Q*3:[J]=[J]*10/11:NEXT
なお、IchigoJam R以外は処理速度が遅いため、
FOR命令にSTEPオプションを追加して、FOR~NEXT回数を少なくする工夫も必要です。
110 FOR J=0 TO Q*3 STEP3:[J]=[J]/2:NEXT
4. 壁と打球位置を別の色で点灯する
例えば壁を赤、打球位置を青にするには、次のようなプログラムを加えます。
120 LET[(Q-1)*3],0,50,0:LET[0],0,0,50
5.打ち返すごとに得点を入れる&最高得点を表示する
得点用の変数Tなどを追加し、打ち返すごとに+10ずつ足していくようにします。
ゲームオーバー処理で最高得点を表示させ、ゲームをより楽しくすることもできます。
打ち返し成功は230行目で行っているので、ここに得点追加の処理を入れます。
230 IF BTN() BEEP5:L=L+10:GOTO@MAIN
6.ボールをスピードアップしていく
ボールを打ち返すたびに、変数Wの値を-1ずつ減らして難易度をあげるようにします。
230 IF BTN() BEEP5:W=W-1:GOTO@MAIN
7.壁が迫るようにする
ボールを打ち返すたびに、壁が迫るように位置を変えます。
変数QにLED個数が設定されていることを利用して、壁で打ち返すごとにQの値を減らすとよいでしょう。
230 IF BTN() BEEP5:Q=Q-1:GOTO@MAIN
この修正だけだと壁が見えませんので、壁に色を付けたり、壁と打球位置の制限をつけたりと、
他にも改良修正が必要になる場合があります。
8.2人対戦にする
壁側にもう一人のプレイヤー用打球位置を設定して、キーボードのスペースキーなどで打ち返すように改良します。
壁判定の後に2人目の打球処理を追加するとよいでしょう。
IF命令やループ命令が必要になるので、サブルーチンにすると作りやすいです。
対戦ゲームでは、得点や再ゲームなどの処理にも注意します。
スカッシュプログラムの応用例1.~7.は、こちらの記事を参考にしてください。

この教材は「Creative Commons — CC BY-SA 4.0」の下に提供されています。
