第7回 逆引き:プログラムを分解解説 「4.自機の移動」
|
|
7−4 自機の移動
さて、次は自機の表示と移動です。 自機(1007)は15x15ピクセルの画像ですが、スクロールエリアの高さは120ピクセルでしたので、ちょうど、120÷15=8段分の表示が可能になります。 ピクセル単位で移動させることも出来ますが、今回のゲームでは「段」単位で移動させています。 つまり、自機は 15ピクセル単位で移動しているわけですが、この表示用の座標に使っている、Yiというグローバル変数には、その段の値が代入されています。 段の値Yi=0〜7の8段階です。そして、実際の表示は、この段数に15を掛ければピクセル寸法になりますので、
DrawBitmap 1007,5,Yi*15+25
としています。スクロールエリアの左端の座標が(5,25)ですので、横方向は 5、縦方向は Yi*15+25 ですね。Yi=0,1,2,3,4,5,・・・ですから、Yi*15+25=25,40,55,70,85,・・・となります。これで、変数Yiの値を変化させれば自機が上下に移動するようになります。 ただし、移動時に前の位置に描いた自機を消す必要はありません。スクロール画面が全てを消してくれますので、楽チンですね。 次に自機の移動ですが、今回は「ボタンを押している時は上昇、そうでない時は下降」するように設定しました。 まずは、簡単な下降から見ていきましょう。 下降させるには、Yiを1加えれば良いわけですから、
Yi=Yi+1
ですね。これが、Do〜Loopの中に入っていますので、1スクロール毎に1つずつ下に下がります。一方、上昇は、何かのキーが押された時に処理します。なので、まずは、ループから抜け出す必要がありますねが、これは、Do〜Loopの条件に、SysEventAvailable()を使えば良いですね。 だたし、常にループが回っていますので、SysEventAvailable()を使って抜け出す時点は、すでに、下降の処理が行われた後ですね。 ![]() 図で表すと分かりやすいですが、NS Basicでは、Doの方にしか条件がつけられませんので、イベントの判定が下降処理の後になります。 したがって、上昇ルーチンに入る時には、既に下降しちゃってますので、変数Yiは+1されています。そのため、上昇したい場合は−1ではなく−2をしなければなりません。
[After]
Do Until SysEventAvailable()=1
Yi=Yi+1
Loop
[events]
Dim theKey as String
If GetEventType()=nsbKeyOrButton Then
theKey=GetKey()
If theKey=&h1 Or theKey=&h2 Or theKey=&h3 Or theKey=&h4 Then
SetEventHandled
Yi=Yi-2
Redraw
End If
End If
とまぁ、こうすればよさそうです。これだと、4つのハードキーの何れかを押すと上昇しますね。 ちなみに、それ以外のキーを使うと、SetEventHandledコマンドを処理しませんので、そのキーに割り当てられた処理が行われます。 しかし、この時点で機能を持ったキーと言えば[ホーム]と[電源]くらいしか残っていませんね。それらのキーは、押されると、割り当てられた機能が働くことになりますが、それ以外(と言っても、ハードキーの上下くらいですが)の場合、処理すべき処理もなく、また、Redrawコマンドも実行しませんので、結果的に「ゲームの一時停止」になります。 そして、操縦用の4つのキーの何れかを押すと、ちゃんと再開します。 さて、NS BasicのDo〜Loopでは、Do側にしか条件が置けないため、更に問題を発生します。 先ほどの図に戻ってみますと、Do〜Loop内でキー入力があれば、イベントが発生してループを抜けて、上昇処理をして、再びDo〜Loopに戻ってきますね。 しかし、キーを押しっぱなしにしている状態ではどうでしょうか? ![]() キーを押しっぱなしにしていると、上昇処理が終わった時点で、すぐにSysEventAvailable()が 1になってしまいます。 したがって、Doループの入り口に差し掛かった時点で、すでに条件が成立し、また上昇処理を行ってしまいます。そのため、押しっぱなしの状態では、下降処理どころか、画面の処理も更新されなくなってしまいます。 そこで、そのような状態を防止するため、Flgというグローバル変数を用意しました。 Flgは、上昇処理が行われた直後に 1 となり、一度Do〜Loopが処理された時に 0 になります。そのため、Doの条件にFlgの値をチェックするようにすれば、押しっぱなし対策を取ることが可能です。
[After]
Do Until (SysEventAvailable()=1 And Flg=1)
Yi=Yi+1
Flg=1
Loop
[events]
Flg=0
これで、Flg=0の時は、キーが押されていても、ループから抜けることはありませんので、必ず、画面更新と下降処理が行われます。また、実際に実行してみて分かったのですが、このまま実行すると、上昇と下降の処理で著しく速度が変わってしまいましたので、
[After]
If Flg=1 Then
Delay 0.15
End If
という時間稼ぎをDo〜Loopの中にいれておきました。この値は、VISOR Platinumでの値ですので、他の機種では適当に変化させると良いでしょう。(とはいえ、0.15秒が正確かどうかは意外と怪しいですので、この値のままでも問題はないと思われます。) さて、キーの押しっぱなしに対応するために、Flgなどという変数を持ち出してきましたが、これらはすべてイベントの判定を先頭で行っているから発生する問題でしたね。したがって、このイベント判定を途中や最後に行えば、もう少しスッキリするのではないでしょうか?
[After]
Do
If SysEventAvailable()=1 Then
Delay 0.15
Exit Do
else
Yi=Yi+1
End if
Loop
例えば、途中でイベントを判定するこの方法であれば、変数Flgは不要になるのは明らかでしょう。BASICプログラムでは、1つの問題を回避することが比較的容易で、それは、他の部分に大きな影響を与えることなく回避することが可能です。 例えば、先ほどの例では、変数Flgを用意して、問題を回避しましたが、その他の部分にはあまり影響を与えていませんね。 ここが、BASICの良いところでもあり、悪いところでもあります。問題解決が容易なのは良いですが、気がつくと「なんだ、この無駄な処理は?」という部分が多く出てきます。 何も考えずにプログラムを作れるBASIC、こんな欠点があることを覚えておきましょう。
|
|
第7回 逆引き:プログラムを分解解説 「4.自機の移動」
|