“RUN” それは魔法の言葉

私とコンピュータの思い出を、だらだらと綴ります。

65.ゲーム&ウォッチのオクトパスを作ろう その6

最後はゲームの微調整部分。
このゲームも200点と500点でミスがクリアされる。
「マンホール」では、1回につき1点しか入らないので、スコア判定も楽だったけど、「オクトパス」は、財宝を取るとその場で1点、船に戻ると3点入る。なので、2か所で判定処理をしなくてはならなかった。

! 財宝ゲット
IF ptake_f=1 & pos=6 THEN
 IF bagpos<10 THEN
  GR.HIDE p_obj[bagpos-1]
  GR.SHOW p_obj[bagpos]
  bagpos++
 ELSE
  pos=6
  ptake_f=0
  sc++
  SOUNDPOOL.PLAY sp,2,0.99,0.99
  VIBRATE vpt[],-1
  GR.HIDE p_obj[bagpos-1]
  GR.SHOW p_obj[pos]
  if sc=200 | sc=500 then GOSUB miss_clear
 ENDIF
 GR.RENDER
ENDIF

bag_score: % 船に戻った

bsc=sc

GR.HIDE p_obj[1]
GR.SHOW p_obj[10]
GR.RENDER
for tt=1 to l*6
next

GR.HIDE p_obj[10]
GR.SHOW p_obj[1]
sc++
SOUNDPOOL.PLAY sp,2,0.99,0.99
GOSUB view_score
GR.RENDER
VIBRATE vpt[],-1
!PAUSE 300
for tt=1 to l*3
next

GR.HIDE p_obj[1]
GR.SHOW p_obj[10]
sc++
SOUNDPOOL.PLAY sp,2,0.99,0.99
GOSUB view_score
GR.RENDER
VIBRATE vpt[],-1
for tt=1 to l*3
next

GR.HIDE p_obj[10]
GR.SHOW p_obj[1]
sc++
SOUNDPOOL.PLAY sp,2,0.99,0.99

GOSUB view_score
GR.RENDER
VIBRATE vpt[],-1
for tt=1 to l*3
next

if (bsc>=197 & bsc<200 & sc>=200) | (bsc>=497 & bsc<500 & sc>=500) then GOSUB miss_clear

start_cnt=20 % 船にいられるカウンタをリセット
bjump=0

RETURN

こうして出来上がったのが、これ。「マンホール」同様、それっぽくて、それなりに遊べるようになった。
youtu.be

64.ゲーム&ウォッチのオクトパスを作ろう その5

次は、ゲームの本体と言ってもいい、タコ足の動きの処理を作った。
「マンホール」と同じく、1サイクルごとに、タコの足(の節)がどれか1つ動くことを繰り返してる。
今回はマンホールの通行人のように、ビットで管理するのはあまり意味が無いので、どの足が、どれくらいまで、伸びるもしくは縮むかの方向を、【リスト】という概念で管理することにした。

リストは昔からある考え方で、値をカンマ記号で区切ったものを羅列する。
 1,2,3,4,5,6,7
こんな感じ。ただ、昔のMSXなどのBASICには、このリストを処理するための命令がなかったので、自分で文字をカンマがどこにあるかを判定しながら切り出す処理を作っていた。
BASIC!では、ありがたいことに、リストを操作する命令が標準搭載されていた。

リストを作る:LIST.CREATE命令
リストに値を追加する:LIST.ADD命令

タコの足は、5か所に伸びるけど、1番目と2番目の足は、根元が共通で、どちらか一本しか出ない。
なので、リストは常に4項目になる。はじめのタコ足の順番は適当に。

!タコ足の位置・段階リスト
LIST.CREATE N,oct_leg_pos % タコ足位置
LIST.CREATE N,oct_leg_step % タコ足段階
LIST.CREATE N,oct_leg_def % タコ足方向
LIST.ADD oct_leg_pos,5,3,2,4
LIST.ADD oct_leg_step,0,0,0,0
LIST.ADD oct_leg_def,1,1,1,1

そして、タコ足を動かすのは、「マンホール」の時と同じく、TIMERイベントを発生させて、その都度1本ずつ処理していく。

リストから値を取得する:LIST.GET命令
リストから値を削除する:LIST.REMOVE命令

LIST.GET命令自体は、リストの何番目から値を取得するかを指定できるのだが、今回は常に先頭のリストを取得して、その足の処理を行う。それが終わったら先頭のリストを消して、末尾に今処理した足の情報をリストに付け加えるようにした。いわゆる、FIFO(ファースト・イン・ファースト・アウト)の処理がしやすい。

タコ足の節の数が3~5とバラバラなので、伸びきって縮むまでのステップの違いで、適度にばらついてくれる。
1番目、2番目の足が縮みきったら、ランダムで次にどちらの足を伸ばすかを決めて、リストに追加するようにした。
これだけ適当に作ってみても、それっぽく遊べるゲームになってきた。

! タコ足の処理
LIST.GET oct_leg_pos,1,o_pos
LIST.GET oct_leg_step,1,o_step
LIST.GET oct_leg_def,1,o_def

% タコの足を1つ動かす
IF o_step>0 THEN GR.HIDE oleg_obj[o_pos,o_step]
o_step+=o_def
IF o_step<oleg_ptn[o_pos] & o_step>0 THEN
 GR.SHOW oleg_obj[o_pos,o_step]
ELSEIF o_step=oleg_ptn[o_pos] THEN
 GR.SHOW oleg_obj[o_pos,o_step]
 o_def=-1
ELSEIF o_step=0 THEN
 o_def=1
 IF o_pos=1 | o_pos=2 THEN % タコ足①と②どちらか1本だけにする
  o_pos=INT(RND()*2)+1
 ENDIF 
ENDIF

IF o_pos=pos-1 & o_step=oleg_ptn[o_pos] THEN % ミス判定
 GOSUB miss_logic
ENDIF 

!タコ足情報の更新
!リストの先頭を削除
LIST.REMOVE oct_leg_pos,1
LIST.REMOVE oct_leg_step,1
LIST.REMOVE oct_leg_def,1

!末尾に次のタコ足情報を追加
LIST.ADD oct_leg_pos,o_pos
LIST.ADD oct_leg_step,o_step
LIST.ADD oct_leg_def,o_def

ENDIF

63.ゲーム&ウォッチのオクトパスを作ろう その4

まずは、潜水夫を移動するために、ボタンの判定を作った。
オクトパスはボタンが2つなので、マンホールの半分の判定処理で済む。済むはずだった。

いざ、作ってみると、ちょっと右ボタンのところに触れただけで、潜水夫がワープしたかのように一番右端に移動した…
タッチパネルに触ったという判定が、触っている間、ずっと続いてしまい、超高速で連打したのと同じになっていた。

幸い、GR.TOUCH命令は、渡した変数にタッチしているかどうかの情報を返してくれるので、タッチしたままだと、移動しないように処理を加えた。

さらにまだアクションがある。
潜水夫が一番右端に居るときに、さらに右ボタンを押すと財宝をゲットするアクションが起きる。
このとき、アニメーションパターンを表示して、その間は移動も追加での財宝ゲットもできないように処理。

一度船から潜ると、潜水夫は財宝を1つでもゲットしないと、船には戻れない。これもフラグ処理を追加。
このフラグが立っていたら、財宝を入れる袋を潜水夫の横に表示させた。

完成版からのソースなので、すでにいろいろな処理が入っているが、だいたいこんな感じ。
単純に移動するだけじゃないので結構ごちゃごちゃしたソースになってしまった…

 GR.TOUCH touched,x,y

 ! ボタンをタッチしたままでは反応しないようにフラグ処理
 IF !touched & touch_f=1 THEN touch_f=0 % タッチパネルから一度手を離すとフラグリセット

 x=x/rate:y=y/rate

 IF touched & touch_f=0 & ptake_f=0 THEN % タッチフラグがオフで、金塊取り始めてなければ移動判定 
  IF y>=210 & y<=290 THEN
   IF x>=30 & x<=100 THEN
    touch_f=1 % タッチフラグをON
    IF pos>1 THEN
     pos--
     IF pos=1 & pbag_f=0 THEN %金塊フラグがないと船に戻れない
      pos=2
     ENDIF
     IF pos<=1
      pos=1
      IF pbag_f=1 THEN % 金塊を持ってたら
       bjump=1
       GOSUB bag_score % 点数処理へ
       pbag_f=0 % 金塊フラグをオフ
      ENDIF
     ENDIF
    ENDIF
   ELSEIF x>=475 & x<=545 THEN
    touch_f=1 % タッチフラグをON
    IF pos<=5 THEN
     pos++
    ELSEIF pos=6 THEN
     pbag_f=1 % 金塊袋フラグを立てる
     ptake_f=1 % 金塊取り始めたフラグを立てる
     bagpos=7
     GR.SHOW p_obj[bagpos]
    ENDIF
   ENDIF
  ENDIF

趣味のプログラムでなければ、リファクタリングするところだが、処理速度にも問題もないので、このまま放置したw

思いつくままに付け足して、動かして、スパゲッティーなプログラムにしていく。でも動けばいい。
うん。これぞ小学生、中学生の時に体験したものだ。なんて楽しいんだろうw

62.ゲーム&ウォッチのオクトパスを作ろう その3

液晶パターン切り出しの続きで、潜水夫の話。潜水夫も、かなり面倒なことがわかった。

潜水夫の位置は、5か所+船の上。これを切り出すだけなら、そんなに大変じゃないが、このゲームのミッション、宝箱から財宝をゲットすると、潜水夫の手には袋が表示されるのだ。

f:id:CORO3:20210110223428j:plain

これはタコの足と同じようにせず、1つずつ袋も切り出して表示するようにした。
他にもミスの時のタコ足と潜水夫のアニメパターン、財宝をゲットするアニメパターン、財宝を持って船に戻った時のアニメパターンなどを切り出すと、結構な数になった。

f:id:CORO3:20210110223628j:plain

これらの画像を、GR.BITMAP.LOAD命令で読み込んで、GR.BITMAP.DRAW命令で、液晶パターンと重なるように座標を調整しながら表示させた。

!背景画像読み込み・描画
GR.BITMAP.LOAD oct_bg1,"oct_bg1.png"
GR.BITMAP.DRAW bg1,oct_bg1,0,0

!タコ画像読み込み
GR.BITMAP.LOAD o_body,"oct_body.png"
GR.BITMAP.DRAW ob,o_body,252,115

!プレイヤーキャラ画像読み込み
DIM p_obj[10] %潜水夫オブジェクト

GR.BITMAP.LOAD p_png, "oct_p0.png" 
GR.BITMAP.DRAW p_obj[1],p_png,172,87
GR.BITMAP.LOAD p_png, "oct_p1.png" 
GR.BITMAP.DRAW p_obj[2],p_png,172,131
GR.BITMAP.LOAD p_png, "oct_p2.png" 
GR.BITMAP.DRAW p_obj[3],p_png,179,173
GR.BITMAP.LOAD p_png, "oct_p3.png" 
GR.BITMAP.DRAW p_obj[4],p_png,220,205
GR.BITMAP.LOAD p_png, "oct_p4.png" 
GR.BITMAP.DRAW p_obj[5],p_png,268,205
GR.BITMAP.LOAD p_png, "oct_p5.png" 
GR.BITMAP.DRAW p_obj[6],p_png,328,210
GR.BITMAP.LOAD p_png, "oct_ptake1.png" 
GR.BITMAP.DRAW p_obj[7],p_png,330,211
GR.BITMAP.LOAD p_png, "oct_ptake2.png" 
GR.BITMAP.DRAW p_obj[8],p_png,330,211
GR.BITMAP.LOAD p_png, "oct_ptake3.png" 
GR.BITMAP.DRAW p_obj[9],p_png,330,211
GR.BITMAP.LOAD p_png, "oct_p_b.png" 
GR.BITMAP.DRAW p_obj[10],p_png,170,87

FOR i=2 TO 10
 GR.HIDE p_obj[i]
NEXT

!金塊袋読み込み・描画
DIM pbag_obj[5]
GR.BITMAP.LOAD pbag,"oct_pbag1.png"
GR.BITMAP.DRAW pbag_obj[1],pbag,202,151
GR.BITMAP.LOAD pbag,"oct_pbag2.png"
GR.BITMAP.DRAW pbag_obj[2],pbag,199,209
GR.BITMAP.LOAD pbag,"oct_pbag3.png"
GR.BITMAP.DRAW pbag_obj[3],pbag,248,233
GR.BITMAP.LOAD pbag,"oct_pbag4.png"
GR.BITMAP.DRAW pbag_obj[4],pbag,298,232
GR.BITMAP.LOAD pbag,"oct_pbag5.png"
GR.BITMAP.DRAW pbag_obj[5],pbag,317,227

FOR i=1 TO 5
 GR.HIDE pbag_obj[i]
NEXT

!タコ足読み込み・描画
DIM oleg_obj[5,5]
ARRAY.LOAD oleg_ptn[],3,4,5,4,3 % タコ足パターン数

!タコ足①
GR.BITMAP.LOAD p_leg,"oct_leg1-1.png"
GR.BITMAP.DRAW oleg_obj[1,1],p_leg,201,137
GR.BITMAP.LOAD p_leg,"oct_leg1-2.png"
GR.BITMAP.DRAW oleg_obj[1,2],p_leg,201,137
GR.BITMAP.LOAD p_leg,"oct_leg1-3.png"
GR.BITMAP.DRAW oleg_obj[1,3],p_leg,201,137

!タコ足②
GR.BITMAP.LOAD p_leg,"oct_leg2-1.png"
GR.BITMAP.DRAW oleg_obj[2,1],p_leg,208,142
GR.BITMAP.LOAD p_leg,"oct_leg2-2.png"
GR.BITMAP.DRAW oleg_obj[2,2],p_leg,208,142
GR.BITMAP.LOAD p_leg,"oct_leg2-3.png"
GR.BITMAP.DRAW oleg_obj[2,3],p_leg,208,142
GR.BITMAP.LOAD p_leg,"oct_leg2-4.png"
GR.BITMAP.DRAW oleg_obj[2,4],p_leg,208,142

!タコ足③
GR.BITMAP.LOAD p_leg,"oct_leg3-1.png"
GR.BITMAP.DRAW oleg_obj[3,1],p_leg,250,157
GR.BITMAP.LOAD p_leg,"oct_leg3-2.png"
GR.BITMAP.DRAW oleg_obj[3,2],p_leg,250,157
GR.BITMAP.LOAD p_leg,"oct_leg3-3.png"
GR.BITMAP.DRAW oleg_obj[3,3],p_leg,250,157
GR.BITMAP.LOAD p_leg,"oct_leg3-4.png"
GR.BITMAP.DRAW oleg_obj[3,4],p_leg,250,157
GR.BITMAP.LOAD p_leg,"oct_leg3-5.png"
GR.BITMAP.DRAW oleg_obj[3,5],p_leg,250,157

!タコ足④
GR.BITMAP.LOAD p_leg,"oct_leg4-1.png"
GR.BITMAP.DRAW oleg_obj[4,1],p_leg,294,172
GR.BITMAP.LOAD p_leg,"oct_leg4-2.png"
GR.BITMAP.DRAW oleg_obj[4,2],p_leg,294,172
GR.BITMAP.LOAD p_leg,"oct_leg4-3.png"
GR.BITMAP.DRAW oleg_obj[4,3],p_leg,294,172
GR.BITMAP.LOAD p_leg,"oct_leg4-4.png"
GR.BITMAP.DRAW oleg_obj[4,4],p_leg,294,172

!タコ足⑤
GR.BITMAP.LOAD p_leg,"oct_leg5-1.png"
GR.BITMAP.DRAW oleg_obj[5,1],p_leg,348,186
GR.BITMAP.LOAD p_leg,"oct_leg5-2.png"
GR.BITMAP.DRAW oleg_obj[5,2],p_leg,348,186
GR.BITMAP.LOAD p_leg,"oct_leg5-3.png"
GR.BITMAP.DRAW oleg_obj[5,3],p_leg,348,186

FOR i=1 TO 5
 FOR j=1 TO oleg_ptn[i]
  GR.HIDE oleg_obj[i,j]
 NEXT j
NEXT i

!残り潜水夫マーク読み込み・描画
DIM p_stock[2]
GR.BITMAP.LOAD p_stc,"oct_p_stock.png"
GR.BITMAP.DRAW p_stock[1],p_stc,208,87
GR.BITMAP.DRAW p_stock[2],p_stc,232,87

!ミスパターン読み込み・描画
DIM p_miss[2]
GR.BITMAP.LOAD p_miss,"oct_miss1.png"
GR.BITMAP.DRAW p_miss[1],p_miss,264,155
GR.BITMAP.LOAD p_miss,"oct_miss2.png"
GR.BITMAP.DRAW p_miss[2],p_miss,264,155

FOR i=1 TO 2
 GR.HIDE p_miss[i]
NEXT

!セロファン部読み込み・描画
GR.BITMAP.LOAD oct_bg2,"oct_bg2.png"
GR.COLOR 204,0,0,0 % 画像の透過度を設定
GR.BITMAP.DRAW bg2,oct_bg2,0,0

これから、メインのプログラムを作っていった。