# 10 sample_shooting.hsp

sample\ 10 sample_shooting.hsp

    #include "hsp3dish.as"

    #include "mod_layerbutton.hsp"

    #packopt xsize 480
    #packopt ysize 800

    ; バーチャルパッド用サンプル シューティング（480x800）
    screen 0,480,800
    title "バーチャルパッド用サンプル シューティング"
    randomize

    // HSP3Dish.js用データフォルダ設定
    info_os = sysinfo(0)
    if instr(info_os,0,"Emscripten")>=0 : mm_dir="" : else : mm_dir="data/"

    // 画像読み込み
    celload mm_dir+"pad.png", -1
    cel_pad = stat : celdiv cel_pad,128,128, 64,64
    celload mm_dir+"nub.png", -1
    cel_nub = stat : celdiv cel_nub,64,64, 32,32
    celload mm_dir+"btn.png", -1
    cel_btn = stat : celdiv cel_btn,64,64
    celload mm_dir+"btn2x.png", -1
    cel_btn2x = stat : celdiv cel_btn2x,128,128
    celload mm_dir+"bean.png", -1
    cel_bean = stat : celdiv cel_bean,64,42, 32,21

    pxConL = 100             ; コントローラ表示位置の中心X座標
    pyConL = ginfo_sy-100    ; コントローラ表示位置の中心Y座標
    szConL = 1.0             ; コントローラのサイズ倍率
    zurizuri = 1             ; スティックを範囲外まで動かしたら本体を追従させるオプション (逆方向に操作する際、常に一定のスライド量で反対側まで操作できます)
    gosub *create_analogCon  ; アナログスティック作成

    pxConR = ginfo_sx-60
    pyConR = ginfo_sy-70
    szConR = 1.0
    gosub *create_btnCon  ; ボタン作成

    // 自機
    px=240.0: py=600.0: pspeed=5: life=3: bomb=1: hit_flash=0 : analogx=0.0 : analogy=0.0
    // 敵管理
    e_num=20: dim ex,e_num: dim ey,e_num: dim evx,e_num: dim evy,e_num: dim et,e_num: dim ealive,e_num
    // 弾管理
    s_num=20: dim sx,s_num: dim sy,s_num: dim salive,s_num

    // メインループ
    *mainloop
    	redraw 0: color 0,0,0: boxf: font msgothic,20
    	frame++

    	if keyM {  ; メニューボタン
    		if gameOver == 0 {
    			gamePause = 1 - gamePause
    		}else {
    			// ゲームリスタート
    			px=240.0: py=600.0: pspeed=5: life=3: bomb=1: hit_flash=0 : analogx=0.0 : analogy=0.0
    			e_num=20: dim ex,e_num: dim ey,e_num: dim evx,e_num: dim evy,e_num: dim et,e_num: dim ealive,e_num			// 弾管理
    			s_num=20: dim sx,s_num: dim sy,s_num: dim salive,s_num
    			frame=1: score=0: item_y=0: gameOver=0
    		}
    	}

    // ポーズまたはゲームオーバー中は操作/更新を停止
    if gamePause == 0 && gameOver == 0 {
    	// アナログスティック入力
    	px = limitf(px+(analogx*10),8,ginfo_sx-8)
    	py = limitf(py+(analogy*10),8,ginfo_sy-8)
    	if keyA {  ; 弾追加
    		repeat s_num
    			if salive(cnt) : continue
    			sx(cnt)=px
    			sy(cnt)=py
    			salive(cnt)=1
    			break
    		loop
    	}
    	if keyB && bomb==1 && bomb_active==0 {
    		bomb_active=1
    		bomb_radius=0
    		bomb=0
    	}

    	// 敵更新
    	repeat e_num
    		if ealive(cnt) == 0 {
    			ex(cnt)=rnd(440)+20
    			ey(cnt)=-rnd(500)-8
    			evx(cnt)=rnd(10)-5
    			evy(cnt)=2+rnd(2+frame/600)
    			et(cnt)=0
    			ealive(cnt)=1
    		}
    		et(cnt)++
    		ex(cnt)+=evx(cnt)
    		ey(cnt)+=evy(cnt)
    		ex(cnt)+=sin(0.1*et(cnt))*2
    		if ex(cnt)>488 || ex(cnt)<-8 : evx(cnt)=-evx(cnt)
    		if ey(cnt)>808 : ealive(cnt)=0
    	loop
    	// 弾更新
    	repeat s_num
    		if salive(cnt) == 0 : continue
    		sy(cnt)-=8
    		if sy(cnt)<0 : salive(cnt)=0
    	loop
    	// ボムアイテム生成
    	if frame\1200 == 0 : item_x=rnd(440)+20: item_y=1
    	if item_y {
    		item_y+=2
    		color 255,255,0: boxf item_x,item_y,item_x+16,item_y+16
    		if abs(px-item_x)<16 && abs(py-item_y)<16 : bomb=1: item_y=0
    	}

    	// 当たり判定
    	repeat e_num
    		if ealive(cnt) == 0 : continue
    		// 自機と敵
    		if abs(px-ex(cnt))<16 && abs(py-ey(cnt))<16 && hit_flash==0 {
    			life--
    			hit_flash=30  ; 点滅カウント
    			ealive(cnt)=0
    			if life<=0 : gameOver=1
    		}
    		cnt2=cnt
    		// 弾と敵
    		repeat s_num
    			if salive(cnt) == 0 : continue
    			if abs(ex(cnt2)-sx(cnt))<10 && abs(ey(cnt2)-sy(cnt))<12 {
    				ealive(cnt2)=0
    				salive(cnt)=0
    				score+=10
    			}
    		loop
    	loop
    	// ボム処理
    	if bomb_active {
    		bomb_radius+=16
    		color 255,255,255: boxf px-bomb_radius,py-bomb_radius,px+bomb_radius,py+bomb_radius
    		repeat e_num : ealive(cnt)=0 : loop
    		if bomb_radius>800 : bomb_active=0
    	}
    }

    	// 自機表示
    	if hit_flash : hit_flash--
    	if hit_flash\4 == 0 {  ; 点滅考慮
    		color 0,255,255: boxf px-8,py-8,px+8,py+8
    	}
    	// 敵表示
    	repeat e_num
    		if ealive(cnt) == 0 : continue
    		color 255,0,0: boxf ex(cnt)-8,ey(cnt)-8,ex(cnt)+8,ey(cnt)+8
    	loop
    	// 弾表示
    	repeat s_num
    		if salive(cnt) == 0 : continue
    		color 255,255,0: boxf sx(cnt)-2,sy(cnt)-4,sx(cnt)+2,sy(cnt)+4
    	loop

    	// ポーズ/ゲームオーバー 表示
    	if gamePause || gameOver {
    		gmode 3,,,200
    		ax=0,ginfo_sx,ginfo_sx,0
    		ay=0,0,ginfo_sy,ginfo_sy
    		color: gsquare -1,ax,ay
    		if gameOver == 0 {
    			if pausemx == 0 : pausemx=-ginfo_sx  ; 初回は画面外に飛ばす (描画幅計測)
    			pos (ginfo_sx-pausemx)/2,350
    			color 255,255: mes "Pause"
    			if pausemx<0 : pausemx=ginfo_mesx
    		}else {
    			if gmov1mx == 0 : gmov1mx=-ginfo_sx  ; 初回は画面外に飛ばす (描画幅計測)
    			if gmov2mx == 0 : gmov2mx=-ginfo_sx  ;
    			font msgothic,30,1
    			pos (ginfo_sx-gmov1mx)/2,350
    			color 255: mes "Game Over"
    			if gmov1mx<0 : gmov1mx=ginfo_mesx
    			font msgothic,20
    			if frame\80>20 {
    				pos (ginfo_sx-gmov2mx)/2,450
    				color 255,255: mes "Restart : Push Menu Button!"
    				if gmov2mx<0 : gmov2mx=ginfo_mesx
    			}
    		}
    	}

    	// スコア/残機/ボム 表示
    	color 255,255,255
    	pos 10,10: mes "SCORE:"+score
    	pos 10,30: mes "LIFE:"+life
    	pos 10,50: mes "BOMB:"+bomb+"/1"

    	redraw 1
    	await 16
    goto *mainloop

    // アナログスティック作成
    *create_analogCon
    	pos pxConL-(szConL*64), pyConL-(szConL*64)
    	layerbutton szConL*128,szConL*128, 0,0 {
    		laybtn_settings 0,4,1+4  ; 設定 : ボタン外からスライドしてもクリック + ボタンを押しても消さない
    		laybtn_hitarea -1, objlayer_size_x/2,objlayer_size_y/2, objlayer_size_x  ; 円形ヒットエリア
    		if lparam == objlayer_cmddraw {
    			if layerbtn_clickx!=-1 && layerbtn_clicky!=-1 {  ; クリック/タッチ中
    				layerbtn_clickx_ = double(layerbtn_clickx) + zrzrx
    				layerbtn_clicky_ = double(layerbtn_clicky) + zrzry
    				rr = double(objlayer_size_x)/2  ; スティックが動く範囲の半径
    				dx = -layerbtn_clickx_ + layerbtn_mousex
    				dy = -layerbtn_clicky_ + layerbtn_mousey
    				_dist = dx*dx + dy*dy
    				if _dist > rr*rr {
    					dist = sqrt(_dist)
    					layerbtn_mousex_ = double(dx * rr) / dist + layerbtn_clickx_
    					layerbtn_mousey_ = double(dy * rr) / dist + layerbtn_clicky_
    					if zurizuri : zrzrx-=layerbtn_mousex_-layerbtn_mousex : zrzry-=layerbtn_mousey_-layerbtn_mousey
    				}else{
    					layerbtn_mousex_ = double(layerbtn_mousex)
    					layerbtn_mousey_ = double(layerbtn_mousey)
    				}
    				// パッドのアナログ値
    				analogx = (layerbtn_mousex_ - (layerbtn_clickx_))*2 / objlayer_size_x
    				analogy = (layerbtn_mousey_ - (layerbtn_clicky_))*2 / objlayer_size_y
    				// 表示用の補正
    				layerbtn_mousex_ -= objlayer_size_x/2
    				layerbtn_mousey_ -= objlayer_size_y/2
    				layerbtn_clickx_ -= objlayer_size_x/2
    				layerbtn_clicky_ -= objlayer_size_y/2
    			}else {
    				zrzrx=0.0 : zrzry=0.0
    				analogx=0.0 : analogy=0.0
    				// 表示用の補正
    				layerbtn_mousex_ = 0.0
    				layerbtn_mousey_ = 0.0
    				layerbtn_clickx_ = layerbtn_mousex_
    				layerbtn_clicky_ = layerbtn_mousey_
    			}
    			// pad, nub 描画
    			laybtn_ezcel cel_pad, 1,,,,,,, layerbtn_clickx_, layerbtn_clicky_, szConL,szConL  ; ezcelの裏技 : 第9引数から ボタン画像ずらし量, 強制倍率 を指定できる
    			laybtn_ezcel cel_nub, 1,,,,,,, layerbtn_mousex_, layerbtn_mousey_, szConL,szConL
    		}
    		return
    	}
    	return

    // ボタン作成
    *create_btnCon
    	; A (shot)
    	pos pxConR-(szConR*48), pyConR-(szConR*48)
    	layerbutton szConR*96,szConR*96, 0,1 {
    		laybtn_settings 0,4+8,1+4  ; 設定 : 同グループ押下中ならボタン外からスライドしてもクリック + ボタンを押しても消さない
    		laybtn_hitarea -1, objlayer_size_x/2,objlayer_size_y/2, objlayer_size_x  ; 円形ヒットエリア
    		if lparam == objlayer_cmddraw {
    			font msgothic,24,1 : color 200,200,200
    			laybtn_ezcel cel_btn2x,0, "Shot"
    			if gamePause : return
    			keyA = ( (layerbtn_stat & LAYBTN_PRESS_IN)!=0 && layerbtn_cnt == 0 )
    		}
    		return
    	}
    	; B (bomb)
    	pos pxConR-(szConR*120), pyConR-(szConR*16)
    	layerbutton szConR*64,szConR*64, 1,1 {
    		laybtn_settings 0,4+8,1+4  ; 設定 : 同グループ押下中ならボタン外からスライドしてもクリック + ボタンを押しても消さない
    		laybtn_hitarea -1, objlayer_size_x/2,objlayer_size_y/2, objlayer_size_x  ; 円形ヒットエリア
    		if lparam == objlayer_cmddraw {
    			font msgothic,16,1 : color 200,200,200
    			laybtn_ezcel cel_btn,0, "Bomb"
    			if gamePause : return
    			keyB = ( (layerbtn_stat & LAYBTN_PRESS_IN)!=0 && layerbtn_cnt == 0 )
    		}
    		return
    	}
    	; menu
    	pos pxConR+(szConR*-5), pyConR-(szConR*90)
    	layerbutton szConR*64,szConR*42, 2,1 {
    		laybtn_settings 0,2,1+4  ; 設定 : マウスクリックで即決定 + ボタンを押しても消さない
    		laybtn_hitarea -3, objlayer_size_x/2,objlayer_size_y/2, objlayer_size_x,objlayer_size_y, 20.0/180.0*M_PI  ; 長方形(角度付き)ヒットエリア
    		if lparam == objlayer_cmddraw {
    			font msgothic,20 : color 200,200,200
    			pos objlayer_axis_x+objlayer_size_x/2, objlayer_axis_y+objlayer_size_y/2
    			switch (layerbtn_stat|1^1)  ; _SELECTED状態を除去して分岐 [(layerbtn_stat & $FFFE)でもOK]
    			case LAYBTN_FOCUS_IN : id_celdiv = 1 : swbreak
    			case LAYBTN_PRESS_IN : id_celdiv = 2 : swbreak
    			default : id_celdiv = 0
    			swend
    			celput cel_bean, id_celdiv, szConR,szConR, 20.0/180.0*M_PI
    			laybtn_mes "≡",0, 1,1
    			keyM = ( layerbtn_stat == LAYBTN_PRESS_IN_SELECTED )
    		}
    		return
    	}
    	return