この項目ではHSPの制御構文を勉強していきます。
1. 条件分岐(1)
条件分岐とはいわゆるif文の事です。まずは、C言語と同じ構文の条件分岐についてです。
if (条件式) {
// 真の時の処理
} else {
// 偽の時の処理
}
上のような構文が使えます。C言語と同じですね。条件式も基本的にはC言語と同じなのですが、少しだけ違うところがあります。それは、「=」の演算です。HSPでは条件式では、比較しか行いません。したがって、
というように書いてもC言語のような代入は行われず、比較だけが行われます。
ポイント:if文はC言語と同じ。
2. 条件分岐(2)
さて、先程も話した条件分岐ですが、別の条件比較の構文も解説しておきます。
if (条件式) : /*真の時の処理*/ : else : /*偽の時の処理*/
このような、構文も存在します。ただし、それぞれの処理が長くなる時にこの書き方をすると非常に見難くなってしまうので、狙いを定めてここぞという時に使いましょう。
そして、この構文を用いることでelse if文を記述できます。
if (条件式1) {
/*1が真の時の処理*/
} else : if(条件式2) {
/*2真の時の処理*/
} else {
/*全て偽の時の処理*/
}
3. for文
続いてはfor文です。C言語ではよく使われますが、HSPではあまり使われません。
for 変数名,初期,終値,増分
// 処理
next
このような構文になっています。実際に使うときは次のように使います。
// for文の例
for a,5,0,-1
mes "a = " + a
next
for文では最終値は実行されないので注意が必要です。そして、この構文の最大の特徴はマクロ処理である点です。後述の「while文」も同様にマクロ処理となっています。マクロ処理は後述のrepeat命令よりは高速に処理が可能です。しかし、マクロ処理であるがために、通常命令のbreakなどではループを抜けることが出来ません。そこで、for文、while文、do~until文のために用意されているのが_break、_continueマクロです。これを使うと次のようなプログラムも可能になります。
// for文の例
for a,0,100,1
mes "a = " + a
if (a > 5) : _break
next
例えばこの例で、間違えてbreakと書くと構文エラーとなるので注意してください。
ポイント:「for 変数名,初期,終値,増分~next」で繰り返しのマクロ。_breakと_continueはアンダーバーを忘れずに!
4. while
続いてはwhileの構文になります。HSPではwhile文よりもrepeat文のほうが使われることが多い気がします。
C言語とほぼ同じですね。そして、このwhileは条件式の演算が最初に行われるので、一度も処理が行われない可能性があることもC言語と同じです。そこで、必ず一度は処理をしてほしい時はdo~until文を使います。予約語がwhile文と異なるので注意してください。
実際に使ってみると次のようになります。
// whileの例
a = 0
while a < 5
mes "a = " + a
a++
wend
// do - untilの例
a = 0
do
mes "a = " + a
a++
until a >= 5
whileやdo~untilは先程もちらっと述べましたが、マクロ処理です。そのため、_breakマクロと_continueマクロを使います。
ポイント:「while 条件式 ~ wend」または「do ~ until 条件式」で繰り返しのマクロ。
5. repeat
繰り返し命令のなかでく最も良く使われる命令です。HSPでもrepeatによる繰り返しを推奨しています。repeat命令の構文は次のとおりです。
回数の部分を省略することで、無限ループになります。次は、実際に使ってみた例です。
// repeatの例
repeat 5
mes "cnt = " + cnt
loop
では、ここの例にある「cnt」ってなんでしょうか?実行してみればわかると思いますが、cntには繰り返しの回数が代入されています。このcntという変数はHSPのシステムが提供し管理している変数です。このようにシステムによって準備されている変数のことをシステム変数といいます。このシステム変数はcntのほかにstatやerr、refstrなど様々なものが用意されています。
少し話が脱線してしまいました。repeatの説明に戻ります。repeat~loopから抜ける場合はbreak命令を使い、ループの最初に戻る場合はcontinueを使います。
// repeatでのcontinue, breakの例
repeat
if cnt == 3 : continue
if cnt == 5 : break
mes "cnt = " + cnt
loop
ここまでの説明でrepeat命令がよく使われる理由はわかっていただけたのではないでしょうか。システム変数cntが強力な動作をしてくれること、repeatの構文が簡単なことがよく使われる理由だと思います。
ポイント:「repeat 回数 ~ loop」で繰り返し命令。システム変数cntで繰り返しの回数が分かる
6. end
この命令が呼び出されると、ウィンドウを閉じてプログラムを終了します。また、ロックしていいたリソースなどもすべて開放してくれる便利な命令です。ただし、リソースの開放等はこの命令に任せるのではなく、ぞれぞれの終了命令を呼び出すべきです。
// end命令の例
repeat
if cnt == 3 : continue
if cnt == 5 : break
mes "cnt = " + cnt
loop
end
このように、end命令が呼び出された瞬間にウィンドウを閉じてプログラムを終了します。
ポイント:終了の命令 end
7. stop
この命令が呼び出されると、そこでプログラムを停止させます。それだけですが、覚えて置かなければならない命令になります。
ポイント:停止の命令 stop
8. wait
この命令はその名の通り、待つ命令です。waitのあとに指定した時間だけプログラムを停止させます。指定する時間は10ms単位なので注意が必要です。
// wait命令の例
repeat 5
mes "wait 1[s]"
wait 100
loop
end
ポイント:10ms単位で指定する待つ命令wait
9. await
この命令も待つ命令なのですが、waitとは少しだけ挙動が異なります。waitはプログラムの状態に関係なく一定時間待つ命令です。これに対して、await命令は前回のwaitまたはawaitからの秒数を待ちます。次のプログラムを見てください。
// wait命令での例
repeat 5
mes "wait 1[s]"
repeat 10000
a = cnt
repeat 10000
b = a*cnt
loop
loop
wait 100
loop
このプログラムでは10000の2乗回の計算をしています。このようなプログラムでは計算の時間が無視できないぐらいに長くなります。それでも、1ループにかかる時間を固定したい場面は良くあります(例えば、シューティングゲームなど)。そんな時にwait命令を使って、呑気に1秒待ってもらっては困るわけです。このようなときにawait命令を使うことで、1ループの時間の最小値を固定することができるようになります。
// await命令での例
repeat 5
mes "wait 1[s]"
repeat 10000
a = cnt
repeat 10000
b = a*cnt
loop
loop
await 1000
loop
注意が必要な点は、await命令に指定する時間が1ms単位である点です。waitは10ms単位なので注意してください。
ポイント:前回のwaitまたはawaitからの待ち時間をしていするawait命令。時間の単位は1ms。
10. ラベル
プログラム上での位置を示すためにラベルというものが存在します。ラベルは*(アスタリスク)から始まる59文字(半角)以下の文字列です。プログラムの実行中にラベルを通過しても何も起こりませんが、後述のgoto命令やgosub命令を使うことで動作が変わってきます。
*label //これがラベル
mes "Wait."
mes "Wait."
ラベルは慣習的に行頭に書きます。というより、インデント的に行頭に書けない位置にラベルを置くべきではないという考え方だと思います。
11. goto
この命令は引数で指定したラベルにジャンプします。
// goto命令の例
*main
mes "wait 1[s]"
wait 100
goto *main
gotoはどこのラベルへでもジャンプすることが出来ます。それゆえgotoを乱用すると非常に読みにくいプログラムになってしまいます。便利なgoto命令ですが、使用するときは使う場面をよく考えて使う必要があります。
ポイント:goto命令で任意のラベルにジャンプする。乱用は厳禁。
12. gosub
ラベルにサブルーチンとしてジャンプします。基本的な動作はgotoと同じですが、ジャンプ先にreturnを置くことが出来ます。ジャンプ先でreturnが呼び出されるとジャンプ元に戻ります。
// gosub命令の例
*main
gosub *s_label1
gosub *s_label2
mes "wait 1[s]"
wait 100
goto *main
*s_label1
mes "ここはサブルーチン1"
return
*s_label2
mes "ここはサブルーチン2"
return
returnを書き忘れると次にreturnが出てくるところまでプログラムが進んでしまいます。上の例で11行目のreturnをコメントアウトしてみてください。実行するとサブルーチン1を呼び出したのに、returnを書き忘れたためにサブルーチン2の部分まで実行されてしまいます。そこで、例のようにサブルーチン用のラベルに「s_」をつけることで、ミスをいくらか減らせます。
ポイント:gosub命令で任意のラベルにサブルーチンとしてジャンプする。returnを忘れないように。
13. waitなしのループに注意
さいごに、次のプログラムを実行してみます(みなさんは実行しないでください)。
// 良くないループの例(実行しないで!)
*main
a++
mes "a = " + a
goto *main
実行すると下の図のようになって、「応答なし」となってしまいます。
これを解決するにはループの中にwait命令を入れる必要があります。wait命令やawait命令で行っていることは時間の消費だけではありません。プログラムがWindowsというOSと対話をする時間でもあるのです。そのため、待つ命令が全く入っていないとOSがしてくれている処理が進められなくなって、応答なしとなってしまいます。この命令は少しでもどこかに入っていれば良いので、先ほどのプログラムは次のように書き換えられます。
// 改良した例
*main
a++
mes "a = " + a
await 1
goto *main
また、全体のループで少し待てば良いので、ループのネストが深い場合でも次のように1箇所だけwaitを入れれば良いことになります。
// ネストの深いループの例
num = 2
*main
repeat 10
repeat 10
num = (num * 2 - 1)\113
loop
loop
mes
"sin(" + num
+ ") = " + sin(num
)
await 1
goto *main
ポイント:無限ループには必ず待つ命令を入れる!
最終更新:2016年04月16日 12:32