2026年 11月 5日
引き続き HSP Dishの標準スプライト(es_命令)で敵弾を作ります。

ソース
![]()
#include "hsp3dish.as" ; HSP3Dishランタイムを使用する
#include "hspmath.as" ; round(四捨五入)用
;--- initialize(初期) ----------
randomize ; 乱数初期
rag45=0.7853982 ; ラジアンで45度
wx=320 : wy=240 ; 画面大きさ
; 自機
jox=16 : joy=16 ; 自機大きさ
jxa=0.0 : jxb=double(wx-jox) ; 座標範囲x
jya=0.0 : jyb=double(wy-joy) ; 座標範囲y
jx=wx/2-8 : jy=wy/2-8 ; 自機座標
jxf=double(jx) : jyf=double(jy) ; 小数点座標
jsp=2.0 ; 自機スピード
jsp2=jsp*rag45 ; 斜めスピード
; ショット
sb=30 ; 最大数
ssp=10 ; スピード
sc=0 ; カウンター
scn=3 ; 発射間隔
; 敵
eb=50 ; 最大数
esp=1 ; スピード
ec=0 ; 出現カウンター
ecn=20 ; 出現間隔
; 敵弾
tb=100 ; 最大数
tsp=2 ; スピード
tcn=200 ; 発生率
; スプライトNo.始め
tna=1 ; 敵弾
sna=tna+tb ; ショット
ena=sna+sb ; 敵
scr=0 ; スコア
screen 0,wx,wy
es_ini ,,360; スプライトの初期化
es_area -16,-16,wx+16,wy+16 ; スプライト生存エリア
buffer 2 : picload "test5.png" ; 画像
es_size 16,16,100 ; 大きさx、y、当たり判定大きさ%
; キャラ登録
es_pat 1,0,0 ; 自機
es_pat 2,16,0 ; 敵
es_pat 3,0,16 ; ショット
es_pat 4,16,16 ; 弾
;スプライト登録(スプNo.、座標x、座標y、キャラNo.)
es_set 0,jx,jy,1 ; 自機
;--- メイン ----------
gsel 0 ; 操作画面をメインスクリーンに戻す
repeat
stick key,31 ; キー入力
if key&128 : break ; [ESC]で終了
repeat 1
if key&1 and key&2 : jxf-=jsp2 : jyf-=jsp2 : break ; 左上
if key&2 and key&4 : jxf+=jsp2 : jyf-=jsp2 : break ; 右上
if key&1 and key&8 : jxf+=jsp2 : jyf+=jsp2 : break ; 左下
if key&4 and key&8 : jxf+=jsp2 : jyf+=jsp2 : break ; 右下
if key&2 : jyf-=jsp ; 上
if key&8 : jyf+=jsp ; 下
if key&1 : jxf-=jsp ; 左
if key&4 : jxf+=jsp ; 右
loop
jxf=limitf(jxf,jxa,jxb) ; 座標範囲x
jyf=limitf(jyf,jya,jyb) ; 座標範囲y
jx=int(round(jxf)) ; 最終座標x
jy=int(round(jyf)) ; 最終座標y
es_pos 0,jx,jy ; 座標セット
repeat 1 ; ショット
sc+ : if sc<scn : break ; 発射間隔
sc=0 ; カウンター
if key&16 {
es_new spn,sna,sb-1 ; 空いてるスプライトNo.
if spn=-1 : break ; -1は無かった場合
es_set spn,jx,jy,3 ; スプラト登録
es_adir spn,180,ssp*100 ; 移動方向
}
loop
; 敵
ec+
if ec=ecn { ; 敵出現
ec=0
es_new spn,ena,eb-1 ; スプNo.
if spn!-1 {
ex=rnd(wx-16) : ey=0 ; 初期座標
es_set spn,ex,ey,2 ; スプ登録
es_adir spn,0,esp*100 ; 移動方向
}
}
; 敵弾
repeat eb-1
epn=ena+cnt ; 敵のスプNo.
es_get f,epn,0 ; 生存フラグ
if f=0 : continue ; 無い
r=rnd(tcn)
if r>0 : continue ; 0なら弾発生
es_new tpn,tna,tb-1 ; スプNo.
if spn=-1 : break ; 空きが無い
es_getpos epn,x,y
es_set tpn,x,y,4 ; スプセット
es_ang x,y,jx,jy ; 確度取得
rag=stat ; 発射確度
r=rnd(11)-5 ; 確度乱数
es_adir tpn,rag+r,tsp*100
loop
;--- 当たり判定 ---------
es_check spn,0,,,ena,ena+eb-1 ; 敵
if spn!-1 : gamef=1 ; ゲームオーバー
es_check spn,0,,,tna,tna+tb-1 ; 敵弾
if spn!-1 : gamef=1 ; ゲームオーバー
repeat sb-1 ; ショット
spn=sna+cnt ; ショットのスプNo.
es_get f,spn,0 ; 生存フラグ
if f=0 : continue ; 無い
es_check epn,spn,,,ena,ena+eb-1
if epn=-1 : continue ; 無かった
es_kill spn ; ショット削除
es_kill epn ; 敵削除
scr+=10 ; スコア
loop
;--- 表示 ----------
redraw 0
color 1,1,1 : boxf
es_draw ; スプライト描画
color 255,255,255
pos 255,220 : mes "FPS "+fpsn ; FPS表示
pos 10,220 : mes "key "+key
pos 10,5 : mes "score "+scr ; スコア
if gamef=1 : pos 140,100 : mes "GAME OVER"
redraw 1
await 1000/60 ; 60FPS
if gamef=1 : break ; ゲームオーバー
; FPS表示
tn2=gettime(6) ; 秒取得
if tn1 not tn2 : tn1=tn2 : fpsn=fps : fps=0 ; リセット
fps+ ; FPS計測値
loop
stop
敵弾の発生は、まず敵の生存フラグを調べて敵ごとに、弾の発生率でランダムに弾を発生させます。
ランダムだとダマになるので、実際はカウンターで弾の発生間隔を空けた方が良いです。
弾の初期座標は es_getpos epn,x,yで敵の座標を参照します。
es_getposは、そのスプNo.の座標を調べる命令です。
es_ang x,y,jx,jy : rag=statで自機と敵との確度(アングル) ragを求めます。
これ x,y,jx,jyの並びで、自機(jx,jy)を後ろにしないと変になります、逆方向になるのかな、元が左で向かう先が右かな。
es_ang p1,p2,p3,p4
p1(0)=基準点のX座標
p2(0)=基準点のY座標
p3(0)=目的点のX座標
p4(0)=目的点のY座標
だから基準点が先ですね、目的点が後です。
発射確度には乱数で幅を持たせます、この場合は r=rnd(11)-5で -5~5までの確度の揺れです、もう少し大きい揺れ幅でも良いと思います。
ちなみに 3way弾のようなものは、中心確度(この場合は rag)に -5と +5とかの弾を作るだけです。
es_adir tpn,rag+r,tsp*100で移動方向とスピードをセットします。
当たり判定は、
es_check spn,0,,,tna,tna+tb-1 ; 敵弾
if spn!-1 : gamef=1 ; ゲームオーバー
で、敵との当たり判定と同じです。
これだと当たり判定が大きいと思うので、

こんな感じで、当たり判定の大きさを変えると良いと思うんだけど、
es_size 16,16,100 ; 大きさx、y、当たり判定大きさ%
es_pat 1,0,0 ; 自機
es_pat 2,16,0 ; 敵
es_pat 3,0,16 ; ショット
es_size 16,16,30 ; 大きさx、y、当たり判定大きさ%
es_pat 4,16,16 ; 弾
そもそも、この当たり判定の座標って左上?それとも中心?
衝突したら止まるようにしました。

きちんと中心座標なんですね。
50%

表示座標は左上ですね(jx=0,jy=0で表示)

当たり判定は左上の表示座標から es_sizeで指定した x,yの大きさの矩形(四角)ですね、画像は関係ないようです。
%による大きさの補正は、ちゃんと中心座標で処理してくれるようです。
次回はホーミングミサイルをやってみたいと思います。