1MS サブウエポンを作ろう


2018年 6月1日
 
 
 今回はいただいたコメントに基づいてサブウエポン(複武装、特殊攻撃)要素をつけたいと思います。
 
 
 その前にコメントいただいた方、発見と返事が送れて済みませんでした。

 ブログ開設以来、長い事コメント 0が常態だったので、確認する習慣が無いとか、確認する方法とかよく分からなかったので。
 以後は確認するようにします。

 コメントありがとうございました。
 
 
 さてサブウエポンですが、例として折角エクセリオンを挙げてもらったのもあり、とりあえずそれっぽくしてみました。

 バルカン、クリックで一定数発射、弾数制限有り。

 弾数の増やし方は色々方法はありますが、とりあえず今回はエクセリオン方式で敵を倒したら一定数増えます。
 
 
 それと前回のソースにバグがありました。

repeat eb ; 敵との当たり判定
 if ef(cnt)=0 : break

 continue(次を繰り返せ)と書かなくてはいけない所を break(終了しろ)と書いたために、その f(フラグ)の敵が 0なら以降当たり判定がなくなるという。

 つまり少し謎のすり抜けがあったかもしれません。

 ブログの表記は直しますが、ゲームは HTML編集しなければいけないし、めんどうなのでそのままにします(今回のは直ってます)


 
 
 今回は問題が発生して、画面がちらつく。

 表示の量が多いのか、計算が多いのか、別の理由なのかイマイチ分からないのでその検証は次回以降にする。

 ただ自分の意見としては素直に JAVAとか他の言語やった方が良いとは思う、スペック的にもプロで仕事目指すにしても。

 HSPは、まあ使い方次第ではあるけど、あくまでも入門だと割り切った方が良いだろうね。

 少なくともこれでブラウザ用の STGみたいな動きのあるものを、というのは少し無謀かもしれない。
(スマホでもちらついたので別の原因かもしれない、PCのウインドウ起動なら問題無い
 それと普通の HSPと HSPdishの webGL要するにブラウザ版とまた違うので注意
 そしてアンドロイドアプリとして作るのとも違う、これはブラウザ版なのだ
 どの道総じてブラウザは重い)

 まあ、もうちょっとやってみないと何とも言えないかな。
 
 
 今回はスマホ用にクリック発射を実装したけど、ただボタン押すだけじゃ無くて、放してる常態から一定フレーム内押してもう一度放したら発射。

 長押しでは発射されない仕組みになってる。
 
 
 後はサブウエポンのバルカンは 1フレームに 3発同時発射、最初の位置を 0~2回分後退させておく、という手法をとった。

 ただ 1フレームのスピードと計算は前回と同じなので、単に 1フレームに同時3発発射というだけの事になってる。

 つまり今回はまだスピード 20 × 3回で計算をしてるが、次は 60 × 1回で、線との当たり判定をしたいとは思ってる。
 
 
 それと集弾率をランダム座標では無くて、ランダムラジアン(円周率)にした。

 ただしメインショットは着弾点の特定が難しかったので、止めにしてそのままにしてる。
 
 
 それでは今回のソース、バルカンの要素が増えてる、変数とか処理とかはショットや敵とほとんど同じ。

 ← バルカン

; 企画第一弾 : 1画面防衛シューティングを作ろう
; var.0.005

#include "hsp3dish.as" ; HSPdishの宣言


	randomize	; 乱数の初期化

	pai=3.141593
	pai2=pai*2

	rad45=0.7853982		; ラジアンで45度
	rad90=1.5707965		; ラジアンで90度


	wx=640	; 画面の大きさx
	wy=360	; 画面の大きさy

	gmode 2

	jw=1 : jo=20 : jo2=jo/2	; 自機
	 celload "jiki_1.png",jw
	  celdiv jw,jo,jo,jo2,jo2

	sw=2 : so=6 : so2=so/2	; ショット
	 celload "shot_1.png",sw
	  celdiv sw,so,so,so2,so2

	ew=3 : eo=20 : eo2=eo/2	; 敵
	 celload "ene_1.png",ew
	  celdiv ew,eo,eo,eo2,eo2

	cw=4 : co=32 : co2=co/2	; カーソル
	 celload "csr_2.png",cw
	  celdiv cw,co,co,co2,co2

	hw=5 : ho=16 : ho2=ho/2	; ヒット
	 celload "hit_4.png",hw
	  celdiv hw,ho,ho,ho2,ho2

	vw=6 : 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 ; 自機下座標

; 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=5			; パワー

	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=3			; パワー
	vu=30			; 揺れ幅(集弾値)
	vnb=180			; 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		; 向き

	ehpb=60			; 耐久度

	esp=0.5			; 敵スピード

	ec=0			; 出現カウント
	ecb=10			; 出現間隔(フレーム)

	scr=0		; スコア
	hiscr=0		; ハイスコア

	kf=0		; キーを押してるかフラグ
	kc=0		; 何フレームキーを押してるか


*main

	mainf=0 ; ゲームフラグ

	repeat ; メインループ ----------------------------------

	 switch mainf
	  case 0 ; タイトル ----------
	   stick k : if k=0 : swbreak ; ボタンでゲーム再開
	   mainf=1
	  swbreak ; ----------

	  case 1 ; ゲーム ----------

; 自機 ----------
	   x=mousex : y=mousey	; マウスの座標

	   stick k,256	; マウスクリック

; SHOT ----------
	   repeat 1 ; 発射
	    if sc>0 : sc- : break ; ウエイト中

	    repeat sb
	     if sf(cnt)!0 : continue ; 使用中

	     sf(cnt)=1 ; 使用フラグon
		 sx(cnt)=double(jx) : sy(cnt)=double(jy) ; 初期座標

		 xx=x-su/2+rnd(su)		; ショットの着弾点x
		 yy=y-su/2+rnd(su)		; ショットの着弾点y

		 xn=double(xx-jx)		; 自機とマウスの距離x
		 yn=double(yy-jy)		; 自機とマウスの距離y

		 rad=atan(xn,yn)		; 距離xyから角度を求める

		 sr(cnt)=-rad+pai		; 向き

	 	 sdx(cnt)=sin(rad)*ssp	; 角度とスピードから移動量xを求める
	 	 sdy(cnt)=cos(rad)*ssp	; 角度とスピードから移動量yを求める


		 sxb(cnt)=xx : syb(cnt)=yy	; 終点座標

		 skn(cnt)=0.0				; 現移動距離をリセット

		 x2=xx-jx : y2=yy-jy
		  skb(cnt)=sqrt(x2*x2+y2*y2); 最終移動距離
		 
		 break
		loop
		sc=scb ; 発射ウエイト
	   loop

	   repeat sb : scn=cnt ; ショット移動処理
		if sf(scn)=0 : continue ; 無し

		repeat skc : cnt2=cnt ; 1ショットの移動繰り返し ====================
		 sx(scn)+=sdx(scn) ; xの移動
		 sy(scn)+=sdy(scn) ; yの移動

		 skn(scn)+=ssp ; どれだけ距離を進んだか
		  if skn(scn)>=skb(scn) { ; 終点判定
			 sx(scn)=double(sxb(scn))
			 sy(scn)=double(syb(scn))
			 sf(scn)=-1 ; 着弾フラグ
		  }

		 sx1=int(sx(scn))-so2 ; ショット左座標
		 sx2=int(sx(scn))+so2 ; ショット右座標
		 sy1=int(sy(scn))-so2 ; ショット上座標
		 sy2=int(sy(scn))+so2 ; ショット下座標

		 repeat eb ; 敵との当たり判定
		  if ef(cnt)=0 : continue

		  ex1=int(ex(cnt))-eo2 ; 敵左座標
		  ex2=int(ex(cnt))+eo2 ; 敵右座標
		  ey1=int(ey(cnt))-eo2 ; 敵上座標
		  ey2=int(ey(cnt))+eo2 ; 敵下座標

		  if sx1<ex2 and ex1<sx2 and sy1<ey2 and ey1<sy2 {
		   sf(scn)=-1
		   ehp(cnt)-=sp ; 耐久度-
			if ehp(cnt)<=0 { ; 倒したか
			 ef(cnt)=0		; 当たった敵とショットを消す
			 vc+=vcb		; バルカンの残弾数を増やす
			 scr+			; スコア
			 if hiscr<scr : hiscr=scr ; ハイスコアの更新
			 break
			}
		  }
		 loop

		 if sf(scn)=1 : if sx2<0 or wx<sx1 or sy2<0 or wy<sy1 : sf(scn)=0 : break ; 場外でフラグ off

		 if sf(scn)=-1 : break ; 着弾してる

		loop ; ====================
	   loop


; VULCAN ----------

	   repeat 1 ; バルカンの入力判定
	    if k=256 : kf=1 : kc+ : break ; 押している
	    if kf=0 : break ; 一度も押してない

	    kf=0 ; 押しフラグリセット
	    if kc>2 : kc=0 : break ; 2フレーム以上押していた
	    if vc>0 and vn=0 : vn+=vnb ; 発射要求数
	    kc=0
	   loop

	   repeat vkc : cnt2=cnt ; 1フレームに発射される数
	    if vn=0 or vc=0 : break ; 発射要求数、または残弾が0

		repeat vb : vcn=cnt
	     if vf(vcn)!0 : continue ; 使用中

	     vn- ; 発射要求数-
	     vc- : if vc=0 : vn=0 ; 残弾-

	     vf(vcn)=1 ; 使用フラグon
		 vx(vcn)=double(jx) : vy(vcn)=double(jy) ; 初期座標

		 xn=double(x-jx)		; 自機とマウスの距離x
		 yn=double(y-jy)		; 自機とマウスの距離y

		 rd=double(-(vu/2)+rnd(vu+1))/100.0 ; 揺れ幅(ラジアン)
		  rad=atan(xn,yn)+rd	; 距離xyから角度を求める

		 vr(vcn)=-rad+pai		; 向き

	 	 vdx(vcn)=sin(rad)*vsp	; 角度とスピードから移動量xを求める
	 	 vdy(vcn)=cos(rad)*vsp	; 角度とスピードから移動量yを求める

		 repeat cnt2
		  vx(vcn)-=vdx(vcn) ; 始点座標をバックさせておくx
		  vy(vcn)-=vdy(vcn) ; 始点座標をバックさせておくy
		 loop

		 break
		loop
	   loop

	   repeat vkc ; vkc回移動
	    repeat vb : vcn=cnt ; ショット移動処理
		 if vf(vcn)=0 : continue ; 無し

	     vx(vcn)+=vdx(vcn) ; xの移動
	     vy(vcn)+=vdy(vcn) ; yの移動

	     vx1=int(vx(vcn))-vo2 ; ショット左座標
	     vx2=int(vx(vcn))+vo2 ; ショット右座標
	     vy1=int(vy(vcn))-vo2 ; ショット上座標
	     vy2=int(vy(vcn))+vo2 ; ショット下座標

	     repeat eb ; 敵との当たり判定
	      if ef(cnt)=0 : continue

	      ex1=int(ex(cnt))-eo2 ; 敵左座標
	      ex2=int(ex(cnt))+eo2 ; 敵右座標
	      ey1=int(ey(cnt))-eo2 ; 敵上座標
	      ey2=int(ey(cnt))+eo2 ; 敵下座標

	      if vx1<ex2 and ex1<vx2 and vy1<ey2 and ey1<vy2 {
	       vf(vcn)=-1
	       ehp(cnt)-=vp ; 耐久度-
	        if ehp(cnt)<=0 { ; 倒したか
	         ef(cnt)=0 ; 敵を消す
	         ;vc+=vcn ; バルカンの残弾数を増やす
	         vcr+ ; スコア
	         if hiscr<scr : hiscr=scr ; ハイスコアの更新
	         break
	        }
	      }
	     loop

	     if vf(vcn)=1 : if vx2<0 or wx<vx1 or vy2<0 or wy<vy1 : vf(vcn)=0 : continue ; 場外でフラグ off

	     if vf(vcn)=-1 : continue ; 着弾してる
	    loop
	   loop


; ENEMY ----------

	   repeat 1 ; 敵出現
	    if ec>0 : ec- : break ; ウエイト中

		repeat eb ; フラグ確認
		 if ef(cnt)>0 : continue ; 使用中
		 ef(cnt)=1 ; 使用フラグon

		 ehp(cnt)=ehpb

		 r=rnd(4) ; 出現方向
		  if r=0 : exs=rnd(wx)-eo2 : eys=0-eo2	; 上
		  if r=1 : exs=rnd(wx)-eo2 : eys=wy+eo2	; 下
		  if r=2 : exs=-eo2	  : eys=rnd(wy)-eo2	; 左
		  if r=3 : exs=wx+eo2 : eys=rnd(wy)-eo2	; 右

		  ex(cnt)=double(exs)	; 初期位置x
		  ey(cnt)=double(eys)	; 初期位置y

		  xn=double(jx-exs)	; 敵と自機の距離x
		  yn=double(jy-eys)	; 敵と自機の距離y

		  rad=atan(xn,yn) 	; 距離xyから角度を求める

		  edx(cnt)=sin(rad)*esp	; 角度とスピードから移動量xを求める
		  edy(cnt)=cos(rad)*esp	; 角度とスピードから移動量yを求める

		  er(cnt)=-rad+pai	; 向き

		  ec=ecb ; 出現ウエイト

		  break ; 登録終わり
		loop
	   loop

	   repeat eb ; 敵移動処理
		if ef(cnt)=0 : continue ; 無し

		ex(cnt)+=edx(cnt) : ey(cnt)+=edy(cnt) ; 移動

		ex1=int(ex(cnt))-eo2 ; 敵左座標
		ex2=int(ex(cnt))+eo2 ; 敵右座標
		ey1=int(ey(cnt))-eo2 ; 敵上座標
		ey2=int(ey(cnt))+eo2 ; 敵下座標

		if jx1<ex2 and ex1<jx2 and jy1<ey2 and ey1<jy2 {
			mainf=2 : break ; 自機と当たりで GAME OVER
		}

		if ex2<0 or wx<ex1 or ey2<0 or wy<ey1 : ef(cnt)=0 ; 枠外でフラグ off
	   loop
	  swbreak ; ----------

	  case 2 ; gameover ----------
	   stick k : if k=0 : swbreak ; ボタンでゲーム再開

	   repeat sb
	    sf(cnt)=0 ; ショットリセット
	   loop

	   repeat vb
	    vf(cnt)=0 ; バルカンリセット
	   loop
	   vn=0 : vc=0 ; 残弾リセット

	  repeat eb
	    ef(cnt)=0 ; 敵リセット
	   loop

	   scr=0 ; スコアリセット

	   mainf=0 ; ゲーム再開
	  swbreak ; ----------
	 swend


	 redraw 0 ; 表示 ====================
	  color 1,1,1 : boxf : color 255,255,255 ; 画面クリア

	  pos jx,jy : celput jw ; 自機

	  repeat eb ; 敵
	   if ef(cnt)=0 : continue ; 無い
	   pos ex(cnt),ey(cnt) : celput ew,,,,er(cnt) ; 敵
	  loop

	  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

	  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

	  pos x,y : celput cw ; カーソル

	  switch mainf
	   case 0 ; タイトル
	    pos wx/2-120,wy/2-50 : mes "1画面防衛シューティング"
	    pos wx/2-43,wy/2+30 : mes "var.0.005"
	   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 ; --------------------------------------------------


	return ; 終わり

 
 

プログラム解説

入力判定

repeat 1 ; バルカンの入力判定
 if k=256 : kf=1 : kc+ : break ; 押している
 if kf=0 : break ; 一度も押してない

 kf=0 ; 押しフラグリセット
 if kc>2 : kc=0 : break ; 2フレーム以上押していた
 if vc>0 and vn=0 : vn+=vnb ; 発射要求数
 kc=0
loop

 この前に stick k という命令が実行されていて、kの変数にキー入力の値が入る。
 k=256はマウスの左クリックと、スマホのタッチという意味。

 kf=そのキーを押してるか、0=押してない、1=押してる。

 kf=1の時、kcを +する、kc=何フレームキーを押してるかのカウント。

 再び kf=0になった時、つまりボタンを放した時 kcが 2フレーム以下なら特殊攻撃発動、それ以上押しっ放しなら照準を動かしているものと見る。

 要するにポンと押した時だけ発動するようなプログラム。

 vc=残弾数、vn=発射数、発射中の変化はしないようにしてる。

 
 
バルカン

 ソースの内容はショットと敵とほとんど同じ。

 ショットのソースをコピペして sを vに書き換え、改造して作った。
 
 
repeat vkc : cnt2=cnt ; 1フレームに発射される数
 始めに vkc発分同時発射する。
 
 

rd=double(-(vu/2)+rnd(vu+1))/100.0 ; 揺れ幅(ラジアン)
 rad=atan(xn,yn)+rd ; 距離xyから角度を求める

 ラジアン(向き)に + -する形で弾道の揺らぎを変化させる。
 vu=ゆれ幅。
 
 

repeat cnt2
 vx(vcn)-=vdx(vcn) ; 始点座標をバックさせておくx
 vy(vcn)-=vdy(vcn) ; 始点座標をバックさせておくy
loop

 1発目は 0回、2発目は 1回分、3発目は2回分、あらかじめバックさせておく。
 
 
repeat vkc ; vkc回移動

 結局今回はまだ 1フレームに3回動かしている。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です