通常のショット処理ができたので、続けて、いろんな種類のショットを作ることにした。
某グラディウスシリーズのショット系を実装する。
大体、こんな感じ。
- NORMAL 前方
- DOUBLE 前方+前方斜め上
- TAIL GUN 前方+後方
- VERTICAL 前方+上方
- DOWN DOUBLE 前方+前方斜め下
- BACK DOUBLE 前方+後方斜め上
- FREEWAY 前方+レバー入力方向
ショットは、画面上には2発までという、グラディウスの仕様に合わせてみた。
ノーマルショット以外は、どちらか1発だけ当たる、もしくは画面外に出ても、もう1発が残っていると、発射できない。
まずダブルの実装からスタート。
画面上には、2つしか自弾用スプライトが要らないということで、es_exnew命令で空きスプライト番号を探すのを、1番号ずつ、2回実行することにしてみた。
es_exnew snum1,100,100,1 es_exnew snum2,101,101,1
こうすると、片方の弾が画面外に消えて空きになったとしても、もう一方が画面外に残っていれば、空き無しということで、-1が返ってくる。
なので、両方ともが0を超える値になる=弾が画面外に1発もない、ことになる。
前方のショットは、右方向に進む。なので、es_adir命令で、方向と進む速度を指定する。
方向の指定にちょっとクセがある。下方向を0として、右回りに数字が大きくなっていく。その分割数は64*1。
右方向に移動するには、90度回転した数字を指定する必要がある。なので、90÷(360÷64)=16を指定する。
これだと、後でソースを見たときに、なんのこっちゃわからん!と思い、無駄とは思いつつ、8方向に番号を振って、その数字×8(64を8分割)を指定するようにした。
方向
543
6✳2 右方向の指定は、2*8=16
701
ダブルの場合は、右上45度に進めたいので、方向は 3*8=24 を指定する。
これで万事OK!と思っていたが、斜め上に発射する弾のグラフィックをどうするかで迷った。
初めは、GIMPで45度ずつ回転した画像を用意すればいいや。と思っていたが、そのままだと当たり判定に問題が出る。
斜め方向の画像は対角線になるから、それを含む矩形は、当然大きくなる。
そうすると、ショットの画像以外のブランク部分にも当たり判定が付く。いわゆる詐欺判定wってやつになる。
スプライトの当たり判定は、パーセンテージ指定で小さくできるけど、おそらく中央から同心円状に広がるはず。
(おそらくというのは、何パーセントならこんな感じの当たり判定になるという情報がどこにもない!)
それでは、弾のグラフィック部分のみに当たり判定を指定するのは難しくなる。
ということで、右方向の自弾グラフィックを、es_setrotで回転することにした。これならes_checkで回転角度も考慮したチェックになる。
ただ、ここでも回転角度は、360度を64分割した値で指定する必要がある。
ここでさらに一癖あり。今度は水平方向が0で、右回りになる。es_adirでは、下が0基準なので、さっき割り振った数字とまた違う値になる。
これも計算式は不要なんだけど、割り振った方向数字と一致するように記述した。
右斜め上は3番。90度分マイナスする必要があるので、(3-2)*8と指定するようにした。
一応方針は決まったので、同じ要領で残りのショットも作った。
とりあえずswitch~caseで、処理を分岐したたけど、1つ作ってコピペしたので、処理や条件式などに無駄があるのはご愛敬でw
#include "hsp3dish.as" #include "m_joystick.hsp" screen 0,800,600,0 title "シューティングっぽい何か(仮称)" es_ini ;スプライト初期化 buffer 2 picload "bg.png" ;仮背景画像 buffer 3 ;バッファを作成 picload "player.png" ;自機画像を読み込み es_size 64,64,1 ;パターンサイズ、ヒット領域1%で es_pat 0,0,0 ;パターンを読み込み buffer 4 ;バッファを作成 picload "shot.png" ;ショット画像を読み込み es_size 64,64,20 es_pat 1,0,0 gsel 0 ;操作バッファを0に戻す px=300:py=200 ;自機のXY座標 es_set 0,px,py,0,0,1 ;自機のスプライトをセット gamecnt=0 dim houkou,3,3 ;FREEWAY用 houkou(0,0)=5:houkou(1,0)=4:houkou(2,0)=3 houkou(0,1)=6:houkou(1,1)=2:houkou(2,1)=2 houkou(0,2)=7:houkou(1,2)=0:houkou(2,2)=1 sdim weapon_name,7 weapon_name="NORMAL","DOUBLE","TAIL GUN","VERTICAL","DOWN DOUBLE","BACK DOUBLE","FREEWAY" es_area 0,0,800,600 ;スプライトの領域設定 move_angle=2 ;自機の弾の方向 weapon_type=0 ;ショット種類 *main redraw 0 ix=1:iy=1:sht=0 ;移動の相対方向フラグとショットボタンフラグ ;Stick key,1+2+4+8 JStick key,1+2+4+8 if key&128 : end ;ESCでゲーム終了(暫定) if key&64 : gosub *shotchange ;Ctrlでショット種別変更 if key&1 : px=px-5 : ix=0 ;カーソル左 if key&4 : px=px+5 : ix=2 ;カーソル右 if key&2 : py=py-5 : iy=0 ;カーソル上 if key&8 : py=py+5 : iy=2;カーソル下 if (key&2048) or (key&8192) : sht=1 ;ボタンZ、Cとボタン1、ボタン3(6BパッドのA) px=limit(px,0,800-64) py=limit(py,0,600-64) if (ix != 1 or iy != 1) : move_angle=houkou(ix,iy) ;FREEWAY用 pos 0,0 gcopy 2,0,0,800,600 color 255,0,0:gmode 2 pos 0,0:mes "アングル="+str(move_angle) : mes "ix="+str(ix)+" iy="+str(iy) : mes str(weapon_type)+":"+weapon_name(weapon_type) gamecnt++ es_pos 0,px,py gosub *shoot ;自弾の発射 es_draw redraw 1 await 1000/60 goto *main *shoot if sht=1 { es_exnew snum1,100,100,1 es_exnew snum2,101,101,1 switch weapon_type case 0 ;ノーマルショット if snum1>0 or snum2>0 { ;ショットの空きがあれば ;どっちのスプライト番号が空いてるかを判定 if snum1>0 : snum=100 if snum2>0 : snum=101 es_set snum,px,py,1 es_type snum,2 ;弾はタイプ2 es_adir snum,2*8,1000 } swbreak case 1 ;ダブル if snum1>0 and snum2>0 { ;ショットの空きがあれば ;前方 es_set snum1,px+32,py,1 es_type snum1,2 ;弾はタイプ2 es_adir snum1,2*8,1000 ;斜め上 es_set snum2,px+40,py,1 es_setrot snum2,(3-2)*8 ;ショットグラフィックを回転 es_type snum2,2 ;弾はタイプ2 es_adir snum2,3*8,1000 } swbreak case 2 ;テイルガン if snum1>0 and snum2>0 { ;ショットの空きがあれば ;前方 es_set snum1,px+32,py,1 es_type snum1,2 ;弾はタイプ2 es_adir snum1,2*8,1000 ;後方 es_set snum2,px,py,1 es_setrot snum2,(6-2)*8 ;ショットグラフィックを回転 es_type snum2,2 ;弾はタイプ2 es_adir snum2,6*8,1000 } swbreak case 3 ;バーティカル if snum1>0 and snum2>0 { ;ショットの空きがあれば ;前方 es_set snum1,px+32,py,1 es_type snum1,2 ;弾はタイプ2 es_adir snum1,2*8,1000 ;上 es_set snum2,px,py-20,1 es_setrot snum2,(4-2)*8 ;ショットグラフィックを回転 es_type snum2,2 ;弾はタイプ2 es_adir snum2,4*8,1000 } swbreak case 4 ;ダウンダブル if snum1>0 and snum2>0 { ;ショットの空きがあれば ;前方 es_set snum1,px+32,py,1 es_type snum1,2 ;弾はタイプ2 es_adir snum1,2*8,1000 ;斜め下 es_set snum2,px+40,py,1 es_setrot snum2,(1-2)*8 ;ショットグラフィックを回転 es_type snum2,2 ;弾はタイプ2 es_adir snum2,1*8,1000 } swbreak case 5 ;バックダブル if snum1>0 and snum2>0 { ;ショットの空きがあれば ;前方 es_set snum1,px+32,py,1 es_type snum1,2 ;弾はタイプ2 es_adir snum1,2*8,1000 ;斜め上 es_set snum2,px,py,1 es_setrot snum2,(5-2)*8 ;ショットグラフィックを回転 es_type snum2,2 ;弾はタイプ2 es_adir snum2,5*8,1000 } swbreak case 6 ;フリーウェイ if snum1>0 and snum2>0 { ;ショットの空きがあれば ;前方 es_set snum1,px,py,1 es_type snum1,2 ;弾はタイプ2 es_adir snum1,2*8,1000 ;レバー方向 es_set snum2,px+(move_angle=2)*16,py,1 ;前方の場合だけショットの間隔を少し開ける es_setrot snum2,(move_angle-2)*8 ;ショットグラフィックを回転 es_type snum2,2 ;弾はタイプ2 es_adir snum2,move_angle*8,1000 } swbreak swend } return *shotchange weapontype++ if weapontype>6 : weapontype=0 return
そして、これを動かしてみたのがこれ。ショット種類は暫定でCtrlキーで切り替られるようにしてみた。
youtu.be
さて、次は敵の動きを作ってみるか。
*1:es_iniで変更はできる