2018年 6月22日
ver.0.007
今回はまとめたものを zipファイルにしました。
表示の 0.006を 0.007にし忘れてますが、最後に気づいてもうめんどくさいのでそのままです。
プログラムやった事のある人なら分かってもらえると思いますけど、バグは必ずある(笑)
今回は敵の種類を 3種類にした。
バギーまたはバイクのイメージ
戦車のイメージ
要塞のイメージ
今回はまだアルゴリズム(挙動のプログラム)自体は全部自機に向かう直線運動だけで変化は無い。
合わせてソースが長くなったので、この辺でいつものフォーマット(プログラム構造)を使う事にした。
こんな感じでソースファイルを分割する
main.hspがメインソースで、ここに put.hsp、shot.hsp、ene.hsp、syoki.hspを #inculude(インクルード、取り込み、この場所にそのファイルのソースを置き換える)する。
put=表示関係全部
shot=ショット、サブウエポン
ene=敵
syoki=初期設定、及びゲームリセット
と言うような感じで分割してる。
ザックリ表にするとこんな感じ
.hspはファイル、赤矢印は呼び出し。
put、shot、eneのソースはラベルを使わず、全部 #deffuncで書かれている。
なので前回やったが、HSPでは呼び出される #deffuncソースが呼び出し箇所の前に書かれなければいけないので、このような配置になってる。
main.hspのソースはこんな感じ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
; 企画第一弾 : 1画面防衛シューティングを作ろう ; var.0.007 #include "hsp3dish.as" ; HSPdishの宣言 gosub *main : end ; メインルーチン #include "put.hsp" ; 表示 #include "shot.hsp" ; 弾 #include "ene.hsp" ; 敵 #include "syoki.hsp" ; 初期設定 *main ; メインルーチン gosub *syoki ; 初期設定 mainf=0 ; メインフラグ while ; ---------- メインルーチン ---------- switch mainf case 0 : gosub *titl : swbreak ; タイトル case 1 : gosub *game_main : swbreak ; ゲーム case 2 : gosub *game_over : swbreak ; ゲームオーバー swend if mainf=3 : _break ; end wend return *titl ; タイトル repeat stick k : if k!0 : mainf=1 : break ; 何か押したらゲームスタート redraw 0 ; 表示 clr ; 画面クリア j_put ; 自機表示 c_put ; 照準表示 scr_put ; スコア表示 pos wx/2-120,wy/2-50 : mes "1画面防衛シューティング" pos wx/2-43,wy/2+30 : mes "var.0.006" redraw 1 await 1000/15 loop return *game_main ; ゲーム repeat ; ゲームループ ======================================== if mainf!1 : break ; ゲームオーバー ; 入力 ---------- x=mousex : y=mousey ; マウス、スマホの座標 stick k,256 ; マウス、スマホクリック repeat 1 ; バルカンの入力判定 if k=256 : kf=1 : kc+ : cx=double(x) : cy=double(y) : break ; 押している if kf=0 : break ; 一度も押してない kf=0 ; 放した、押しフラグリセット esn_set 1 ; 近くの標的をセット if kc>2 : kc=0 : break ; 2フレーム以上押していた kc=0 if jx1<x and x<jx2 and jy1<y and y<jy2 : autof=(autof+1)\2 : esn_set 0 : break ; 自機の位置の場合、オート切り替え if vc=0 or vcn>0 : break ; 弾切れ or バルカン発射中 vcn+=vnb loop ; 照準 ---------- x2=ex(esn)-cx : y2=ey(esn)-cy nd=sqrt(x2*x2+y2*y2); 標的と照準の距離 repeat 1 ; 照準の移動 if autof=0 : cx=double(x) : cy=double(y) : break ; マニュアルの場合 if nd<csp : cx=ex(esn) : cy=ey(esn) : break ; ↑ 標的が照準スピード以下の距離なら、照準座標を標的の座標にする ; ↓ そうでないなら照準スピード分動かす xn=double(ex(esn)-cx) ; 一番近い敵と照準の距離x yn=double(ey(esn)-cy) ; 一番近い敵と照準の距離y rad=atan(xn,yn) ; 距離xyから角度を求める cx+=sin(rad)*csp ; 照準移動x cy+=cos(rad)*csp ; 照準移動y loop ; 出現 ---------- s_set ; ショット出現 v_set ; バルカン出現 e1_set ; 敵1出現 e2_set ; 敵2出現 e3_set ; 敵3出現 ; 移動処理 ---------- s_syo ; ショット処理 v_syo ; バルカン処理 e_syo ; 敵処理テーブル redraw 0 ; 表示 ---------- clr ; 画面クリア e_put ; 敵表示 j_put ; 自機表示 s_put ; ショット表示 v_put ; バルカン表示 c_put ; 照準表示 scr_put ; スコア表示 redraw 1 await 1000/15 ; ウエイト、FPS 15 loop ; ==================================================== return *game_over ; ゲームオーバー repeat stick k : if k!0 : mainf=0 : break ; 何か押したらタイトルへ redraw 0 ; 表示 clr ; 画面クリア e_put ; 敵表示 j_put ; 自機表示 s_put ; ショット表示 v_put ; バルカン表示 c_put ; 照準表示 scr_put ; スコア表示 pos wx/2-43,wy/2+50 : mes "GAME OVER" redraw 1 await 1000/15 ; ウエイト、FPS 15 loop reset ; ゲーム再初期化 return |
while文(繰り返し)と switch文(値分岐)による mainf値分岐で、タイトルとメインゲームとゲームオーバーのモードを切り替えている。
今回は表示関係を putに分離して、それぞれのモード事に表示プログラムを呼び出しで表示している。
putのソース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
; 表示 #deffunc clr ; 画面クリア color 1,1,1 : boxf : color 255,255,255 return #deffunc j_put ; 自機表示 pos jx,jy if autof=0 : celput jw1 ; 自機、マニュアル if autof=1 : celput jw2 ; 自機、オート return #deffunc e_put ; 敵表示 repeat eb : en=cnt ; 敵No. if ef(en)=0 : continue ; 無い pos ex(en),ey(en) if ef(en)=1 : celput e1w,,,,er(en) ; 敵 if ef(en)=2 : celput e2w,,,,er(en) ; 敵 if ef(en)=3 : celput e3w,,,,er(en) ; 敵 loop return #deffunc s_put ; ショット表示 repeat sb ; ショット if sf(cnt)=0 : continue ; 無い pos sx(cnt),sy(cnt) if sf(cnt)=-1 : celput hw,,,,sr(cnt) : sf(cnt)=0 : continue ; フラグリセット celput sw ; ショット loop return #deffunc v_put ; バルカン表示 repeat vb ; バルカン if vf(cnt)=0 : continue ; 無い pos vx(cnt),vy(cnt) if vf(cnt)=-1 : celput hw,,,,vr(cnt) : vf(cnt)=0 : continue ; フラグリセット celput vw,,,,vr(cnt) ; バルカン loop pos 10,wy-20 : mes vc ; バルカンの残弾表示 repeat vc/10 pos 50+cnt*6,wy-12 : celput vw if cnt=100 : break ; 最大 loop return #deffunc c_put ; 照準表示 pos cx,cy : celput cw ; 照準 return #deffunc scr_put ; スコア表示 pos wx-300,5 : mes "SCORE "+scr pos wx-150,5 : mes "HI SCORE "+hiscr return |
syokiのソース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
*syoki ; 初期設定 randomize ; 乱数の初期化 pai=3.141593 pai2=pai*2 rad45=0.7853982 ; ラジアンで45度 rad90=1.5707965 ; ラジアンで90度 wx=640 ; 画面の大きさx wy=360 ; 画面の大きさy gmode 2 jw1=1 : jo=20 : jo2=jo/2 ; 自機、マニュアル celload "jiki_3.png",jw1 celdiv jw1,jo,jo,jo2,jo2 jw2=2 ; 自機、オート celload "jiki_2.png",jw2 celdiv jw2,jo,jo,jo2,jo2 sw=3 : so=6 : so2=so/2 ; ショット celload "shot_1.png",sw celdiv sw,so,so,so2,so2 e1w=4 : e1o=20 : e1o2=e1o/2 ; 敵1 celload "ene_1.png",e1w celdiv e1w,e1o,e1o,e1o2,e1o2 e2w=5 : e2o=24 : e2o2=e2o/2 ; 敵2 celload "ene_2.png",e2w celdiv e2w,e2o,e2o,e2o2,e2o2 e3w=6 : e3o=64 : e3o2=e3o/2 ; 敵3 celload "ene_3.png",e3w celdiv e3w,e3o,e3o,e3o2,e3o2 cw=7 : co=32 : co2=co/2 ; カーソル celload "csr_2.png",cw celdiv cw,co,co,co2,co2 hw=8 : ho=16 : ho2=ho/2 ; ヒット celload "hit_4.png",hw celdiv hw,ho,ho,ho2,ho2 vw=9 : vo=16 : vo2=vo/2 ; バルカン celload "vulcan_1.png",vw celdiv vw,vo,vo,vo2,vo2 ; 自機 ---------- jx=wx/2 ; プレイヤーの座標x jy=wy/2 ; プレイヤーの座標y jx1=jx-jo2 ; 自機左座標 jx2=jx+jo2 ; 自機右座標 jy1=jy-jo2 ; 自機上座標 jy2=jy+jo2 ; 自機下座標 cx=double(jx) ; 照準座標x cy=double(jy) ; 照準座標y csp=20.0 ; 照準スピード esn=0 ; 標的 autof=1 ; オートフラグ(0=マニュアル、1=オート) ; SHOT ---------- sb=20 ; ショット最大数 dim sf,sb ; ショット発射フラグ ddim sx,sb ; ショット座標x ddim sy,sb ; ショット座標y ddim sdx,sb ; ショット移動量x ddim sdy,sb ; ショット移動量y ddim sr,sb ; 向き dim sxb,sb ; 終点座標x dim syb,sb ; 終点座標y ddim skn,sb ; 現移動距離 ddim skb,sb ; 最終移動距離 ssp=20.0 ; スピード skc=3 ; 1フレームで移動計算する回数 sc=0 ; 出現カウント scb=0 ; 発射間隔(フレーム) sp=6 ; パワー su=32 ; 揺れ幅(集弾値) ; VULCAN ---------- vb=30 ; バルカン最大数 dim vf,vb ; バルカン発射フラグ ddim vx,vb ; バルカン座標x ddim vy,vb ; バルカン座標y ddim vdx,vb ; バルカン移動量x ddim vdy,vb ; バルカン移動量y ddim vr,vb ; 向き vkc=3 ; 1フレームに出現する数 vsp=20.0 ; スピード vp=5 ; パワー vu=30 ; 揺れ幅(集弾値) vnb=140 ; 1クリックで発射される数 vc=0 ; 残弾数 vcb=20 ; 1つ敵を倒した時に増える数 ; ENEMY ---------- eb=40 ; 敵最大数 dim ef,eb ; 出現フラグ dim ehp,eb ; 耐久度 ddim ex,eb ; 敵座標x ddim ey,eb ; 敵座標y ddim edx,eb ; 敵移動量x ddim edy,eb ; 敵移動量y ddim er,eb ; 向き dim escr,4 ; スコア e1hpb=24 ; 耐久度 e1sp=1.0 ; 敵1スピード e1c=0 ; 出現カウント e1cb=10 ; 出現間隔(フレーム) escr(1)=10 ; スコア e2hpb=300 ; 耐久度 e2sp=0.5 ; 敵2スピード e2c=50 ; 出現カウント e2cb=70 ; 出現間隔(フレーム) escr(2)=100 ; スコア e3hpb=5000 ; 耐久度 e3sp=0.1 ; 敵2スピード e3c=400 ; 出現カウント e3cb=2000 ; 出現間隔(フレーム) escr(3)=2000 ; スコア scr=0 ; スコア hiscr=0 ; ハイスコア kf=0 ; キーを押してるかフラグ kc=0 ; 何フレームキーを押してるか return #deffunc reset ; ゲーム再初期化 cx=double(jx) ; 照準座標xリセット cy=double(jy) ; 照準座標yリセット repeat sb : sf(cnt)=0 : loop ; ショットリセット repeat vb : vf(cnt)=0 : loop ; バルカンリセット vcn=0 : vc=0 ; 残弾リセット repeat eb : ef(cnt)=0 : loop ; 敵リセット scr=0 ; スコアリセット esn=0 ; 標的リセット return |
shotのソース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
; ショット -------------------- #deffunc esn_set int esn_setf ; 標的設定 esn=0 ; 一番近い敵No. nd1=1000.0 ; 一番近い距離 repeat eb if ef(cnt)=0 : continue if esn_setf=0 : x2=ex(cnt)-jx : y2=ey(cnt)-jy ; 自機に近い if esn_setf=1 : x2=ex(cnt)-cx : y2=ey(cnt)-cy ; 照準に近い nd2=sqrt(x2*x2+y2*y2); 距離 if nd2<nd1 : nd1=nd2 : esn=cnt loop return ; SHOT -------------------- #deffunc s_set ; 出現 if sc>0 : sc- : return ; ウエイト中 sc=scb ; 発射ウエイトリセット f=0 ; 空きフラグ確認 ---------- repeat sb : sn=cnt ; ショットNo. if sf(sn)=0 : sf(sn)=1 : f=1 : break ; 使用フラグon loop if f=0 : return ; 空きが無い sx(sn)=double(jx) : sy(sn)=double(jy) ; 初期座標 xx=int(cx)-su/2+rnd(su) ; ショットの着弾点x yy=int(cy)-su/2+rnd(su) ; ショットの着弾点y xn=double(xx-jx) ; 自機とマウスの距離x yn=double(yy-jy) ; 自機とマウスの距離y rad=atan(xn,yn) ; 距離xyから角度を求める sr(sn)=-rad+pai ; 向き sdx(sn)=sin(rad)*ssp ; 角度とスピードから移動量xを求める sdy(sn)=cos(rad)*ssp ; 角度とスピードから移動量yを求める sxb(sn)=xx : syb(sn)=yy ; 終点座標 skn(sn)=0.0 ; 現移動距離をリセット x2=xx-jx : y2=yy-jy skb(sn)=sqrt(x2*x2+y2*y2); 最終移動距離 return #deffunc s_syo ; 移動処理 repeat sb : sn=cnt ; ショット移動処理 if sf(sn)=0 : continue ; 無し repeat skc : cnt2=cnt ; 1ショットの移動繰り返し ==================== sx(sn)+=sdx(sn) ; xの移動 sy(sn)+=sdy(sn) ; yの移動 skn(sn)+=ssp ; どれだけ距離を進んだか if skn(sn)>=skb(sn) { ; 終点判定 sx(sn)=double(sxb(sn)) sy(sn)=double(syb(sn)) sf(sn)=-1 ; 着弾フラグ } sx1=int(sx(sn))-so2 ; ショット左座標 sx2=int(sx(sn))+so2 ; ショット右座標 sy1=int(sy(sn))-so2 ; ショット上座標 sy2=int(sy(sn))+so2 ; ショット下座標 ; 敵との当たり判定 repeat eb : en=cnt ; 敵No, if ef(en)=0 : continue if ef(en)=1 : eo2=e1o2 ; 敵1の時の大きさ if ef(en)=2 : eo2=e2o2 ; 敵2の時の大きさ if ef(en)=3 : eo2=e3o2 ; 敵3の時の大きさ ex1=int(ex(en))-eo2 ; 敵左座標 ex2=int(ex(en))+eo2 ; 敵右座標 ey1=int(ey(en))-eo2 ; 敵上座標 ey2=int(ey(en))+eo2 ; 敵下座標 if sx1<ex2 and ex1<sx2 and sy1<ey2 and ey1<sy2 { ; 当たり判定 sf(sn)=-1 ; 着弾フラグ ehp(en)-=sp ; 耐久度- if ehp(en)<=0 { ; 倒したか scr+=escr(ef(en)) ; スコア ef(en)=0 ; 当たった敵とショットを消す esn_set 0 ; 次の標的を探す vc+=vcb ; バルカンの残弾数を増やす if hiscr<scr : hiscr=scr ; ハイスコアの更新 break } } loop if sf(sn)=1 : if sx2<0 or wx<sx1 or sy2<0 or wy<sy1 : sf(sn)=0 : break ; 場外でフラグ off if sf(sn)=-1 : break ; 着弾してる loop ; ==================== loop return ; VULCAN -------------------- #deffunc v_set ; 出現 repeat vkc : cnt2=cnt ; 1フレームに発射される数 if vcn=0 or vc=0 : break ; 発射要求数、または残弾が0 repeat vb : vn=cnt if vf(vn)!0 : continue ; 使用中 vcn- ; 発射要求数- vc- : if vc=0 : vcn=0 ; 残弾- vf(vn)=1 ; 使用フラグon vx(vn)=double(jx) : vy(vn)=double(jy) ; 初期座標 xn=cx-double(jx) ; 自機とマウスの距離x yn=cy-double(jy) ; 自機とマウスの距離y rd=double(-(vu/2)+rnd(vu+1))/100.0 ; 揺れ幅(ラジアン) rad=atan(xn,yn)+rd ; 距離xyから角度を求める vr(vn)=-rad+pai ; 向き vdx(vn)=sin(rad)*vsp ; 角度とスピードから移動量xを求める vdy(vn)=cos(rad)*vsp ; 角度とスピードから移動量yを求める repeat cnt2 vx(vn)-=vdx(vn) ; 始点座標をバックさせておくx vy(vn)-=vdy(vn) ; 始点座標をバックさせておくy loop break loop loop return #deffunc v_syo repeat vkc ; vkc回移動 repeat vb : vn=cnt ; バルカン移動処理 if vf(vn)=0 : continue ; 無し vx(vn)+=vdx(vn) ; xの移動 vy(vn)+=vdy(vn) ; yの移動 vx1=int(vx(vn))-vo2 ; バルカン左座標 vx2=int(vx(vn))+vo2 ; バルカン右座標 vy1=int(vy(vn))-vo2 ; バルカン上座標 vy2=int(vy(vn))+vo2 ; バルカン下座標 repeat eb : en=cnt ; 敵との当たり判定 if ef(en)=0 : continue if ef(en)=1 : eo2=e1o2 ; 敵1の時の大きさ if ef(en)=2 : eo2=e2o2 ; 敵2の時の大きさ if ef(en)=3 : eo2=e3o2 ; 敵3の時の大きさ ex1=int(ex(en))-eo2 ; 敵左座標 ex2=int(ex(en))+eo2 ; 敵右座標 ey1=int(ey(en))-eo2 ; 敵上座標 ey2=int(ey(en))+eo2 ; 敵下座標 if vx1<ex2 and ex1<vx2 and vy1<ey2 and ey1<vy2 { vf(vn)=-1 ehp(en)-=vp ; 耐久度- if ehp(en)<=0 { ; 倒したか scr+=escr(ef(en)) ; スコア ef(en)=0 ; 敵を消す esn_set 1 ; 次の標的を探す if hiscr<scr : hiscr=scr ; ハイスコアの更新 break } } loop if vf(vn)=1 : if vx2<0 or wx<vx1 or vy2<0 or wy<vy1 : vf(vn)=0 : continue ; 場外でフラグ off if vf(vn)=-1 : continue ; 着弾してる loop loop return |
eneのソース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
; ENEMY -------------------- #deffunc e1_set ; 出現 if e1c>0 : e1c- : return ; ウエイト中 e1c=e1cb ; 出現ウエイトリセット f=0 ; 空きフラグ確認 ---------- repeat eb : en=cnt ; 敵No. if ef(en)=0 : ef(en)=1 : f=1 : break ; 使用フラグon loop if f=0 : return ; 空きが無い ehp(en)=e1hpb ; 耐久力 r=rnd(4) ; 出現方向 if r=0 : exs=rnd(wx)-e1o2 : eys=0-e1o2 ; 上 if r=1 : exs=rnd(wx)-e1o2 : eys=wy+e1o2 ; 下 if r=2 : exs=-e1o2 : eys=rnd(wy)-e1o2 ; 左 if r=3 : exs=wx+e1o2 : eys=rnd(wy)-e1o2 ; 右 ex(en)=double(exs) ; 初期位置x ey(en)=double(eys) ; 初期位置y xn=double(jx-exs) ; 敵と自機の距離x yn=double(jy-eys) ; 敵と自機の距離y rad=atan(xn,yn) ; 距離xyから角度を求める edx(en)=sin(rad)*e1sp ; 角度とスピードから移動量xを求める edy(en)=cos(rad)*e1sp ; 角度とスピードから移動量yを求める er(en)=-rad+pai ; 向き return #deffunc e2_set ; 出現 if e2c>0 : e2c- : return ; ウエイト中 e2c=e2cb ; 出現ウエイトリセット f=0 ; 空きフラグ確認 ---------- repeat eb : en=cnt ; 敵No. if ef(en)=0 : ef(en)=2 : f=1 : break ; 使用フラグon loop if f=0 : return ; 空きが無い ehp(en)=e2hpb ; 耐久力 r=rnd(4) ; 出現方向 if r=0 : exs=rnd(wx)-e2o2 : eys=0-e2o2 ; 上 if r=1 : exs=rnd(wx)-e2o2 : eys=wy+e2o2 ; 下 if r=2 : exs=-e2o2 : eys=rnd(wy)-e2o2 ; 左 if r=3 : exs=wx+e2o2 : eys=rnd(wy)-e2o2 ; 右 ex(en)=double(exs) ; 初期位置x ey(en)=double(eys) ; 初期位置y xn=double(jx-exs) ; 敵と自機の距離x yn=double(jy-eys) ; 敵と自機の距離y rad=atan(xn,yn) ; 距離xyから角度を求める edx(en)=sin(rad)*e2sp ; 角度とスピードから移動量xを求める edy(en)=cos(rad)*e2sp ; 角度とスピードから移動量yを求める er(en)=-rad+pai ; 向き return #deffunc e3_set ; 出現 if e3c>0 : e3c- : return ; ウエイト中 e3c=e3cb ; 出現ウエイトリセット f=0 ; 空きフラグ確認 ---------- repeat eb : en=cnt ; 敵No. if ef(en)=0 : ef(en)=3 : f=1 : break ; 使用フラグon loop if f=0 : return ; 空きが無い ehp(en)=e3hpb ; 耐久力 r=rnd(4) ; 出現方向 if r=0 : exs=rnd(wx)-e3o2 : eys=0-e3o2 ; 上 if r=1 : exs=rnd(wx)-e3o2 : eys=wy+e3o2 ; 下 if r=2 : exs=-e3o2 : eys=rnd(wy)-e3o2 ; 左 if r=3 : exs=wx+e3o2 : eys=rnd(wy)-e3o2 ; 右 ex(en)=double(exs) ; 初期位置x ey(en)=double(eys) ; 初期位置y xn=double(jx-exs) ; 敵と自機の距離x yn=double(jy-eys) ; 敵と自機の距離y rad=atan(xn,yn) ; 距離xyから角度を求める edx(en)=sin(rad)*e3sp ; 角度とスピードから移動量xを求める edy(en)=cos(rad)*e3sp ; 角度とスピードから移動量yを求める er(en)=-rad+pai ; 向き return #deffunc e1_syo ; 敵1移動処理 ex(en)+=edx(en) : ey(en)+=edy(en) ; 移動 ex1=int(ex(en))-e1o2 ; 敵左座標 ex2=int(ex(en))+e1o2 ; 敵右座標 ey1=int(ey(en))-e1o2 ; 敵上座標 ey2=int(ey(en))+e1o2 ; 敵下座標 if jx1<ex2 and ex1<jx2 and jy1<ey2 and ey1<jy2 { mainf=2 : return ; 自機と当たりで GAME OVER } if ex2<0 or wx<ex1 or ey2<0 or wy<ey1 : ef(en)=0 ; 枠外でフラグ off return #deffunc e2_syo ; 敵2移動処理 ex(en)+=edx(en) : ey(en)+=edy(en) ; 移動 ex1=int(ex(en))-e2o2 ; 敵左座標 ex2=int(ex(en))+e2o2 ; 敵右座標 ey1=int(ey(en))-e2o2 ; 敵上座標 ey2=int(ey(en))+e2o2 ; 敵下座標 if jx1<ex2 and ex1<jx2 and jy1<ey2 and ey1<jy2 { mainf=2 : return ; 自機と当たりで GAME OVER } if ex2<0 or wx<ex1 or ey2<0 or wy<ey1 : ef(en)=0 ; 枠外でフラグ off return #deffunc e3_syo ; 敵3移動処理 ex(en)+=edx(en) : ey(en)+=edy(en) ; 移動 ex1=int(ex(en))-e3o2 ; 敵左座標 ex2=int(ex(en))+e3o2 ; 敵右座標 ey1=int(ey(en))-e3o2 ; 敵上座標 ey2=int(ey(en))+e3o2 ; 敵下座標 if jx1<ex2 and ex1<jx2 and jy1<ey2 and ey1<jy2 { mainf=2 : return ; 自機と当たりで GAME OVER } if ex2<0 or wx<ex1 or ey2<0 or wy<ey1 : ef(en)=0 ; 枠外でフラグ off return #deffunc e_syo ; 敵移動処理テーブル repeat eb : en=cnt ; 敵No, if ef(en)=0 : continue ; 無し switch ef(en) case 1 : e1_syo : swbreak ; 敵1移動処理 case 2 : e2_syo : swbreak ; 敵2移動処理 case 3 : e3_syo : swbreak ; 敵3移動処理 swend loop return |
こんな感じで分割すると、敵とかショットの種類が増えても管理が分かりやすくなる。
この構造論(フォーマット)を使えば、どんなゲームでも大体これで作れてしまう。
自分は goto文は使わない、goto文は Javaとか Cではたぶん使われなくて、全部呼び出し returnで構成されてると思う、たぶん。
プログラム解説
メイン
while ; ———- メインルーチン ———- switch mainf case 0 : gosub *titl : swbreak ; タイトル case 1 : gosub *game_main : swbreak ; ゲーム case 2 : gosub *game_over : swbreak ; ゲームオーバー swend if mainf=3 : _break ; end wend mainfの値を切り替える事により、モードを切り替える。 OP、EDとか、ストーリーの挿入とか、戦闘前のパワーアップや面セレクトの待機画面とかの切り替えも考えられる。 もう少し複雑なソースの場合、例えば RPGなんかだとゲームルーチン内にもう一つルーチンを作って、フィールド移動、町探索、戦闘なんかを切り替えたりする。 前回そうしたつもりだったが、そうでもなかったみたい。
ショットと敵の出現と移動処理を、全部呼び出しで行う。
表示関係も全て呼び出しで行う。 |
ene.hsp 敵
#deffunc e_syo ; 敵移動処理テーブル repeat eb : en=cnt ; 敵No, if ef(en)=0 : continue ; 無し switch ef(en) case 1 : e1_syo : swbreak ; 敵1移動処理 case 2 : e2_syo : swbreak ; 敵2移動処理 case 3 : e3_syo : swbreak ; 敵3移動処理 swend loop ef(en)のフラグが 1なら敵 1、2なら敵 2、3なら敵 3の移動処理を実行する。 要するに efとか ex,eyのような変数は、全部の敵で使いまわし。 つまり ef(n)=敵フラグ 0=無し と言う風になってる。 移動処理を分けるのは今回は設定してないが、それぞれの敵でアルゴリズムが異なる場合を想定している。 例えば小型は蛇行するとか、要塞から小型が吐き出されるとか、戦車からミサイルが放たれるとか、そういう要素(アルゴリズム)をそれぞれの処理ルーチンで作る。 |
syoki.hsp 初期
e1hpb=24 ; 耐久度 e1sp=1.0 ; 敵1スピード e1c=0 ; 出現カウント e1cb=10 ; 出現間隔(フレーム) escr(1)=10 ; スコア e2hpb=300 ; 耐久度 e2sp=0.5 ; 敵2スピード e2c=50 ; 出現カウント e2cb=70 ; 出現間隔(フレーム) escr(2)=100 ; スコア e3hpb=5000 ; 耐久度 e3sp=0.1 ; 敵2スピード e3c=400 ; 出現カウント e3cb=2000 ; 出現間隔(フレーム) escr(3)=2000 ; スコア 敵によってそれぞれ違うステータスを、ここで定義している。 スコアについて、escrの配列変数に定義しおき、scr+=escr(ef(en))のように書けば、倒した敵のソースを分けずにスコア加算が出来る。 escr(1)=10,100,2000 のような書き方でも良い。 再ゲームするにあたって、必要な初期化をするルーチン。 |