2018年 5月5日
今回はショットを複数撃てるようにした。
それかから switch文を使ってタイトル、ゲーム、ゲームオーバーのモードを分けるようにした。
それではソースを
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 207 208 209 210 211 212 |
; 企画第一弾 : 1画面防衛シューティングを作ろう ; var.0.002 #include "hsp3dish.as" ; HSPdishの宣言 randomize ; 乱数の初期化 wx=640 ; 画面の大きさx wy=360 ; 画面の大きさy ox=20 ; キャラ大きさx oy=20 ; キャラ大きさy font "",ox ; キャラの大きさ設定 ; 自機 ---------- px=wx/2-ox/2 ; プレイヤーの座標x py=wy/2-oy/2 ; プレイヤーの座標y ; SHOT ---------- sb=20 ; ショット最大数 dim sf,sb ; ショット発射フラグ ddim sx,sb ; ショット座標x ddim sy,sb ; ショット座標y ddim sdx,sb ; ショット移動量x ddim sdy,sb ; ショット移動量y ssp=12.0 ; スピード sc=0 ; 出現カウント scb=6 ; 発射間隔(フレーム) ; ENEMY ---------- eb=40 ; 敵最大数 dim ef,eb ; 出現フラグ ddim ex,eb ; 敵座標x ddim ey,eb ; 敵座標y ddim edx,eb ; 敵移動量x ddim edy,eb ; 敵移動量y esp=3.0 ; 敵スピード ec=0 ; 出現カウント ecb=7 ; 出現間隔(フレーム) scr=0 ; スコア hiscr=0 ; ハイスコア *main mainf=0 ; ゲームフラグ repeat ; メインループ ---------------------------------- switch mainf case 0 ; タイトル ---------- stick k : if k=0 : swbreak ; ボタンでゲーム再開 mainf=1 swbreak ; ---------- case 1 ; ゲーム ---------- ; 自機 ---------- x=mousex : y=mousey ; マウスの座標 ; SHOT ---------- repeat 1 ; 発射 if sc>0 : sc- : break ; ウエイト中 repeat sb if sf(cnt)>0 : continue ; 使用中 sf(cnt)=1 ; 使用フラグon sx(cnt)=double(px) : sy(cnt)=double(py) ; 初期座標 xn=double(x-px) ; 自機とマウスの距離x yn=double(y-py) ; 自機とマウスの距離y rad=atan(xn,yn) ; 距離xyから角度を求める sdx(cnt)=sin(rad)*ssp ; 角度とスピードから移動量xを求める sdy(cnt)=cos(rad)*ssp ; 角度とスピードから移動量yを求める break loop sc=scb ; 発射ウエイト loop repeat sb : scn=cnt ; ショット移動処理 if sf(scn)=0 : continue ; 無し sx(scn)+=sdx(scn) ; xの移動 sy(scn)+=sdy(scn) ; yの移動 repeat eb ; 敵との当たり判定 if ef(cnt)=0 : continue if sx(scn)<ex(cnt)+ox and ex(cnt)<sx(scn)+ox and sy(scn)<ey(cnt)+oy and ey(cnt)<sy(scn)+oy { ef(cnt)=0 : sf(scn)=0 ; 当たった敵とショットを消す scr+ ; スコア if hiscr<scr : hiscr=scr ; ハイスコアの更新 break } loop if sf(scn)=1 : if sx(scn)<0-ox or wx<sx(scn) or sy(scn)<0-oy or wy<sy(scn) : sf(scn)=0 ; 場外でフラグ off loop ; ENEMY ---------- repeat 1 ; 敵出現 if ec>0 : ec- : break ; ウエイト中 repeat eb ; フラグ確認 if ef(cnt)>0 : continue ; 使用中 ef(cnt)=1 ; 使用フラグon r=rnd(4) ; 出現方向 if r=0 : exs=rnd(wx) : eys=-oy ; 上 if r=1 : exs=rnd(wx) : eys=wy ; 下 if r=2 : exs=-ox : eys=rnd(wy) ; 左 if r=3 : exs=wx : eys=rnd(wy) ; 右 ex(cnt)=double(exs) ; 初期位置x ey(cnt)=double(eys) ; 初期位置y xn=double(px-exs) ; 敵と自機の距離x yn=double(py-eys) ; 敵と自機の距離y rad=atan(xn,yn) ; 距離xyから角度を求める edx(cnt)=sin(rad)*esp ; 角度とスピードから移動量xを求める edy(cnt)=cos(rad)*esp ; 角度とスピードから移動量yを求める ec=ecb ; 出現ウエイト break ; 登録終わり loop loop repeat eb ; 敵移動処理 if ef(cnt)=0 : continue ; 無し ex(cnt)+=edx(cnt) : ey(cnt)+=edy(cnt) ; 移動 if px<ex(cnt)+ox and ex(cnt)<px+ox and py<ey(cnt)+oy and ey(cnt)<py+oy { mainf=2 : break ; 自機と当たりで GAME OVER } if ex(cnt)<0-ox or wx<ex(cnt) or ey(cnt)<0-oy or wy<ey(cnt) : ef(cnt)=0 ; 枠外でフラグ off loop swbreak ; ---------- case 2 ; gameover ---------- stick k : if k=0 : swbreak ; ボタンでゲーム再開 repeat eb ef(cnt)=0 ; 敵リセット loop repeat sb sf(cnt)=0 ; ショットリセット loop scr=0 ; スコアリセット mainf=0 ; ゲーム再開 swbreak ; ---------- swend redraw 0 ; 表示 ==================== color 1,1,1 : boxf : color 255,255,255 ; 画面クリア pos px,py : mes "●" ; 自機 repeat sb ; ショット if sf(cnt)=0 : continue ; 無い pos sx(cnt),sy(cnt) : mes "・" ; ショット loop repeat eb ; 敵 if ef(cnt)=0 : continue ; 無い pos ex(cnt),ey(cnt) : mes "敵" ; 敵 loop switch mainf case 0 ; タイトル pos wx/2-120,wy/2-50 : mes "1画面防衛シューティング" pos wx/2-43,wy/2+30 : mes "var.0.002" swbreak case 1 ; ゲーム swbreak case 2 ; gameover pos wx/2-43,wy/2+50 : mes "GAME OVER" swbreak swend pos wx-300,5 : mes "SCORE "+scr pos wx-150,5 : mes "HI SCORE "+hiscr redraw 1 ; ==================== await 1000/15 ; ウエイト、FPS 15 loop ; -------------------------------------------------- end ; 終わり |
それではプログラムの説明
今回は単発だったショットを複数にし、敵と同じで一定の間隔で発射するようにした。
見てもらえれば分けるけど、プログラム的に敵のソースとほとんど同じ。
sf,sx,sdx,sy,sdyを配列変数にしただけだ。
ちょっと説明が要るのは、ショットと敵の当たり判定は 1つの弾と敵全部を総当りする必要がある。
これもなんか「外積」とか言うのを使うと当たり判定を高速にできるらしいんだけど、外積は大学の数学らしくて自分はやり方を知らない。
ショットも敵も敵弾(まだ無いが)も大体同じ処理をする。
1、出現処理
a、フラグon
b、初期位置をセット
c、移動値をセット
2、移動処理
a、現座標に移動量を +
b、当たり判定
c、場外判定
出現処理
repeat sb if sf(cnt)>0 : continue sf(cnt)=1 sx(cnt)=double(px) : sy(cnt)=double(py) xn=double(x-px) sdx(cnt)=sin(rad)*ssp break sc=scb |
移動処理
scn=cnt sx(scn)+=sdx(scn) repeat eb if sx(scn)<ex(cnt)+ox and ex(cnt)<sx(scn)+ox and sy(scn)<ey(cnt)+oy and ey(cnt)<sy(scn)+oy { ef(cnt)=0 : sf(scn)=0 scr+ break if sf(scn)=1 : if sx(scn)<0-ox or wx<sx(scn) or sy(scn)<0-oy or wy<sy(scn) : sf(scn)=0 |
さて、この仕様だとショットと敵の発生間隔が同じだった場合、百発百中だと延々とゲームが続く。
敵を撃ちもらした分だけ包囲網が狭まるのだが、そこでショットの発生を敵より僅かに早くすると追い詰められてからの復帰ができる。
この場合、敵のスピードが遅かったり、発生間隔が短いと簡単すぎてやはりゲームが終わらない。
そこで敵のスピードを早くして、ミスを誘発するようにした。
ゲームバランスを考えるのに一番時間がかかってる。
mainfを switch文にかけて、タイトル画面とゲームと GAMEOVER画面を振り分けてる。
つまり mainf=0はタイトル、1=ゲームモード、2=GAMEOVER画面モードだ。
表示も同じやり方で、前よりスッキリしたと思う。