ポケコンBASICによる

アクションゲーム制作講座 〜入門編〜

第3回 キャラをちらつきなしに動かす


 前回、敵キャラを加えるだけで今まで無かった"P"のちらつきが非常に目立ってきました。これは10行のWAITの値をどんな値にしても改善できません。" "(スペース)で消さないならば、このような点滅は無くなりますがそうなると残像が残ってしまいます。

 それでは、なぜこんなに激しくちらついてしまうのか原因を考えてみます。
 まずは前回のリスト5を入力してみてください。TRON [RETURN]でトレースモードにして、としてどのように実行されているのか見ていきます。
"P"は140行で表示された後に150行で消され、160、170、20、30、40、50、60、70、80、90、100、110、120、130、それぞれの行が実行されている間ずっと消えており、再び140行で表示されています。敵キャラ"&"も同様で70行で表示された後に80行で消され、再び70行で表示されるまでずっと消えています。
 つまり、消えている時間が長いためにちらつきが起きているわけです。表示している時間を伸ばそうとしてWAITで自キャラ"P"が表示している時間を増やしても敵キャラ"&"が消えている時間が長くなるため根本的な解決にはなりません。

 したがって、キャラを動かす部分だけを根本的に改善する必要があります。第1回のリスト5からやり直してみましょう。
 要するにキャラがちらついて見えるのは表示した次の行ですぐに消しているのが原因となっており消している行に問題がありそうです。元々はなぜ消す必要があったのかを考えると残像が残るからですね。それならばちらつかないようにする方法は2つ考えることができます。

(1)移動するときのみ消去処理を行う
(2)キャラが消えている時間をできるだけ短くする

、それならば表示したキャラを消すのではなく残像の方だけを消せばこの問題は解決できそうです。
 ここで問題となるのは残像を消すというのがどのようなものかということです。残像になっているのは場所を移動する前のキャラであるため場所を移動する前の元のキャラの座標に" "(スペース)を表示することで残像が消去が可能になります。

リスト1
10 CLS :X=0:Y=0:WAIT 5
20 K$=INKEY$
30 IF K$="8" AND Y>0 THEN LOCATE X,Y:PRINT " ":Y=Y-1
40 IF K$="2" AND Y<3 THEN LOCATE X,Y:PRINT " ":Y=Y+1
50 IF K$="4" AND X>0 THEN LOCATE X,Y:PRINT " ":X=X-1
60 IF K$="6" AND X<39 THEN LOCATE X,Y:PRINT " ":X=X+1
70 LOCATE X,Y:PRINT "P"
80 GOTO 20

 キーを押したときにしか消去をしないのでキャラの点滅もなくなりました。
 しかし、LOCATE X,Y:PRINT " "という全く同じものが4つもあるのが気になります。今回は4方向移動でしたが、これが8方向移動になれば同じものが8つになりますし、キャラ数が2つになればさらに2倍になります。それに今は単純に" "(スペース)でキャラを消去していますが、背景キャラがあればそういう単純消去もできなくなるために今後のことを考え、できればキャラ消去は1カ所のみでやりたいところです。

 1カ所でキャラ消去を行うには残像、つまりキャラの元の座標が分からなくてはなりません。それを解決するための方法は2つあります。

(1)キャラの元の座標を別の変数に入れておく
(2)キャラの移動量を別の変数に入れておく

 今回は(2)の方法でやってみることにしましょう。(1)の方法の方が簡単なのですが、(2)のように移動量を別途変数に入れることで便利になる場合があるからです。
 移動量が分かっていればそれをマイナスすれば元の座標も分かります。そういうことで、変数VにX座標の移動量変数WにY座標の移動量を入れてリスト5をもう一度作り直してみます。

リスト7
10 CLS :X=0:Y=0:WAIT 5
20 K$=INKEY$:V=0:W=0
30 IF K$="8" AND Y>0 THEN W=-1
40 IF K$="2" AND Y<39 THEN W=1
50 IF K$="4" AND X>0 THEN V=-1
60 IF K$="6" AND Y<3 THEN V=1
70 X=X+V:Y=Y+W
80 LOCATE X,Y:PRINT "P"
90 LOCATE X,Y:PRINT " "
100 GOTO 20

 例えば30行のW=-1はただの移動量であり実際のキャラのX座標、Y座標はこの数値を元に70行で計算されています。それを考えればこの30行はY=Y-1と同じことを意味します。そうなると、これはリスト5と変わってないことが分かるでしょう。
 20行のV=0W=0はなぜ必要かというと押してないときには移動しないようにするためです。実際にこれを削除してみれば分かりますが、もしもV=0、W=0が無ければ一旦キーを押したらキーを離してもキャラが動き続けます。今回はキーを押したときのみ動作させていますが、キーを1回押したら離しても動き続けるタイプのゲームもこの方法を使えば簡単にできるわけです。

 リスト7で残像(元の座標のキャラ)の方を消すように改良したものは次のようになります、

リスト8
10 CLS :X=0:Y=0:WAIT 5
20 K$=INKEY$:V=0:W=0
30 IF K$="8" AND Y>0 THEN W=-1
40 IF K$="2" AND Y<39 THEN W=1
50 IF K$="4" AND X>0 THEN V=-1
60 IF K$="6" AND Y<3 THEN V=1
70 X=X+V:Y=Y+W
80 LOCATE X-V,Y-W:PRINT " "
90 LOCATE X,Y:PRINT "P"
100 GOTO 20

 80行の" "(スペース)の表示座標は90行の"P"の表示座標と比較すると移動量の分だけマイナスされているのでこれが元の座標ということが分かると思います。

 ここで10行のWAITを取り除いてみてください。

リスト9
10 CLS :X=0:Y=0
20 K$=INKEY$:V=0:W=0
30 IF K$="8" AND Y>0 THEN W=-1
40 IF K$="2" AND Y<39 THEN W=1
50 IF K$="4" AND X>0 THEN V=-1
60 IF K$="6" AND Y<3 THEN V=1
70 X=X+V:Y=Y+W
80 LOCATE X-V,Y-W:PRINT " "
90 LOCATE X,Y:PRINT "P"
100 GOTO 20

 キャラの点滅は無くなったと思います。しかも、WAITが無くなった分だけ速度も速くなりました。
 移動していない状態(キーを押していない状態)であれば80行と90行は同じ座標に表示しているのになぜキャラが普通に見えているのかというと消えている間が表示されている間よりも圧倒的に短いからです。
 確かに同じ座標で表示しているのですが、消えている時間は80行を実行してから90行を実行する前だけなのに対して、表示されている時間は90行、100行、20行、30行、40行、50行、60行、70行を実行している時となっています。このように表示している時間が長くなるようにしておけば意図的にWAITを入れて表示時間の待ち時間を作るという無駄なことをする必要はありません。

 ちなみに(2)の移動量を変数V、Wに入れるのではなく、(1)の元の座標を変数V、Wに入れた場合のプログラムリストは次のようになります。

リスト10
10 CLS :X=0:Y=0
20 K$=INKEY$:V=X:W=Y
30 IF K$="8" AND Y>0 THEN Y=Y-1
40 IF K$="2" AND Y<39 THEN Y=Y+1
50 IF K$="4" AND X>0 THEN X=X-1
60 IF K$="6" AND Y<3 THEN X=X+1
70 LOCATE V,W:PRINT " "
80 LOCATE X,Y:PRINT "P"
90 GOTO 20

 20行で変数V、Wに変数X、Yの値を代入しているのですが、30〜60行でX、Yの座標計算を新しく行うことで、70行の時点では変数V、Wは元のX、Y座標となっているわけです。
 リスト9の方でもリスト10の方でもどちらでも問題はありません。

 では、リスト9に前回加えた敵キャラを改めて加えてみることにします。敵キャラに関しても自キャラと同じく移動量を別の変数に入れておくことでちらつきを無くしています。

リスト11
10 CLS :A=20:B=2:X=0:Y=0
20 Z=RND 4:C=0:D=0
30 IF Z=1 AND B>0 THEN D=-1
40 IF Z=2 AND B<3 THEN D=1
50 IF Z=3 AND A>0 THEN C=-1
60 IF Z=4 AND A<39 THEN C=1
70 K$=INKEY$:V=X:W=Y
80 IF K$="8" AND Y>0 THEN W=-1
90 IF K$="2" AND Y<3 THEN W=1
100 IF K$="4" AND X>0 THEN V=-1
110 IF K$="6" AND X<39 THEN V=1
120 A=A+C:B=B+D:X=X+V:Y=Y+W
130 LOCATE A-C,B-D:PRINT " "
140 LOCATE A,B:PRINT "&"
150 LOCATE X-V,Y-W:PRINT " "
160 LOCATE X,Y:PRINT "P"
170 IF A=X AND B=Y THEN BEEP 1:END
180 GOTO 20

 以上のことをまとめるとキャラの移動というのはこうなります。

座標計算元の場所のキャラを消去新しい場所にキャラを表示

 このように消去と表示の間隔をできるだけ短くすることがキャラがちらつかないためには大切となってきます。この基本さえちゃんと理解していればキャラ数がどれだけ増えてもどれだけ複雑な動きになっても怖くはありません

 どんなアクションゲームも基本はキャラの移動当たり判定で構成されています。だからそれを完全にマスターしておけばどんなアクションゲームも作れる可能性があります。
 とはいえ、基本形だけではどうしようもなくゲームに合わせて工夫が必要になる場合が多いでしょう。それには他の人が作ったゲームのプログラムリストを解析するのが有用ですが、長いプログラムリストを1つ1つ把握していくのも大変ですし、他人が作ったものを理解するということ自体も簡単なことではないです。そういうことで、初級編からは簡単なゲームの具体例をあげていきますので少しずつマスターしましょう。

初級編に行く


RETURN/ RETURN *MAIN inserted by FC2 system