SmileBASIC

SmileBASIC講座


今回は「制御」について紹介します。ここでいう制御というのは、プログラムの処理の流れを制御する機能のことです。今まで詳しく触れてこなかった「IF」や「FOR」などについても、今回はしっかり紹介します。

プログラムの処理

プログラムの処理には次の3種類があります。

(1)順次処理

順次処理とはプログラムを順番に実行していく処理のことです。

順次処理の流れを図にすると、こうなります。これは特に説明することがないので、次に進みます。

(2)分岐処理

分岐処理というのは、ある条件によって分岐する処理のことです。

分岐処理の流れを図にしたものがこちらです。
分岐処理は「IF」文で記述します。ここではIF文の代表的な書式を挙げてみました。 「条件」と書かれた部分には式が入ります。たとえば、「変数Aが5より大きいか?」を判定したい場合には「A>5」という式を記述します。
「THEN」の後には条件がYESだった場合の処理を記述します。「ELSE」を使うと、NOだった場合の処理を行うことができます。処理が複数行の場合には「ENDIF」を使います。 この図では分岐の行く先を「YES」「NO」で表現しています。正確には「YES」は値が0以外のことで、「NO」は値が0のことです。このあたりは詳しい話をすると、ややこしくなってしまうので後回しにします。

(3)繰り返し処理

繰り返し処理はその名のとおり、繰り返す処理のことです。繰り返しのことを「ループ」といいます。

繰り返し処理の1つが「FOR」文です。「FOR」文の処理の流れを図にしたものがこちらです。
数値型の変数を使って、その値を比較しながら処理を繰り返します。
処理の最後には必ず「NEXT」を記述します。

《FOR文の使い方1》

FOR文を使ったプログラムの例がこちらです。
変数「I」を使っています。初期値を0、終了値を9と設定しています。
ループの中にはPRINT文があり、変数の値を表示します。
ループを見やすくするため、PRINT命令の手前には空白を入れています。これを「字下げ」といいます。字下げは書き方の1つというだけなので、行わなくてもかまいません。

I=0
I=1
I=2
I=3
I=4
I=6
I=7
I=8
I=9

プログラムを実行した結果がこちらです。
表示された内容を見ると、処理が10回繰り返されたことが分かります。

変数の値はどのように変化したのでしょうか。それを図にしたものがこちらです。
ループ1周目では値は「0」です。ループを繰り返すごとに値は1つずつ増えていきます。
ループ10周目に達した時点で値は「9」になります。
ループ11周目に入ろうとする手前で値は「10」となり、ここでループを終了します。

《FOR文の使い方2》

FOR文は「STEP」と記述することによって加算値を指定することができます。
STEPを省略した場合の加算値は「1」です。
ここでは例として加算値を「0.5」としてみました。

I=0
I=0.5
I=1
I=1.5
I=2
I=2.5
I=3
I=3.5
I=4
I=4.5
I=5
I=5.5
I=5
I=6.5
I=7
I=7.5
I=8
I=8.5
I=9
OK

プログラムの実行結果がこちらです。
変更前は値が1ずつ増えていましたが、変更後は値が0.5ずつ増えています。
表示を見ると、処理が19回実行されたことが分かります。
加算値を半分にしたら、ループ回数は20回になるのではと思ってしまいますが、正解は19回です。

《FOR文の使い方3》

「STEP」の値をマイナスにすると、変数を減算るループもできます。
初期値を9、終了値を0としています。

I=9
I=8
I=7
I=6
I=5
I=4
I=3
I=2
I=1
I=0
OK

プログラムの実行結果がこちらです。
処理は10回繰り返されました。
表示を見ると、処理を繰り返すごとに値が減っていることが分かります。
以上のようにFOR文には、様々な機能があります。ぜひ使いこなしてみましょう。

《WHILEとREPEAT》

その他、繰り返し処理には「WHILE」文と「REPEAT」文があります。
WHILEとREPEATの処理の流れを図にしたものがこちらです。
両者の書式は似ていますが機能が次のように違います。

WHILEは継続する条件判定がループの前にあります(前判定)。条件がNOだった場合にループを終了します。
REPEATは終了する条件判定がループの後にあります(後判定)。条件がYESだった場合にループを終了します。

以上でプログラムの処理の紹介を終わります。
話をまとめると、プログラムの処理は「順次処理」と「分岐処理」と「繰り返し処理」の3種類ということです。
これを組み合わせると、プログラムを構造的に作ることができます。 構造的に作ったプログラムは丈夫になり、規模が大きくなっても複雑になりにくいというメリットがあります。

繰り返しデータを読み取る

《READ命令の使い方》
繰り返し処理の応用例としてREAD命令を紹介します。 READ命令はデータを読み出すことができるという命令です。READ命令はDATA文と組み合わせて使います。

READ命令を使った例がこちらのプログラムです。
READの後に格納したい変数名を記述します。ここでは「READ A$」として、文字列変数のA$に格納します。
DATA文には読み込む元のデータを記述します。 RESTORE命令はDATA文の読み取り開始位置を指定するための命令です。位置はラベル名で指定します。RESTOREを省略した場合には、最も少ない行番号にあるDATA文から読み取られます。

プログラムの実行結果がこちらです。
大きな文字が表示されました。

実行中の変数の中身を図にしたものがこちらです。
FOR文によってREAD命令が繰り返し実行されます。
READ命令によって、A$には1行ぶんのデータが格納されます。処理を9回繰り返すことで、9行分の文字列が表示されたわけです。
このように、READ命令は大量のデータを扱いたい場合に役立ちます。

タイミングを調節する

ゲームなどを作る場合、繰り返し処理の周期を一定に保つ必要があります。
そうした場合に使うのが「VSYNC」という命令です。
実際に例を挙げて紹介します。

《VSYNCの使い方1》

こちらがVSYNCを使ったプログラムです。
VSYNC 1」と記述することで、フレームを1枚更新するまで処理を待つことができます。フレームというのは更新する画面のことです。普段、皆さんが目にしているゲームは、ものすごい高速に画面を書き換えることで動いているように見えています。SmileBASICが動いているハードウェアは1秒間に60フレームを更新しています。
どれくらいのフレーム数を更新したかを確認するには、「MAINCNT」というシステム変数を読み取ることができます。システム変数とはSmileBASICのシステムに関わる変数のことです。MAINCNTにはソフトを起動してから更新したフレーム数の合計が格納されています。

ちなみに2行目の「WHILE 1」は無限にループするという意味です。GOTOを使っても同様の処理は可能ですが、WHILEならラベルを使わず、プログラムの見た目をすっきりさせることができます。

実行すると、画面に数値がものすごい勢いで表示されます。 文字の流れが速すぎて読めません。そこで、「STOP」を押してプログラムを停止させます。
表示を見ると、ループが1周するごとに値が1つずつ増えていることが分かります。 この値が1つ増えるタイミングで画面が書き換えられています。

《VSYNCの使い方2》


続いて、このようなプログラムを作ってみました。1秒間に60フレームを更新していることを確認するためのプログラムです。
ループの中でMAINCNT(フレームカウント数)を監視して、60フレームが更新されるごとにループの回数を表示します。


プログラムの実行すると、このような結果が表示されます。
画面に繰り返し「60」と表示されます。
これはいったいどういう意味でしょうか。

プログラム内で処理を実行されるタイミングを図にしたものがこちらです。
「VSYNC 1」を実行することによって、一つ前にVSYNC命令を実行してから1/60秒間、処理を待つことができます。処理時間は前後しても、VSYNC命令によって調節されます。この機能があれば、性能の違ったハードウェア(ニンテンドー3DS/Newニンテンドー3DS/Wii U)であっても同じ速度でプログラムを動かすことができます。
ただし、処理時間が1/60秒以上かかってしまった場合はVSYNC命令では調節できません。

ボタンの入力方法

ボタンの入力方法について紹介します。ボタンの処理はゲーム作りには欠かせません。

こちらがボタンを入力するプログラムです。
2行目にあるWHILE文は処理を繰り返すためのものです。ループの中にはVSYNC命令も忘れずに入れましょう。これによってループの周期を1/60秒に調節します。
BUTTON」がボタンの状態を読み取る関数です。関数の返す結果のことを「戻り値」といいます。
この場合、戻り値はBTという変数に格納されます。
BUTTON関数のあとに「()」というカッコが記述されていますが、この中には引数が入ります。引数というのは関数に与える値のことです。
BUTTON関数は引数に与えることで、たくさんの機能を使うことができます。ここではデフォルトのまま使うため、引数には何も入れていません。
4行目にある「BIN$」は数値を2進数の文字列に変換する関数です。

プログラムを実行してみた様子です。
大量の「0」が表示され続けます。ボタンの状態が2進数で表示されています。2進数というのは0か1だけで表現された数値のことです。
この状態でAボタンを押してみると、数値の右から5列目に「1」が表示されます。

BUTTON関数の戻り値は各ボタンに割り振られています。
Aボタンが押された場合の値を2進数で表現すると「&B10000」です。
先ほどのプログラムで数値の右から5列目の場所に「1」が表示されたというのはこのためです。

複数のボタンが同時押されていても管理できるようにするため2進数で処理しています。
ただし、「&B10000」という記述は、文字が多すぎます。そこで、SmileBASICには定数という機能があり、「#A」と記述すると「&B10000」と同じ値として扱うことができます。

岩を避けるゲーム

今まで紹介したテクニックを組み合わせて、ゲームを作ってみましょう。ひたすら岩を避けるというゲームです。

こちらが完成したプログラムです。

プログラムの3行目にあるREPEAT文が主体となる繰り返し処理です。これを「メインループ」といいます。
9行目にあるIF文ではAボタンが押されているかどうかを判定しています。

このプログラムでは「プレイヤー」と「岩」という2つのキャラクターを動かします。
キャラクターが同時に動いているように見せるには、2つの処理を少しずつ実行させるようにします。

処理の仕組みを図にすると、こうなります。
ループが1周する1/60秒の間にプレイヤーの処理、岩の処理、VSYNC処理を実行します。
短い時間の処理を積み重ねることで、同時に動いているように見せることができます。

プログラムの25行目にはプレイヤーと岩との衝突を判定する処理を行っています。
この処理を図にしたものがこちらです。
ABS関数を使ってX座標とY座標の差を求めて、一定の値より下回ると衝突したと判定しています。「ABS」とは絶対値を求める関数です。

プログラムを実行すると、このような画面になります。
水色のキャラクターがプレイヤーです。赤色のキャラクターが岩です。

岩は右側から左側に向かって移動します。
岩の移動速度はランダムです。
プレイヤーは岩に当たらないように避けないといけません。
Aボタンを押すとプレイヤーがジャンプします。

プレイヤーが岩に当たってしまうとゲームオーバーです。
タイミングよくジャンプして避けましょう。

このゲームは見た目が地味だったり、プレイヤーが左右に移動できなかったり、いろいろと不満な点があります。
改造の余地はいっぱいあります。
どのように改造したらいいかについても考えてみましょう。

今回のまとめ

今回紹介した命令と関数は次のとおりです。さらに深く知りたい場合には、ヘルプ機能や公式サイトにある「命令表」で調べてみましょう。

  • IF、THEN、ELSE、ENDIF
  • FOR、NEXT
  • WHILE、WEND
  • REPEAT、UNTIL
  • READ、DATA、RESTORE
  • VSYNC
  • BUTTON
  • BIN$
  • ABS
ページトップへ