第11回 何か作ってみよう「5.ムシムシ大行進」
|
|
11−5 ムシムシ大行進
さて、大まかな準備が揃ったところで、実際のコードを書いてみましょう。え、フローは、どうするの?って・・・ 先ほど、仮に出しましたね、全体像の予想図 ![]() これを元にフローを考えながら、プログラムも書いちゃいましょう。とても実践的なのですが、教育的意義の低い方法です・・・ まず、ムシの表示と移動をセットで進めましょう。表示と移動は、定番「消す処理と描く処理がセット」になっていますので、実際にムシの位置を表す座標は、表示用と消去用の2種類を用意しなければなりません。 これらと方向を表す変数を、次ようにStartup()で用意することにしましょう。
'虫の座標(表示用)
Global X1 as Integer
Global Y1 as Integer
'虫の座標(消去用)
Global X2 as Integer
Global Y2 as Integer
'虫の向き、右、下、左、上=1,2,3,4
Global M1 as Integer
'初期値
'虫の向き 右(=1)
M1=1
まず、移動の定番は、FormのAfter()に
DrawBitmap 1004,X2,Y2 '前の虫の消去
DrawBitmap 1005+M1,X1,Y1 '新しい位置の虫を描画
'今の座標を保存
X2=X1
Y2=Y1
こんな始まりですね。これを方向によって移動させるわけですから、例えば、
'新しい位置へ移動
Select Case M1
Case 1 '右
X1=X1+10
Case 2 '下
Y1=Y1+10
Case 3 '左
X1=X1-10
Case 4 '上
Y1=Y1-10
End Select
これで、移動は可能なんですが、なにか一つスッキリしませんね。私だけでしょうか?1つは、それほど大げさな処理でもないのに、Select Caseが大きな顔をしているのが気に入りません。そこで、こう言う場合、方向に対する移動量を配列変数にします。???何を言っているの?とりあえず、ソースを見て下さい。 まず、Startup()に次のような配列変数と初期値を用意します。
'ムシの移動量(向き対応)
Global Hx(4) as Integer
Global Hy(4) as Integer
'移動量のセット
Hx(1)=10
Hx(3)=-10
Hy(2)=10
Hy(4)=-10
この新たに登場した「ムシの移動量」を使えば、先ほどの移動処理が、次のようにシンプルになります。
'新しい位置へ移動
X1=X1+Hx(M1)
Y1=Y1+Hy(M1)
もちろん、初期値を与えていないHx()、Hy()は、0 のままです。例えば、右方向への移動では、Hx(1)=10、Hy(1)=0ですので、縦方向の座標は変化しないわけです。結構スッキリしたのではないでしょうか?さて、先に進んで、壁にぶつかった処理です。 こちらは、移動した先が壁だったら、向きを変えれば良いわけですから、難しくなさそうです。 例えば、
'もし移動した先が壁だったら、移動前の位置に戻して方向反転する
If Maze(X1/10+1,Y1/10+1)=1 Then
'移動前の位置に戻す
X1=X2
Y1=Y2
'向きを変える
M1=M1+1
'向きが4を越えたら、1にする
If M1>4 Then
M1=1
End If
End If
気を付ける点は、Maze(i,j)の添字i、jです。ムシの実際の座標(X1,Y1)は、10ピクセルずつ増減しますので、0〜150になりますが、Maze(i,j)は、i,j=1〜16で定義されています。したがって、(X1,Y1)をMaze()の座標系に変換しなければなりません。それが Maze(X1/10+1,Y2/10+1) の部分ですね。表示、移動、ぶつかった処理が揃ったところで完成、と言いたいところですが、忘れている処理があります。それは、外周です。 このままだと、ムシは、Palmの画面からはみ出して、見えなくなってしまいます。いや、たぶん、出た後すぐに、Maze()の添字がオーバーしますので、PalmOSが致命的なエラーで止まるんじゃないでしょうか?そうならないために、はみ出さないようにチェックしなければなりません。色々な方法がありますが、ここでは素直に外周をチェックすることにしましょう。 素直な、外周チェックは、結構簡単です。条件としては、
さて、この条件を考えてコード化すれば良いので、例えば、右端を超えたときは、
'右端を超えたら方向転換する
If X1>150 Then
'横方向を移動前の位置に戻す
X1=X2
'向きを変える
M1=M1+1
'向きが4を越えたら、1にする
If M1>4 Then
M1=1
End If
End If
これを先ほどの条件に合わせて4つ作るだけですが、やっぱりスッキリしませんね。スッキリしないのは、どこか、というと、
例えば、次のように考えてみます。
'方向転換フラグの用意
Dim flgTurn as Integer
Do
'方向転換フラグの初期化
flgTurn = 0
'横方向にはみ出しているかチェック
'はみ出していたら、戻して方向反転を有効にする
If X1>150 Then
X1=X2
flgTurn=1
End If
If X1<0 Then
X1=X2
flgTurn=1
End If
'縦方向にはみ出しているかチェック
'はみ出していたら、戻して方向反転を有効にする
If Y1>150 Then
Y1=Y2
flgTurn=1
End If
If Y1<0 Then
Y1=Y2
flgTurn=1
End If
'もし移動した先が壁だったら、移動前の位置に戻して方向反転する
If Maze(X1/10+1,Y1/10+1)=1 Then
'移動前の位置に戻す
X1=X2
Y1=Y2
flgTurn=1
End If
'方向転換フラグが1だったら、方向転換
If flgTurn=1 Then
'向きを変える
M1=M1+1
'向きが4を越えたら、1にする
If M1>4 Then
M1=1
End If
End If
Loop
向きを変える処理部分だけ取り出して、そこを実行するか否かは、方向転換フラグflgTurnという変数を用意して、判定しています。これで、同じ処理を繰り返さなくても大丈夫になりました。さて、もう1つの無駄、これは、このコードを見ればわかりますね。 もう、詳しくは言わなくてもよいでしょう、
If X1>150 Or X1<0 Then
これだけヒントを出しておけば大丈夫ですね。さて、今まで出てきた部分を「パズル」のように組み合わせてください。1つのムシ移動プログラムが出来あがります。 でも、まだ、実行しないで下さい!!。わからない人は、リセットピンを用意して、実行してみましょう。 最後の仕上げは、ブロックを置く処理と結合させる事です。 今回のプログラムは、2つの処理がそれほど関係していない、という前提で作り始めましたので、結合もそれほど難しくないでしょう。 ただ、1つ考慮する点は「どの時点でイベントを発生させるか?」という点です。 FormのAfter()モジュール内で、Do〜Loopなどの連続的な処理をする場合、SysEventAvailable()で意図的に抜け出さないと、リセットが必要な無限ループにんなる事は、周知の事実か、または、数分前に経験したかと思います。例えば、このプログラムで、定石通りに、 Do Until SysEventAvailable()=1 とすると、流れ的には、 ![]() ムシの移動やぶつかった処理が終わった後、新しい座標に表示される前に、ループを抜けてしまいます。したがって、ブロックを置く位置に、実は、ムシが表示される予定だったかもしれません。ということで、これでは感覚的にも、精神衛生的にも、よくありませんので、実際の表示が終わった後にループを抜けるのが妥当でしょう。したがって、フローは次のように考えるのが妥当でしょう。 ![]() コードは、サービスで掲載しておきましょう。
If SysEventAvailable()=1 Then
Exit Do
End If
一通り、コード類の部品を紹介してみました。 多分、頭の中でフローも組み立てられている事と思いますので、後、完成までは、パズルのようですが各自で組み上げてみてください。もう、ここまで来れば、大丈夫でしょう? あ、一つだけ、載せていないコードがあります。 もし、ムシの移動が早すぎるようでしたら、Delayコマンドをどこかに入れて時間調整して下さい。 |
第11回 何か作ってみよう「5.ムシムシ大行進」
|