新飛び道具の解析

 本来ならAPI付属ドキュメントで解説されているはずですが、 サポートネットが崩壊中ですので、ちょっととりあげてみましょう。

 新飛び道具をいきなり使いこなすのはちょっと無理があるでしょうから、 既存の飛び道具を、新飛び道具に置き換えることを目標に頑張りましょう。

 当然ながら、不明な部分や間違っている部分もあるでしょうが、それは勘弁してください。

 SFXVI4.0β3から実装された新飛び道具は、かなりの拡張が施され、 本格的なシューティングゲームでさえも実現出来そうです。

 まずは、今までのものとどこがかわったのかをみていきましょう。
 これらが目玉とも言える機能です。さらに詳しく違いをあげると
 これを見るとわかるように、かなり色々なことが出来るようになりました。 が、しかし、そのぶんだけ、自分でやらなければならないことが増えたということでもあります。


 旧版の飛び道具はACT_飛び道具に表示のための関数を登録し、飛び道具威力設定()を使うだけで、 使うことが出来ましたが、新飛び道具では使用するための手続きも、今までとかわっています。 旧飛び道具の場合、実体(座標や性能などを保持するデータ領域)はシステムが用意していました。 が、新飛び道具では不特定多数の飛び道具が存在出来るため、飛び道具の実体を自分で用意しなければなりません。 飛び道具の実体は、SHOT構造体の変数になります。

 飛び道具の登録から放出まで解説していきます。

1.main関数内で、SHOT登録()でシステムに登録します。 この登録は画面上に現れる全ての飛び道具について行なわなければなりません。 例えばショットが画面上に10発撃てる場合、10発分全て登録します。

	SHOT登録(&shot_ビーム[0],Proc_ビーム,0);
	SHOT登録(&shot_ビーム[1],Proc_ビーム,1);
	SHOT登録(&shot_レーザー,Proc_レーザー,0);
	SHOT登録(&shot_ミサイル[0],Proc_ミサイル,0);
	SHOT登録(&shot_ミサイル[1],Proc_ミサイル,1);

2.OPT_初期化で飛び道具を全て未使用状態にします。

	SHOT操作(p1,&shot_ビーム[0],SHOT_ACT_NULL,0,0);
	SHOT操作(p1,&shot_ビーム[1],SHOT_ACT_NULL,0,0);
	SHOT操作(p1,&shot_レーザー,SHOT_ACT_NULL,0,0);
	SHOT操作(p1,&shot_ミサイル[0],SHOT_ACT_NULL,0,0);
	SHOT操作(p1,&shot_ミサイル[1],SHOT_ACT_NULL,0,0);

3.動作関数の好きな場所でSHOT操作()を呼び、飛び道具を放出します。

	SHOT操作(p1,&shot_ビーム[0],SHOT_ACT_INIT,0,0);

このような手順になりました。ACT_飛び道具の動作登録は必要なくなっています。

 SHOT登録()、SHOT操作()の解説です。
void SHOT登録( SHOT *shot, short (*proc)(), short sk );
引き数
SHOT *shot;
SHOT構造体変数へのポインタ。変数ひとつにひとつの飛び道具が割り当てられる。
short (*proc)();
飛び道具の動作を記述した関数。
short sk;
サブキー。同じ種類の飛び道具を区別するための番号。 飛び道具動作関数を共有する変数が二つ以上ある場合は それぞれに重複しない番号を割り当てる必要がある。
機能
SHOT構造体変数に動作関数を対応させ、システムに登録する関数。 登録はキャラクタロード時に一度だけ行なえばよい。
戻り値
なし
void SHOT操作( int p, SHOT *shot, short act, short param1, short param2 );
引き数
int p;
キャラハンドラ。通常は自分のハンドラ以外指定する必要はない。
SHIT *shot;
飛び道具の実体となる変数へのポインタ。
short act;
飛び道具の動作(SHOT_ACT ID)を指定する。
short param1;
short param2:
パラメータ。飛び道具動作関数への値の引渡しに使う。
機能
飛び道具の実体に割り当てられた関数の指定の処理を行なわせる。 パラメータは、飛び道具動作関数の作り方次第で意味を持たせることも可能。
戻り値
なし


 そして、飛び道具の実体となるSHOT構造体です。 開発キットのインクルードファイルTYPE.Hをみてみると、SHOT構造体は以下のように定義されています。 コメントは筆者註。ユーザーと書かれているメンバはシステムが値を参照しないもの。 ユーザーが自由に使えます。

typedef  struct
{
  int       owner;		//システム
  short   (*proc)();		//システム
  short     sub_key;		//ユーザー?
  short     type;		//システム
  short     state;		//システム?
  short     pos_x;		//システム
  short     pos_y;		//システム
  short     len_x;		//システム
  short     len_y;		//システム
  short     rect_x;		//システム
  short     rect_y;		//システム
  short     rect_w;		//システム
  short     rect_h;		//システム
  short     pcg_num;		//ユーザー
  short     sp_num;		//ユーザー
  HIT_INFO *hit_info;		//システム
  short     counter;		//ユーザー
  short     drct;		//システム
  short     multi;		//ユーザー?
  short     super;		//システム?
  short     value16;		//ユーザー
  int       value32;		//ユーザー
  void     *ptr_pre;		//システム
  void     *ptr_next;		//システム
  char      reserve[32];	//システム
}
SHOT;
 ownerはキャラハンドラです。
 (*proc)()は上で説明した、飛び道具の動作を記述した関数のアドレスです。
 sub_keyは同じ種類の飛び道具を区別するための番号です。 飛び道具が画面上に二発撃てる場合、それを区別するために使います。
 typeは飛び道具の種類を指定します。種類の指定には「SHOT_TYPE_虚像」 「SHOT_TYPE弾丸」「SHOT_TYPE_盾」の三つが使えます。 「SHOT_TYPE_虚像」を指定すると当たり判定を行なわなくなります。 「SHOT_TYPE_盾」を指定した飛び道具はガードできません。
 stateは飛び道具の状態を表します。「SHOT_STATE_NULL」「SHOT_STATE_VANISH」 「SHOT_TYPE_VALID」のいずれかの値をとります。 「SHOT_STATE_NULL」は画面上に存在しない状態を、「SHOT_STATE_VANISH」は画面上に存在するが消滅処理中である状態、 「SHOT_TYPE_VALID」は画面上に存在し有効状態であることを示しています。
 pos_x,pos_yは飛び道具の存在座標です。
 len_x,len_yは飛び道具に使用するスプライトの枚数です。
 rect_x,rect_yは当たり判定矩形の左上座標で、pos_x,pos_yからのオフセットで表します。
 rect_w,rect_hは当たり判定矩形の横幅と高さです。実際の幅ー1の値を指定します。 矩形の横幅が8ドットなら7になります。
 pcg_numは使用するPCGパターンを指定します。おそらく、システムはこの値を参照しないので、自由に使えます。
 sp_numは使用するSP番号を指定します。これもユーザー参照用なので自由に使えます。
 hit_infoはヒット情報のアドレスです。
 counterは汎用カウンタです。アニメーションカウンタなどに使うのがいいでしょう。
 drctは飛び道具の向きです。
 multiは飛び道具の重なり数です。
 superはスーパーコンボフラグです。
 value16は汎用16ビットカウンタです。−32768〜32767の値をとります。
 value32は汎用32ビットカウンタです。−21億〜21億の値をとります。
 *ptr_pre,*ptr_nextはリンクポインタです。システムが飛び道具を検索するときに参照しますので不用意に書き換えてはいけません。
 reserveはリザーブ領域です。将来拡張用なので使用してはいけません。

 では、基本的な動作のみを行なう飛び道具のソースをあげてみましょう。

SHOT	shot_波動拳;	//飛び道具の実体変数を定義

/*--------------------------------------------------------------------------*/
	void	Sht_ロード(void)
/*--------------------------------------------------------------------------*/
{
    //main()関数から呼ばれるサブルーチン
    //キャラクタロード時に一度だけ行なわれる処理
  SHOT登録(&shot_波動,Proc_波動,0);
}

/*--------------------------------------------------------------------------*/
	void	Sht_初期化(int p1,int p2)
/*--------------------------------------------------------------------------*/
{
    //OPT_初期化で呼ばれるサブルーチン
  飛び道具PALET再設定(p1,同キャラ識別番号(p1));
    //飛び道具パレットは変更しないのでここで一度だけ設定する
  SHOT操作(p1,&shot_波動,SHOT_ACT_NULL,0,0);
}

/*--------------------------------------------------------------------------*/
	void	波動拳( int p1, int p2 )
/*--------------------------------------------------------------------------*/
{
  short	c = カウンタ初期設定( 48 ) ;
  if(c >= 48) {
    身体実体化( p1 );	/*  必殺技は最初、無敵状態にされているので解除する	*/
    表示セル設定( CELL_必殺技S0 );
  }
  else if(c >= 43) {
    表示セル設定( CELL_必殺技S0 );
  }
  else if(c >= 38) {
    表示セル設定( CELL_必殺技S1 );
  }
  else if(c >= 33) {
    表示セル設定( CELL_必殺技S2 );
  }
  else if(c >= 32) {
    if(サブゲージ値( p1 ) == 0) {	/*	飛び道具ゲージが0の場合	*/
      ボイス再生( p1, 0, PCM_振り2 );	/*	空振りの音	*/
      カウンタ設定( p1, 20 );	/*	隙だけは小さくしてやる	*/
    }
    else {
      サブゲージ操作( p1, -1 );	/*	飛び道具ゲージから1減らす	*/
      if(攻撃威力レベル() == 大) {	/*	Aボタンの場合	*/
        SHOT操作(p1,&shot_波動,SHOT_ACT_INIT,15,3 );	/*	高速	*/
        ボイス再生( p1, 1, PCM_必殺技S2 );
      }
      else {	/*	Bボタンの場合	*/
        SHOT操作(p1,&shot_波動,SHOT_ACT_INIT,10,2 );	/*	低速	*/
        ボイス再生( p1, 1, PCM_必殺技S1 );
      }
    }
    表示セル設定( CELL_必殺技S3 );
  }
  else if(c >= 1) {
    表示セル設定( CELL_必殺技S3 );
  }
  else {
    表示セル設定( CELL_必殺技S3 );
    攻撃動作完了( p1, p2 );
  }
}

/*----------------------------------------------------------------------*/
/*	波動拳のSHOT関数						*/
/*......................................................................*/
	short	Proc_波動( int p1, int p2, SHOT *shot,
				short act, short param1, short param2 )
/*----------------------------------------------------------------------*/
{
//  param1  飛び道具の威力
//  param2  飛び道具の飛行速度

static HIT_INFO  hit_info;

  /*..........  無効化(消去)  ..........*/
  if(act == SHOT_ACT_NULL) {
    SHOT状態設定( p1, shot, SHOT_STATE_NULL );  /*  無効状態にする  */
    return ON;
  }

  /*..........  有効化(放出)  ..........*/
  else if(act == SHOT_ACT_INIT) {
    /*  ヒット情報の設定  */
    SHOT状態設定( p1, shot, SHOT_STATE_VALID );  /*  有効状態にする  */
    hit_info.dm=param1;
    hit_info.df=1;
    hit_info.py=12;
    hit_info.bu=0;
    hit_info.st=15;
    hit_info.pt=中;
    hit_info.pcm=PCM_HIT飛;
    hit_info.act=ACT_波動くらい;

    /*  SHOT属性の設定  */
    if(身体方向( p1 ) == 右)	shot->pos_x = 身体X位置( p1 )+52 ;
    else			shot->pos_x = 身体X位置( p1 )-36 ;
    shot->pos_y = BASE_LINE+24;
    shot->type = SHOT_TYPE_弾丸;	/*  タイプ      */
    shot->len_x = 2 ;			/*  X方向のSP数    */
    shot->len_y = 2 ;			/*  Y方向のSP数    */
    shot->rect_x = 24 ;			/*  ヒット矩形の左上X座標(右向き時)  */
    shot->rect_y = 4 ;			/*  ヒット矩形の左上Y座標(右向き時)  */
    shot->rect_w = 2-1 ;		/*  ヒット矩形の幅    */
    shot->rect_h = 24-1 ;		/*  ヒット矩形の高さ    */
    shot->drct = 身体方向( p1 ) ;	/*  移動方向      */
    shot->multi = 1 ;			/*  重なり数      */
    shot->super = OFF ;			/*  超必殺技扱いにしない  */
    shot->hit_info = &hit_info ;	/*  ヒット情報      */
    shot->sp_num = 飛び道具用SP番号();/*  表示用SP番号  */
    shot->pcg_num = PCG番号(OFF,OFF);/*  表示用PCG番号  */
    shot->counter = 0 ;			/*  アニメカウンタをクリア  */
    shot->value16 = param2;		/*  飛行スピード    */
    return ON;
  }

  /*..........  状態変化(移動)  ..........*/
  else if(act == SHOT_ACT_MOVE) {
    if(shot->state == SHOT_STATE_VALID) {	/*  有効状態の場合  */
      if(++shot->counter>=8) shot->counter=0;	/*  アニメカウンタのインクリメント  */
      if(shot->drct == 右)	shot->pos_x += shot->value16 ;	/*  移動  */
      else			shot->pos_x -= shot->value16 ;
      if(shot->pos_x > 256||shot->pos_x< -16) {		/*  無効領域  */
        SHOT操作( p1, shot, SHOT_ACT_NULL, 0,0 );	/*  消去する  */
      }
    }
    else if(shot->state == SHOT_STATE_VANISH ) {	/*  消滅状態の場合  */
      SHOT操作( p1, shot, SHOT_ACT_NULL, 0,0 );		/*  消去する  */
    }
    return ON;
  }

  /*..........  グラフィックの表示  ..........*/
  else if(act == SHOT_ACT_DISP) {
    if(shot->state == SHOT_STATE_VALID) {	/*  有効状態の場合  */
      short	sp=0,pat = 0 ;
      if(shot->counter<2)	return ON;
      else if(shot->counter<4)	;
      else if(shot->counter<6)	return ON;
      else			pat+=4;
      sp=shot->sp_num;
      pat += PCG反転( shot->pcg_num, shot->drct, OFF );
      if(shot->drct==右) {
        表示SP設定(sp++,shot->pos_x+16, shot->pos_y+16, pat++, 1 );
        表示SP設定(sp++,shot->pos_x+32, shot->pos_y+16, pat++, 1 );
        表示SP設定(sp++,shot->pos_x+16, shot->pos_y+32, pat++, 1 );
        表示SP設定(sp  ,shot->pos_x+32, shot->pos_y+32, pat  , 1 );
      }
      else {
        表示SP設定(sp++,shot->pos_x+32, shot->pos_y+16, pat++, 1 );
        表示SP設定(sp++,shot->pos_x+16, shot->pos_y+16, pat++, 1 );
        表示SP設定(sp++,shot->pos_x+32, shot->pos_y+32, pat++, 1 );
        表示SP設定(sp  ,shot->pos_x+16, shot->pos_y+32, pat  , 1 );
      }
    }
    return ON;
  }

  /*..........  衝突時の処理(対SHOT)  ..........*/
  else if(act == SHOT_ACT_HIT_SHOT) {
    SHOT操作( p1, shot, SHOT_ACT_DECREASE, 0,0 );	/*  重なり数を減少する  */
    return ON;
  }

  /*..........  衝突時の処理(対身体)  ..........*/
  else if(act == SHOT_ACT_HIT_BODY) {
    SHOTヒット音再生( p1, p2, hit_info.pcm, PCM_防御 );
    SHOT操作( p1, shot, SHOT_ACT_DECREASE, 0,0 );	/*  重なり数を減少する  */
    return ON;
  }

  /*..........  くらい動作の変更  ..........*/
  else if(act == SHOT_ACT_CHG_ACT) {
    if(身体Y位置( p2 ) < BASE_LINE && !シューティングモード( p2 )) {
      hit_info.act = ACT_空中波動くらい ;
    }
    else {
      /*  相手が地上の場合  */
      hit_info.act = ACT_波動くらい ;
    }
    return ON;
  }

  /*..........  減少時の処理  ..........*/
  else if(act == SHOT_ACT_DECREASE) {
    --shot->multi;	/*  重なり数を減らす  */
    if(shot->multi==0) SHOT操作( p1, shot, SHOT_ACT_VANISH, 0,0 );	/*  消滅する  */
    return ON;
  }

  /*..........  消滅時の処理  ..........*/
  else if(act == SHOT_ACT_VANISH) {
    SHOT標準ヒットマーク表示(p1, shot, shot->pos_x, shot->pos_y+8, OFF, OFF);
    SHOT状態設定( p1, shot, SHOT_STATE_VANISH );	/*  消滅状態にする  */
    return ON;
  }

  /*..........  背景スクロール時の処理  ..........*/
  else if(act == SHOT_ACT_BACK_SCROLL) {
    shot->pos_x += param1 ;	/*  移動する  */
    shot->pos_y += param2 ;
    return ON;
  }
  return OFF;
}
 もともと4タブで書かれたソースを無理矢理変換したので 所々見づらくなっているかもしれませんが、我慢してください。

 飛び道具動作関数をよくみてみると、いくつかの処理が集められています。 これらの処理は、引き数actの内容によって振り分けられていることがわかると思います。 どのような構造になっているかわかるように書いてみます。

short	Proc_波動( int p1, int p2, SHOT *shot,
			short act, short param1, short param2 )
{
//無効(消去)
	if(act==SHOT_ACT_NULL) {
		旧飛び道具において飛び道具消去()を実行した時に行なわれるような
		消去処理。
		ラウンド開始時、画面外はみ出し時などに使います。
		旧版ではシステムが行なっていた処理。
	}

//初期化(放出)
	else if(act==SHOT_ACT_INIT) {
		旧飛び道具において飛び道具威力設定()を実行した時に行なわれるよ
		うな初期化&放出処理。
		旧版ではシステムが行なっていた処理。
	}

//移動
	else if(act==SHOT_ACT_MOVE) {
		飛び道具の移動を行ないます。アニメーションカウンタの更新はここ
		で行ないます。
		画面外はみ出しチェックもここで行ないます。
		また、スーパーコンボの画面暗転時はここは呼び出されません。
		旧版では画面外はみ出しチェックと横方向移動をシステムが、
		その他をACT_飛び道具、VCT_飛び道具消滅処理で行なっていました。
	}

//表示
	else if(act==SHOT_ACT_DISP) {
		飛び道具の表示のみを行ないます。
		スーパーコンボの画面暗転時でもここは呼び出されます。
		飛び道具消滅パターンの表示ここで行ないます。
		旧版ではACT_飛び道具、VCT_飛び道具消滅処理で行なっていた処理。
	}

//衝突時(対SHOT)
	else if(act==SHOT_ACT_HIT_SHOT) {
		相手の飛び道具と衝突した時に呼び出されます。
		主に重なり数の変更を行ないます。
		旧版ではシステムまかせだった処理。
	}

//衝突時(対身体)
	else if(act==SHOT_ACT_HIT_BODY) {
		相手の身体と衝突した時に呼び出されます。
		主にヒット音の再生、重なり数の変更を行ないます。
		旧版ではシステムが行なっていた処理。
	}

//くらい動作変更
	else if(act==SHOT_ACT_CHG_ACT) {
		おそらく、飛び道具がヒットした直後に呼び出されます。
		地上と空中、相手がシューティングモードかどうかで、くらい動作を
		変えたい時はここで変更を行ないます。
		旧版ではシステムが行なっていた処理。
	}

//重なり数減少
	else if(act==SHOT_ACT_DECREASE) {
		サブルーチン的な存在です。
		重なり数の減少はここで行ないます。
		旧版ではシステムが行なっていた処理。
	}

//消滅
	else if(act==SHOT_ACT_VANISH) {
		サブルーチン的な存在です。
		重なり数が0になった瞬間などに呼び出されます。
		消滅パターンのアニメーションカウンタ初期化処理などを行ないます。
		これも旧版ではシステムが処理していました。
	}

//背景スクロール時
	else if(act==SHOT_ACT_BACK_SCROLL) {
		背景がスクロールした時に呼び出されます。
		スクロールにあわせて飛び道具を移動させるために使います。
		これも旧版ではシステムが行なっていました。
	}

}
 波動拳放出の動作関数は基本的に今までのものとかわりません。 飛び道具威力設定()の代わりにSHOT操作()が呼ばれているだけです。 ここではSHOT_ACTIDにSHOT_ACT_INITが指定してありますから、 Proc_波動()のSHOT_ACT_INITが実行されます。この時、パラメータを飛び道具の威力と移動速度として利用しています。
 また、SHOT_ACT_INITでは同時に飛び道具放出位置も設定するので、 飛び道具X位置設定()、飛び道具Y位置設定()が必要なくなっています。

 今までに解説しなかったSHOT関数

short CONFIG状態_飛び道具有限(void)
引き数
なし
機能
コンフィグの飛び道具使用回数制限状態を調べる関数です。
戻り値
ON(飛び道具は有限)
OFF(飛び道具は無限)
short PCGコード(int p, short pal, short pcg_blk, short pcg_ofs, short h, short v, short bg )
引き数
int p;
キャラハンドラ
short pal;
パレットブロックID
short pcg_blk;
PCGブロックID
short pcg_ofs;
PCGパターンのオフセット(0〜31)
short h;
パターンの水平反転フラグ(ON,OFF)
short v;
パターンの垂直反転フラグ(ON,OFF)
short bg;
?とりあえずOFFを指定しておけば問題なし?
機能
指定の情報からPCGコードを作成します。
指定できるパレットブロックIDは以下の通りです。
PAL_身体
PAL_残像
PAL_PCG
PAL_ヒット
PAL_顔
指定できるPCGブロックIDは以下の通りです。
PCG_BLK_飛び道具
PCG_BLK_身体1
PCG_BLK_身体2
戻り値
PCGコード
void SHOT状態設定( int p, SHOT *shot, short state );
引き数
int p;
キャラハンドラ
SHOT *shot;
飛び道具の実体変数へのポインタ
short state;
SHOT状態ID
機能
指定の飛び道具のSHOT状態を変更します。
指定できるSHOT状態IDは以下の通りです。
SHOT_STATE_NULL
SHOT_STATE_VANISH
SHOT_STATE_VALID
戻り値
なし
void 被SHOT衝突矩形( int p, short *x1, short *x2, short *y1, short *y2 );
使用法不明
short SHOT攻撃状態( int p );
引き数
int p;
キャラハンドラ
機能
詳細は不明。
おそらく稼働中の飛び道具プロセス数を返すと思われる。
戻り値
おそらく稼働プロセス数
void SHOTヒット音再生( int p1, int p2, short idHit, short idDef );
引き数
int p1;
自分のキャラハンドラ
int p2;
相手のキャラハンドラ
short idHit;
ヒット時の再生PCM ID
short idDef;
ガード時の再生PCM ID
機能
飛び道具がヒットしたかガードされたかを調べて、それに合わせたPCMを再生します。
戻り値
なし
void SHOT標準ヒットマーク表示( int p, SHOT *shot, short x, short y, short body, short def );
引き数
int p;
キャラハンドラ
SHOT *shot;
飛び道具実体変数へのポインタ
short x;
表示X座標
short y;
表示Y座標
short body;
?とりあえずOFFでいいらしい
short def;
?これもOFFにしておくといいかも
機能
SHOT用のヒットマークを表示します。一度この関数を呼び出すと、 ヒットマークの表示が終わるまで、自動で行ないます。2回以上呼び出す必要はありません。
戻り値
なし

 さて、今回はここまでにさせていただきます。

 この新しい飛び道具は自由度が高くなったぶん、細かいところまで自分で面倒をみる必要があります。 途中でくじけないで、自由に使いこなせるように頑張りましょう。 そうすれば、キャラクタの表現の幅も広がりますからね。

 次回はおそらく複数の飛び道具を動かす方法について解説する予定です。 構造体へのポインタなど、今まで以上にポインタの知識が重要になってくると思うので、 予習しておくのもいいのではないでしょうか。

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