中級編:SHOTセルを使う


 Ver 4.0 からの新機能として、セルデータを身体の表示以外に使う事が出来るようになりました。 この機能は主にSHOTで使う事になりますが、これによりSHOTの当たり判定の設定、 SHOTの初期表示位置等がCBで設定出来るようになります。表示についても、 今までのように「Spr設定_表示」で一つずつ指定する必要がなく、プログラムが簡略化されます。

 今回は、セルを使ってSHOTを表示する方法を説明します。 (説明の都合上、この機能をSHOTセル表示と呼ぶことにします。)
 また、SHOTの機能自体についての説明は省かせていただきますので、 SHOTの扱いについてある程度の知識が必要となります。

 まず最初に関連関数の説明です。

・Shot設定_セル情報( SHOT *shot, short cell_id )
現SHOTモジュールで表示に使用するセルIDを設定します。
Shot設定_セル座標()、Shot設定_セル矩形()、Shot設定_表示セル()は、 この関数で設定したセルIDを参照するので、関数呼出の順番には注意が必要です。
関数内でSHOTメンバlen_x,len_yを書き換えています。

・Shot設定_セル座標( SHOT *shot )
SHOTセルの表示位置を設定します。
具体的には身体X,Y位置とセルのX,Yオフセットを加算した値が表示位置になります。 Shot設定_セル情報()を実行し、セルIDを設定した後で呼び出します。 表示位置の上下、左右反転はShot設定_X方向()、Shot設定_Y方向()で設定した値が参照されます。
SHOTメンバpos_x,pos_yを書き換えています。

・Shot設定_セル矩形( SHOT *shot )
SHOTセルの赤矩形を参照して、SHOTの当たり判定の大きさを設定します。
内部的には、SHOTメンバrect_x,rect_y,rect_w,rect_hを書き換えます。

・Pcg転送_セル画像( int p, short cell_id, short pcg_blk, short ofst, short max )
セルの画像データを任意のPCGエリアに展開します。
展開可能な最大枚数は展開するPCGブロックによります。引数 ofst + max がその値を越えてはいけません。 PCG_BLK_ユーザ = 8、PCG_BLK_身体1 = 32、PCG_BLK_身体2 = 32、が最大値です。

・Shot設定_表示セル( SHOT *shot )
Shot設定_セル情報()で設定したセル情報と、 Pcg転送_セル画像()で展開したPCGデータからSHOTセルを画面に表示します。

・Spr取得_番号( int p, short sp_blk )
キャラクタが使用出来るSP番号を取得します。
SP_BLK_飛び道具、SP_BLK_残像は固定値ですが、SP_BLK_身体で得られるSP番号は状況により変動するので注意が必要です。
また、極力 SP_BLK_飛び道具 以外の使用は避けた方がよいでしょう。

・Pcg取得_コード( int p, short pal_blk, short pcg_blk, short ofst, short rev_x, short rev_y, short bg )
PCGコードを引数にしたがって算出します。
SHOTセルの表示に使うPCGコードを算出する場合、 pcg_blk、ofst はPcg転送_セル画像()の引数、pcg_blk、ofst と同じ値を設定する必要があります。
また、rev_x、rev_y、bg は常に OFF を設定します。

・Shot設定_SP番号( SHOT *shot, short sp_num )
SHOTセルの表示に使うSP番号を設定します。
Shot設定_表示セル()ではこの設定値を参照するので、必ず指定します。 通常はSpr取得_番号()で得られた値を加工して使います。

・Shot設定_PCGコード( SHOT *shot, short pcg_code )
SHOTセルの表示に用いるPCGコードを設定します。
通常はPcg取得_コード()の戻り値をそのまま設定します。


 以上の説明からわかるように、これらの関数は実行する順序に気を付けなければいけないものがあります。

Shot設定_セル座標()
Shot設定_セル矩形()
Shot設定_セル情報()の実行後
Shot設定_表示セル() Shot設定_SP番号()
Shot設定_PCGコード()
Pcg転送_セル画像()
Shot設定_セル情報()の実行後
基本的には上のような決まりがあります。

 次にSHOTセルとして表示するセルの用意です。 基本的に身体セルと同じようにCBを使って設定します。 注意する点は、3つの矩形のうち赤矩形のみが有効であるという事。 そして、ここで設定したオフセット座標がShot設定_セル座標()で参照されるという事です。
 これはどういうことかというと、例えば波動拳を放出する絵の身体セルと、 波動拳のSHOTセルがあるものとして考えてみます。
 CBで身体セルの手の部分に重なるような位置にSHOTセルのオフセット座標を設定します。 このようにセルを作成すると、Shot設定_セル座標()を実行した時に、 SHOTセルが身体セルの手の部分に重なるような位置に表示されます。
 飛び道具の初期表示位置の設定には苦労するのですが、SHOTセルならCBで設定するだけで済むので、非常に簡単です。 左右の反転はShot設定_X方向()という関数を事前に実行しておけば、あとは考える必要がありません。 従来、反転時の座標の設定は頭の痛い問題だったのですが、これも簡単に済ませる事が出来るというわけです。

 では、簡単なサンプルを元に解説していきます。SHOTセルと関連がある部分のみ掲載します。

  1:/*---------------------------------------------------------------------------------------*/
  2:  short  Shot_波動拳( int p1, int p2, SHOT *shot, short cmd, short param1, short param2 )
  3:/*---------------------------------------------------------------------------------------*/
  4:{
  5:  static short  pcg_num;
  6://////
  7:(略)
  8://////
  9:  /*....................  有効化(放出)  ....................*/
 10:
 11:  else if( cmd == SHOT_CMD_有効化 ) {
 12:    Shot設定_モジュール状態( shot, SHOT_STATE_有効 );
 13:
 14:    /*.....  基本SHOT属性の設定  .....*/
 15:
 16:    Shot設定_特性タイプ( shot, SHOT_TYPE_弾丸 );
 17:    Shot設定_X方向( shot, 状態取得_表示方向( p1 ) );
 18:    Shot設定_超技フラグ( shot, OFF );
 19:    Shot設定_カウンタ( shot , 8 );
 20:
 21:    /*.....  セル情報の設定  .....*/
 22:
 23:    Shot設定_セル情報( shot, CELL_波動SP01 );
 24:    Shot設定_セル座標( shot );
 25:    Shot設定_セル矩形( shot );
 26:    pcg_num = Pcg取得_コード( p1 , PAL_BLK_表示_PCG, PCG_BLK_ユーザ, 0, OFF, OFF, OFF );
 27:    Shot設定_PCGコード( shot, pcg_num );
 28:    Shot設定_SP番号( shot, Spr取得_番号( p1, SP_BLK_飛び道具 ) );
 29:    Pcg転送_セル画像( p1 , CELL_波動SP01 , PCG_BLK_ユーザ , 0 , 4 );
 30:    Pcg転送_セル画像( p1 , CELL_波動SP02 , PCG_BLK_ユーザ , 4 , 4 );
 31:
 32:    /*.....  ヒット情報の設定  .....*/
 33:
 34:    Shot設定_ヒット情報( shot, HIT_波動 );
 35:    Shot設定_重なり数( shot, 1 );
 36:
 37:    return ON;
 38:  }
 39:
 40:  /*....................  状態変化(移動)  ....................*/
 41:
 42:  else if( cmd == SHOT_CMD_状態変化 ) {
 43:    if( Shot取得_モジュール状態( shot ) == SHOT_STATE_有効 ) {
 44:      short c = Shot減少_カウンタ( shot );
 45:      if( c >= 7 ) {
 46:        Shot設定_セル情報( shot , CELL_波動SP1 );
 47:        Shot設定_セル矩形( shot );
 48:        Shot設定_PCGコード( shot , pcg_num );
 49:        Pcg転送_セル画像( p1 , CELL_波動SP1 , PCG_BLK_ユーザ , 0 , 4 );
 50:        Pcg転送_セル画像( p1 , CELL_波動SP2 , PCG_BLK_ユーザ , 4 , 4 );
 51:      }
 52:      else if( c >= 6 ) {
 53:      }
 54:      else if( c >= 5 ) {
 55:        Shot設定_セル情報( shot , CELL_波動SP2 );
 56:        Shot設定_セル矩形( shot );
 57:        Shot設定_PCGコード( shot , pcg_num + 4 );
 58:      }
 59:      else if( c >= 4 ) {
 60:      }
 61:      else if( c >= 3 ) {
 62:        Shot設定_セル情報( shot , CELL_波動SP3 );
 63:        Shot設定_セル矩形( shot );
 64:        Shot設定_PCGコード( shot , pcg_num );
 65:        Pcg転送_セル画像( p1 , CELL_波動SP3 , PCG_BLK_ユーザ , 0 , 4 );
 66:        Pcg転送_セル画像( p1 , CELL_波動SP4 , PCG_BLK_ユーザ , 4 , 4 );
 67:      }
 68:      else if( c >= 2 ) {
 69:      }
 70:      else if( c >= 1 ) {
 71:        Shot設定_セル情報( shot , CELL_波動SP4 );
 72:        Shot設定_セル矩形( shot );
 73:        Shot設定_PCGコード( shot , pcg_num + 4 );
 74:      }
 75:      else {
 76:        Shot設定_カウンタ( shot , 8 );
 77:      }
 78:      Shot移動_相対方向( shot , 1 , 0 );
 79:      if( Shot調査_表示領域外( shot , 0 , 0 , 0 , 0 ) ) {
 80:        Shot送信_コマンド( shot , SHOT_CMD_無効化 , 0 , 0 );
 81:      }
 82:    }
 83:    else if( Shot取得_モジュール状態( shot ) == SHOT_STATE_消滅 ) {
 84:      if( Shot減少_カウンタ( shot ) <= 0 ) {
 85:        Shot送信_コマンド( shot, SHOT_CMD_無効化, 0, 0 );
 86:      }
 87:    }
 88:    return ON;
 89:  }
 90:
 91:  /*....................  グラフィックの表示  ....................*/
 92:
 93:  else if( cmd == SHOT_CMD_表示 ) {
 94:    if( Shot取得_モジュール状態( shot ) == SHOT_STATE_有効 ) {
 95:      Shot設定_表示セル( shot );
 96:    }
 97:    return ON;
 98:  }
 99://////
100:(略)
102://////
103:}
 このSHOTモジュールでは、以下のような飛び道具を想定しています。
 プログラムを細かく解説していきます。

5行:pcg_num という静的なローカル変数を定義しています。 この変数は、このSHOT関数の中でのみ使えます。 また、static 宣言をしているので内容はプログラムが終了するまで保存されます。
 ここでは Pcg取得_コード() の戻り値を保存しておくのに使っています。

・9〜39行:SHOT_CMD_有効化に応答する部分です。

17行:SHOTのX方向を設定しています。通常は身体の向きと同じ方向を設定するので、 こういった書き方で設定が可能です。X方向は必須設定項目です。

19行:アニメーションのカウンタの初期値を設定しています。 飛び道具の放出時に行う初期化などの処理を記述します。

23〜30行:SHOTセル表示のための初期設定です。最初に表示するセルは CELL_波動SP1 なので、 このセルの情報を元に初期値を設定します。
 28行で飛び道具表示用スプライトをSHOTセルの表示に使う事を設定しています。
 29,30行で Pcg転送_セル画像() を実行しユーザーPCG定義エリアの0〜3の4枚分に CELL_波動SP1 の画像データ、 PCG定義エリアの4〜7の4枚分に CELL_波動SP2 の画像データを展開しています。 アニメーションに使用するセル枚数が2枚であれば、Pcg転送_セル画像()はここで実行するだけで済みます。

・40〜90行:SHOT_CMD_状態変化に応答する部分です。 SHOTの移動、アニメーションカウンタの変化等を行います。

43〜82行:SHOT_STAT_有効の時、つまり当たり判定を持っている状態の時に処理される部分です。
 44行でアニメーションカウンタのデクリメントを行います。 カウンタは8から始まるため、カウンタが7の時がループの始点であるという事になります。
 45〜51行はカウンタが7の時に行う処理です。CELL_波動SP1 CELL_波動SP2 の画像データをPCG定義エリアに展開しています。 またカウンタが7、6の時は CELL_波動SP1 を表示させたいので、 Shot設定_PCGコード() で、初期化時にあらかじめ算出しておいたPCGコード pcg_num を設定します。
 よく見るとわかると思うのですが、この部分の処理は初期化時とほぼ同じです。 つまり、初期化部分で、いくつか無駄な処理をしているというわけです。具体的には 25,27,29,30行です。 このソースではわかりやすさを優先させているので、若干こういった無駄なコーディングが存在します。
 52、53行はカウンタが6の時の処理です。 が、カウンタ7の時と同じセルを表示するので、何もする必要はありません。
 54〜58行はカウンタが5の時の処理です。表示するSHOTセルを CELL_波動SP2 に変更しています。 CELL_波動SP2 の画像データは、カウンタが7の時に展開済みですから、 Pcg転送_セル画像() の必要はありません。 その代わりに、pcg_num に4を足した値をShot設定_PCGコード()で設定しています。 こうすることでユーザーPCG定義エリアの4〜7に展開してある画像データを表示に使います。
 59、60行はカウンタが4の時の処理ですが、何も行いません。
 61〜67行はカウンタが3の時の処理です。カウンタが7の時の処理とほぼ同じです。
使用するセルが CELL_波動SP3、CELL_波動SP4 に替わっているだけです。 ここから74行まではとくに説明の必要はないと思います。
 75、76行はカウンタが0以下の時の処理です。カウンタがマイナス値になることは有り得ないのですが。 カウンタが0の時は、カウンタを8に戻し、アニメーションをループさせます。
 78〜81行はSHOTセルとは関係ありません。移動と表示範囲外チェックを行います。

・91〜98行:SHOT_CMD_表示に応答する部分です。 基本的に、ここでは表示のみを行います。座標移動やカウンタの変化等をさせてはいけない事になっています。

95行:SHOT_CMD_状態変化で必要な情報を全てセットしているので、 ここですることはShot設定_表示セル() の呼び出しだけです。


 SHOTセルを用いる事で、従来よりかなり処理が簡略化されることがわかったのではないでしょうか。 基本的な使い方しか説明しませんでしたが、応用はいくらでも利きますから工夫してみると面白いでしょう。


余談:SFXVIのスプライト管理

 説明中に「極力 SP_BLK_飛び道具 以外の使用は避けた方がよいでしょう」 と書かれていたのをおぼえているでしょうか?

 その理由や仕組みなどを、私の知りうる範囲で説明してみたいと思います。

 X680x0のスプライト最大表示可能数は128個です。X68k登場当時は多く思えたものですが、 この数少ないスプライトを効率よく割り当てなければ、すぐに数が足りなくなってしまいます。

 SFXVIではどのように割り当てているのかというと・・・


 身体セル1と身体セル2は状況によって、システムがどちらのプレイヤーに割り当てるか決定しています。 基本的に攻撃中のキャラが身体セル1に割り当てられるようです。
 また、この割り当ての決定は、SHOT関数の表示、動作関数呼出より後で、OPT_サイクル2の前の様です。 つまり、身体セル表示用スプライトを身体の表示以外に使用するにはOPT_サイクル2の中で、 使用するSP番号を取得しなければならないわけです。

 身体セル表示用スプライトは32枚ずつしか割り当てられていませんが、 身体セルは最大64枚のスプライトを使う事が許されています。 では足りない分はどこから持ってくるのでしょうか?
 これは残像表示用スプライトから持ってきています。 ですから残像表示用スプライトをむやみに使うと、身体の表示が出来なくなる可能性があります。注意しましょう。
 また、残像表示スプライトは誰が何の目的に使用しているか、といった情報を得る手段が有りません。 残像表示用スプライトを残像以外の目的で使う場合、必ず画面に表示される保証はない、ということを覚えておきましょう。

 まだ解明されていないのが、二人のキャラクターの身体セルサイズが64枚だった時どうなるのか、ということです。 64枚×2人でX680x0のスプライトを全て使い切ってしまいます。 身体セルの表示は最優先事項なのでおそらく、ヒットマーク、飛び道具、影などの一切が表示されなくなるはず。 あまり大きいセルを長時間表示するのは控えるのがいいということでしょう。

 飛び道具やヒットマークなどは常時画面に表示されているわけではありません。 使われていないスプライトはどうなるのかというと、単に表示されないだけです。 はっきり言って非常にもったいない。使わずに眠らせておくくらいなら、自由に使わせてくれ! と声を大にして言いたいくらいなのですが、互換性の問題もあってどうしようもないというのが現実なんでしょう。

 以上、あまり役に立たない話でした。

ひとつ前にもどるSFXVI Worldにもどるトップページにもどる