フルーツ ミラージュ 製作過程(2)

Home PC-6001mkII Program etc

 このページでは、画面表示から完成までの過程を書いています。

フルーツ ミラージュ 製作過程 Top


2009/08/16:肉付け
 今日は、まず面クリアができるように、画面上のフルーツがなくなったらドアを開ける処理とドア(開)に入ると面クリアする処理を追加する。ここはサクッと作り終える。

 次に、画面周りをもう少しマシにする。HSP 3.2からグラデーション命令gradfが出たのでちょっと使ってみようか。...ちょっとセンスが足りないように思うが、この辺りで止めておく。

画面

 次に、Rキーを押したら面やり直しを行う(面生成処理まで飛ぶ)処理を追加。これもさっくり作成、と思いきや、落とし穴があった。

*StartMaze
 :
repeat
  await 30
   :
  getkey k, 82
  if k: goto *StartMaze
loop

 このようにループの中からループの外にジャンプする処理にしていたため、Rキーを数十回押すとネストエラーになってしまった。

 仕方ない。回りくどいけど、変数を一つ用意して正式にループを抜けてからジャンプするようにしよう。
*StartMaze
 :
repeat
  await 30
   :
  getkey k, 82
  if k: gamestatus = 1
   :
  if gamestatus: break
loop
if gamestatus = 1: goto *StartMaze

 ちなみにわざわざ変数を用意したのは、面クリア等でループを抜けるときにも使えると思ったからだ。

 その他、アンドゥ処理を実装する。この処理自身は、以前に作ったストレトリのものとほぼ同じだ。違うのは、岩かフルーツを押したタイミングでアンドゥ用のポインタを移動させることぐらいだ。

 見た目はさほど変わらないが、これで操作性はあがった。

2009/08/17:2面
 面クリアの後は、当然次の面だ。という事で、前に作ったツールを使って2面のデータを入力する。

 さて実行...1面クリア後にエラー発生。「配列の要素が無効です」と出たが、どうにも心当たりがない。とはいえ、新規に入力した2面のデータに悪い部分があるのは明らかなのでデータを確認する。

 わかった。データ中に「\」が入ってたんだ。HSPの文字列中の「\」は特殊文字なので「\\」に変えなければならないんだった。原因がわかると後は楽だ。サクサクとツールの修正を行い、データを再度入力する。

画面

 あとは、手詰まり処理を実装する。
 画面上の各フルーツの個数を数えて、一種類でも残り1つか2つの場合手詰まり状態となる。手詰まりフラグ用の変数を用意し、フラグが立っている場合はカーソル移動部分のみ無効にする。アンドゥした場合は、手詰まりフラグは解除する、っと。こんなところかな?

2009/08/19:サイズ削減その3
 3面から16面までのデータを入力する。元データはPC-6001版のものがあるので楽だが、その分特に面白みもない作業なので、飽きる前に一気にやり終える。

 あとは、ソースを見直して削減できそうな部分を作り変える。
 まずは、省略できるパラメータだ。わざわざ書くほどでもないけど、こんな感じだ。
  • boxf 0, 90 → boxf , 90
  • buffer 1, 1944, 95, 0 → buffer 1, 1944, 95
 次に、if文を論理式に変更することで削減を試みる。判定の結果、値が±1する場合は割と使える手段だ。HSP掲示板のスレッドで論理式の真を1でなく-1にすべきという話になっているが、変わるとこんな部分も見直さないとダメなんだろうな...面倒だ。
  • if p_next = 0 : moveflag+ →  moveflag += (p_next = 0)
 あとは、今回すっかりお気に入りになってしまった8/11の手法を使ってサイズ削減する。
これがこんな感じ
;●フルーツくっつき処理
repeat 71, 9	;8*8+7
  p1 = a_p(cnt)
  if p1 >= 6 and p1 <= 12 {
    if p1 = a_p(cnt + 1) {
      ;横長(左)フルーツ番号
      a_p(cnt) = p1 + 18
      ;横長(右)フルーツ番号
      a_p(cnt + 1) = p1 + 24
    }
    if p1 = a_p(cnt + 9) {
      ;縦長(上)フルーツ番号
      a_p(cnt) = p1 + 6
      ;縦長(下)フルーツ番号
      a_p(cnt + 9) = p1 + 12
    }
  }
loop
;●フルーツくっつき処理
repeat 71, 9	;8*8+7
  p1 = a_p(cnt)
  if p1 >= 6 and p1 <= 12 {
    c = cnt
    cp = cnt + 1
    ;横長(左)フルーツ番号
    pp = p1 + 18
    repeat 2
      if p1 = a_p(cp) {
        ;左 or 上 フルーツ
        a_p(c) = pp
        ;右 or 下 フルーツ
        a_p(cp) = pp + 6
      }
      cp += 8	;cnt + 9
      ;縦長(上)フルーツ番号
      pp -= 12
    loop
  }
loop


2009/08/22:6000越え
 あと残すは、面選択処理と16面クリア処理だろうか。

 まずは面選択処理を実装する。まずEnterキーを押したら面選択の入力ボックスと決定ボタンを表示する。ここで面数を入力し決定ボタンを押す事で、(入力面が現在の面と違う場合)その入力面に移動するようにする。

 ここで妙なこだわりだが、キーボード操作の操作性を高めておきたい。
具体的には「Enterキーを押しても決定ボタンが押されたときと同じ動作をする」事と「Escキーを押すと入力をキャンセルする」事だ。あると嬉しいというほどではないが、ないとどこか不便を感じる地味な機能なのだが。

 さて面選択を実装完了した頃、ついに来てしまった。start.axの6000バイト越えだ。うむむ、まだ16面クリア処理をまったく入れてないのだが...。しかたない、またサイズ削減するか。

 サイズ削減する際に良く見るのは、同じような処理が複数あった場合に1つにまとめられないかといった観点だ。これがうまくはまると、100バイト程度削減できる場合もある。

 今回成功したケースで言うと、岩変化の判定処理だ。
これがこんな感じ
repeat 71, 9  ;=8*8+7
  p1 = q(cnt)
  if p1 < 99 {
    ;3回以上使うので変数化
    cm1 = cnt - 1: cp1 = cnt + 1
    cm9 = cnt - 9: cp9 = cnt + 9
    ;上下左右のうち2つ以上同じ種類の
    ;フルーツがあれば岩変化
    if (p1 = q(cm1)) + (p1 = q(cp1)) +
       (p1 = q(cm9)) + (p1 = q(cp9)) > 1 {
      a_p(cnt) = 1
      if p1 = q(cm1): a_p(cm1) = 1
      if p1 = q(cp1): a_p(cp1) = 1
      if p1 = q(cm9): a_p(cm9) = 1
      if p1 = q(cp9): a_p(cp9) = 1
    }
  }
loop
repeat 71, 9  ;=8*8+7
  p1 = q(cnt)
  if p1 < 99 {



    ;上下左右のうち2つ以上同じ種類の
    ;フルーツがあれば岩変化
    if (p1 = q(cnt-1)) + (p1 = q(cnt+1)) + 
       (p1 = q(cnt-9)) + (p1 = q(cnt+9)) > 1 {
      a_c = cnt, cnt-1, cnt+1, cnt-9, cnt+9
      repeat 5
        if p1 = q(a_c(cnt)): a_p(a_c(cnt)) = 1
      loop

    }
  }
loop

 後半の処理では、同じ書式の文が4つ並んでいる。これを、ループ化する事でサイズ削減した。cm1, cp1, cm9, cp9の変数化は外してしまった(概ね3回以上使わないと変数化するメリットがないため)が、これで130バイト削減できる。

 この後、「cnt - 1」「cnt + 1」「cnt - 9」「cnt + 9」が複数使用されている部分をなんとかまとめられないかと思い、以下のように変更している。
これがこんな感じ
repeat 71, 9  ;=8*8+7
  p1 = q(cnt)
  if p1 < 99 {
    ;上下左右のうち2つ以上同じ種類の
    ;フルーツがあれば岩変化
    if (p1 = q(cnt-1)) + (p1 = q(cnt+1)) + 
       (p1 = q(cnt-9)) + (p1 = q(cnt+9)) > 1 {
      a_c = cnt, cnt-1, cnt+1, cnt-9, cnt+9



      repeat 5
        if p1 = q(a_c(cnt)): a_p(a_c(cnt)) = 1
      loop
    }
  }
loop
repeat 71, 9	;=8*8+7
  p1 = q(cnt)
  if p1 < 99 {
    ;上下左右のうち2つ以上同じ種類の
    ;フルーツがあれば岩変化
    a_c = cnt-1, cnt+1, cnt-9, cnt+9, cnt
    dim samecount
    repeat 4
      samecount += (p1 = q(a_c(cnt)))
    loop
    if samecount > 1 {
      repeat 5
        if p1 = q(a_c(cnt)): a_p(a_c(cnt)) = 1
      loop
    }
  }
loop

 ぱっと見た目処理は増えているが、これでさらに64バイト削減だ。

 その他、同じ配列変数の値を使用している箇所を、dup命令で変数化したり、実際に使われていなかったゴミ処理を削ったりして、200バイトほどの余裕ができた。あとはエンディング処理を追加してからまた考えることにしよう。

2009/08/22:エンディング
 最後の処理となる、エンディング処理の実装を行う。

 エンディングの内容は秘密(どうしても見たい人は、P6版の解答集を参考のこと)だが、当然のようにまたstart.axのサイズが膨れ上がり、6232バイトとなった。いつもならまた後日にするところだが、この日は妙にやる気があったのでまたサイズ削減にいそしむ。

 まずトム君の移動と岩/フルーツを押す処理を、考え方はそのままに1から作り直す。この部分で88バイト削減。さらに、前に書いた岩変化の2回目の変更で64バイト削減。

 あとは、こまごまとしたサイズ削減を行う。この辺りになると、特定の処理に特化した話になってとても説明しきれないので割愛する。

 という訳で、ようやく6000バイト内に収まった!

 最後に、軽く一通りプレイして問題が出ないことを確認してから、HSPプログラムコンテストへのエントリーを行う。これで一区切りだ。


製作過程(1) フルーツ ミラージュ 製作過程