3.シューティングゲームを作る
HSPでシューティングゲームを作ってみましょう
◆どう作るか
今回も例によって、どう作るかを考えてから作成しましょう。今回は、
- stick命令でキー入力を取得し、自機を移動
- 配列変数を使いまくり、弾を発射
- 敵も配列変数を使いまくる
- 敵の弾も配列変数w スピード・方向は乱数で決定
- 当たり判定をつける
- あとは、適当にアレンジ
◆作成
どう作るかを考えたので、早速作成に取り掛かりましょう。今回は相当根気が要ります。今までとくらべものにならない程度にw
ちなみに今回使用する画像は

です。
※画像の素材はこちらのものを使わせていただきました。
◇stick命令でキー入力を取得し、自機を移動
まずは1の「stick命令でキー入力を取得し、自機を移動」です。まぁ比較的簡単です。buffer 1 picload "pic.bmp" screen 0,300,500 title "ShotGame" *start mx=133 : my=452 repeat 8 sx(cnt)=1000 : sy(cnt)=1000 loop repeat redraw 0 color 0,0,0 : boxf stick key,31 gosub *me redraw 1 await 10 loop *me if key&1 : mx=mx-6 : if mx<=0 : mx=0 if key&2 : my=my-6 : if my<=0 : my=0 if key&4 : mx=mx+6 : if mx>=265 : mx=265 if key&8 : my=my+6 : if my>=452 : my=452 pos mx,my gmode 2 gcopy 1,0,0,35,48 returnメインルーチンでstick命令を使ってキー入力情報を読み込んでいます。そしてキー入力情報によって、自機の座標を変え、ウィンドウID1のバッファから画像を読み出しています。
また、「if mx<=0 : mx=0」のような部分で、画面からはみでないようにする処理をしています。
◇配列変数を使いまくり、弾を発射
次に2の「配列変数を使いまくり、弾を発射 」です。buffer 1 picload "pic.bmp" screen 0,300,500 title "ShotGame" *start dim sx,8 : dim sy,8 : dim st,8 mx=133 : my=452 : tk=1 repeat 8 sx(cnt)=1000 : sy(cnt)=1000 loop tks(6)=1 : tks(7)=1 repeat redraw 0 color 0,0,0 : boxf stick key,31 gosub *me repeat 8 c=cnt gosub *shot loop redraw 1 await 10 loop *me if key&1 : mx=mx-6 : if mx<=0 : mx=0 if key&2 : my=my-6 : if my<=0 : my=0 if key&4 : mx=mx+6 : if mx>=265 : mx=265 if key&8 : my=my+6 : if my>=452 : my=452 pos mx,my gmode 2 gcopy 1,0,0,35,48 return *shot if st(c)=0 and ss=0 { if key&16 { sx(c)=mx+11 : sy(c)=my st(c)=1 : key=0 ss=40 } } else { sy(c)=sy(c)-10 if sy(c)<0 : st(c)=0 } if st(c)=1 { color 0,0,0 pos sx(c),sy(c) gmode 2 gcopy 1,35,0,12,12 } ss=ss-1 if ss<0 : ss=0 returnshotルーチンが加わりました。このルーチンでは、配列変数stに弾が表示されているかいないかの状態を代入し、それによってスペースキーが押されている時に弾を発射するかしないかを決めています。
ss=40というのは、弾発射までの装填時間と思っていいでしょう。この時間がないと、弾が一気に発射されてしまいます。
◇敵も配列変数を使いまくる
敵の表示にも、配列変数を使いまくります。buffer 1 picload "pic.bmp" screen 0,300,500 title "ShotGame" *start dim sx,8 : dim sy,8 : dim st,8 dim tx,8 : dim ty,8 : dim tks,8 mx=133 : my=452 : tk=1 repeat 8 sx(cnt)=1000 : sy(cnt)=1000 loop tks(6)=1 : tks(7)=1 repeat redraw 0 color 0,0,0 : boxf stick key,31 gosub *me repeat 8 c=cnt gosub *shot gosub *teki loop redraw 1 await 10 loop *me if key&1 : mx=mx-6 : if mx<=0 : mx=0 if key&2 : my=my-6 : if my<=0 : my=0 if key&4 : mx=mx+6 : if mx>=265 : mx=265 if key&8 : my=my+6 : if my>=452 : my=452 pos mx,my gmode 2 gcopy 1,0,0,35,48 return *shot if st(c)=0 and ss=0 { if key&16 { sx(c)=mx+11 : sy(c)=my st(c)=1 : key=0 ss=40 } } else { sy(c)=sy(c)-10 if sy(c)<0 : st(c)=0 } if st(c)=1 { color 0,0,0 pos sx(c),sy(c) gmode 2 gcopy 1,35,0,12,12 } ss=ss-1 if ss<0 : ss=0 return *teki if tk=1 { if tkt=0 { repeat 6 tx(cnt)=cnt*50 loop repeat 6 ty(cnt)=cnt*40-240 loop tkt=1 } if tks(c)=0 { ty(c)=ty(c)+3 if ty(c)>500 : tks(c)=1 pos tx(c),ty(c) gmode 2 gcopy 1,47,0,51,48 } if tks(c)=1 { ty(c)=500 } repeat 8 tkm=tkm+tks(cnt) loop if tkm=8 { tkm=0 tkt=0 tk=2 repeat 8 tks(cnt)=0 loop } else { tkm=0 } } if tk=2 { if tkt=0 { repeat 6 tx(cnt)=cnt*50 loop repeat 3 ty(cnt)=cnt*40 loop repeat 3,3 ty(cnt)=200-(cnt*40) loop tkt=1 } if tks(c)=0 { ty(c)=ty(c)+3 if ty(c)>500 : tks(c)=1 pos tx(c),ty(c) gmode 2 gcopy 1,98,0,37,48 } if tks(c)=1 { ty(c)=500 } repeat 8 tkm=tkm+tks(cnt) loop if tkm=8 { tkm=0 tkt=0 tk=3 } else { tkm=0 } } if tk=3 { color 180,180,180 : boxf 50,180,250,320 color 120,120,120 : boxf 65,240,235,275 color 0,0,0 : pos 60,180 : font "",50,2 : mes "CLEAR" pos 65,240 : font "",30,2 : mes "SCORE:"+scr pos 65,290 : font "",16 : mes "※エンターキーでもう一度" redraw 1 repeat stick key if key&32 : break wait 1 loop goto *start } returnこのスクリプトを実行すると、零戦がななめの編隊・F15戦闘機がV字形の編隊で出てくるはずです。
新しく加わったのはtekiルーチン。変数tkの状態で敵の種類を決めています。そして、変数tksの状態で個々の敵の表示・非表示を決めています。
◇敵の弾も配列変数w スピード・方向は乱数で決定
敵の弾を表示してみましょう。今回もまた配列変数です。buffer 1 picload "pic.bmp" screen 0,300,500 title "ShotGame" *start dim sx,8 : dim sy,8 : dim st,8 dim tx,8 : dim ty,8 : dim tks,8 dim tsx,8 : dim tsy,8 : dim tss,8 : dim tdx,8 : dim tdy,8 mx=133 : my=452 : tk=1 repeat 8 sx(cnt)=1000 : sy(cnt)=1000 loop tks(6)=1 : tks(7)=1 repeat redraw 0 color 0,0,0 : boxf stick key,31 gosub *me gosub *tkshot repeat 8 c=cnt gosub *shot gosub *teki loop redraw 1 await 10 loop *me if key&1 : mx=mx-6 : if mx<=0 : mx=0 if key&2 : my=my-6 : if my<=0 : my=0 if key&4 : mx=mx+6 : if mx>=265 : mx=265 if key&8 : my=my+6 : if my>=452 : my=452 pos mx,my gmode 2 gcopy 1,0,0,35,48 return *shot if st(c)=0 and ss=0 { if key&16 { sx(c)=mx+11 : sy(c)=my st(c)=1 : key=0 ss=40 } } else { sy(c)=sy(c)-10 if sy(c)<0 : st(c)=0 } if st(c)=1 { color 0,0,0 pos sx(c),sy(c) gmode 2 gcopy 1,35,0,12,12 } ss=ss-1 if ss<0 : ss=0 return *teki if tk=1 { if tkt=0 { repeat 6 tx(cnt)=cnt*50 loop repeat 6 ty(cnt)=cnt*40-240 loop tkt=1 } if tks(c)=0 { ty(c)=ty(c)+3 if ty(c)>500 : tks(c)=1 pos tx(c),ty(c) gmode 2 gcopy 1,47,0,51,48 } if tks(c)=1 { ty(c)=500 } repeat 8 tkm=tkm+tks(cnt) loop if tkm=8 { tkm=0 tkt=0 tk=2 repeat 8 tks(cnt)=0 loop } else { tkm=0 } } if tk=2 { if tkt=0 { repeat 6 tx(cnt)=cnt*50 loop repeat 3 ty(cnt)=cnt*40 loop repeat 3,3 ty(cnt)=200-(cnt*40) loop tkt=1 } if tks(c)=0 { ty(c)=ty(c)+3 if ty(c)>500 : tks(c)=1 pos tx(c),ty(c) gmode 2 gcopy 1,98,0,37,48 } if tks(c)=1 { ty(c)=500 } repeat 8 tkm=tkm+tks(cnt) loop if tkm=8 { tkm=0 tkt=0 tk=3 } else { tkm=0 } } if tk=3 { color 180,180,180 : boxf 50,180,250,320 color 120,120,120 : boxf 65,240,235,275 color 0,0,0 : pos 60,180 : font "",50,2 : mes "CLEAR" pos 65,240 : font "",30,2 : mes "SCORE:"+scr pos 65,290 : font "",16 : mes "※エンターキーでもう一度" redraw 1 repeat stick key if key&32 : break wait 1 loop goto *start } return *tkshot r=rnd(8) : e=rnd(8) if tss(r)=0 { tsx(r)=tx(r)+8 : tsy(r)=ty(r)+16 tdx(r)=((rnd(4)+7)-2*4) : tdy(r)=(rnd(2)+1)*8 tss(r)=1 } repeat 8 c=cnt if tss(c)=1 { pos tsx(c),tsy(c) : gcopy 1,35,12,12,12 tsx(c)+=tdx(c) : tsy(c)+=tdy(c) if (tsx(c)<0)|(tsx(c)>312)|(tsy(c)>512) : tss(c)=0 } loop returntkshotルーチンが加わりました。説明はめんどいのでしません。がんばって解釈してくださいなw
◇当たり判定をつける
弾に当たったら爆発などをして消えないと、ゲームになりません。if文を使った当たり判定を組み込みましょう。buffer 1 picload "pic.bmp" screen 0,300,500 title "ShotGame" *start dim sx,8 : dim sy,8 : dim st,8 dim tx,8 : dim ty,8 : dim tks,8 dim tsx,8 : dim tsy,8 : dim tss,8 : dim tdx,8 : dim tdy,8 mx=133 : my=452 : tk=1 repeat 8 sx(cnt)=1000 : sy(cnt)=1000 loop tks(6)=1 : tks(7)=1 repeat redraw 0 color 0,0,0 : boxf stick key,31 gosub *me gosub *tkshot repeat 8 c=cnt gosub *shot gosub *teki gosub *check loop redraw 1 await 10 loop *me if key&1 : mx=mx-6 : if mx<=0 : mx=0 if key&2 : my=my-6 : if my<=0 : my=0 if key&4 : mx=mx+6 : if mx>=265 : mx=265 if key&8 : my=my+6 : if my>=452 : my=452 pos mx,my gmode 2 gcopy 1,0,0,35,48 return *shot if st(c)=0 and ss=0 { if key&16 { sx(c)=mx+11 : sy(c)=my st(c)=1 : key=0 ss=40 } } else { sy(c)=sy(c)-10 if sy(c)<0 : st(c)=0 } if st(c)=1 { color 0,0,0 pos sx(c),sy(c) gmode 2 gcopy 1,35,0,12,12 } ss=ss-1 if ss<0 : ss=0 return *teki if tk=1 { if tkt=0 { repeat 6 tx(cnt)=cnt*50 loop repeat 6 ty(cnt)=cnt*40-240 loop tkt=1 } if tks(c)=0 { ty(c)=ty(c)+3 if ty(c)>500 : tks(c)=1 pos tx(c),ty(c) gmode 2 gcopy 1,47,0,51,48 } if tks(c)=1 { ty(c)=500 } repeat 8 tkm=tkm+tks(cnt) loop if tkm=8 { tkm=0 tkt=0 tk=2 repeat 8 tks(cnt)=0 loop } else { tkm=0 } } if tk=2 { if tkt=0 { repeat 6 tx(cnt)=cnt*50 loop repeat 3 ty(cnt)=cnt*40 loop repeat 3,3 ty(cnt)=200-(cnt*40) loop tkt=1 } if tks(c)=0 { ty(c)=ty(c)+3 if ty(c)>500 : tks(c)=1 pos tx(c),ty(c) gmode 2 gcopy 1,98,0,37,48 } if tks(c)=1 { ty(c)=500 } repeat 8 tkm=tkm+tks(cnt) loop if tkm=8 { tkm=0 tkt=0 tk=3 } else { tkm=0 } } if tk=3 { color 180,180,180 : boxf 50,180,250,320 color 120,120,120 : boxf 65,240,235,275 color 0,0,0 : pos 60,180 : font "",50,2 : mes "CLEAR" pos 65,240 : font "",30,2 : mes "SCORE:"+scr pos 65,290 : font "",16 : mes "※エンターキーでもう一度" redraw 1 repeat stick key if key&32 : break wait 1 loop goto *start } return *tkshot r=rnd(8) : e=rnd(8) if tss(r)=0 { tsx(r)=tx(r)+8 : tsy(r)=ty(r)+16 tdx(r)=((rnd(4)+7)-2*4) : tdy(r)=(rnd(2)+1)*8 tss(r)=1 } repeat 8 c=cnt if tss(c)=1 { pos tsx(c),tsy(c) : gcopy 1,35,12,12,12 tsx(c)+=tdx(c) : tsy(c)+=tdy(c) if (tsx(c)<0)|(tsx(c)>312)|(tsy(c)>512) : tss(c)=0 } loop return *check if tk=1 { repeat 8 if (sx(cnt)+12>=tx(c))&(sx(cnt)<=tx(c)+51)&(sy(cnt)+12>=ty(c))&(sy(cnt)<=ty(c)+48) { gcopy 1,135,0,36,48 tks(c)=1 scr=scr+10 ty(c)=500 } loop } if tk=2 { repeat 8 if (sx(cnt)+12>=tx(c))&(sx(cnt)<=tx(c)+37)&(sy(cnt)+12>=ty(c))&(sy(cnt)<=ty(c)+48) { gcopy 1,135,0,36,48 tks(c)=1 scr=scr+10 ty(c)=500 } loop } if (mx+35>=tsx(c))&(mx<=tsx(c)+12)&(my+48>=tsy(c))&(my<=tsy(c)+12) { color 180,180,180 : boxf 50,180,250,320 color 120,120,120 : boxf 65,240,235,275 color 0,0,0 : pos 60,190 : font "",30,2 : mes "GAMEOVER" pos 65,240 : font "",30,2 : mes "SCORE:"+scr pos 65,290 : font "",16 : mes "※エンターキーでもう一度" redraw 1 repeat stick key if key&32 : break wait 1 loop goto *start } return
◆完成スクリプト
buffer 1 picload "pic.bmp" screen 0,300,500 title "ShotGame" *start dim sx,8 : dim sy,8 : dim st,8 dim tx,8 : dim ty,8 : dim tks,8 dim tsx,8 : dim tsy,8 : dim tss,8 : dim tdx,8 : dim tdy,8 mx=133 : my=452 : tk=1 repeat 8 sx(cnt)=1000 : sy(cnt)=1000 loop tks(6)=1 : tks(7)=1 repeat redraw 0 color 0,0,0 : boxf gosub *icon stick key,31 gosub *me gosub *tkshot repeat 8 c=cnt gosub *shot gosub *teki gosub *check loop redraw 1 await 10 loop *icon color 200,200,200 : boxf 0,0,120,30 color 0,0,0:pos 0,5:font "",20,1 mes "SCORE:"+scr return *me if key&1 : mx=mx-6 : if mx<=0 : mx=0 if key&2 : my=my-6 : if my<=0 : my=0 if key&4 : mx=mx+6 : if mx>=265 : mx=265 if key&8 : my=my+6 : if my>=452 : my=452 pos mx,my gmode 2 gcopy 1,0,0,35,48 return *shot if st(c)=0 and ss=0 { if key&16 { sx(c)=mx+11 : sy(c)=my st(c)=1 : key=0 ss=40 } } else { sy(c)=sy(c)-10 if sy(c)<0 : st(c)=0 } if st(c)=1 { color 0,0,0 pos sx(c),sy(c) gmode 2 gcopy 1,35,0,12,12 } ss=ss-1 if ss<0 : ss=0 return *teki if tk=1 { if tkt=0 { repeat 6 tx(cnt)=cnt*50 loop repeat 6 ty(cnt)=cnt*40-240 loop tkt=1 } if tks(c)=0 { ty(c)=ty(c)+3 if ty(c)>500 : tks(c)=1 pos tx(c),ty(c) gmode 2 gcopy 1,47,0,51,48 } if tks(c)=1 { ty(c)=500 } repeat 8 tkm=tkm+tks(cnt) loop if tkm=8 { tkm=0 tkt=0 tk=2 repeat 8 tks(cnt)=0 loop } else { tkm=0 } } if tk=2 { if tkt=0 { repeat 6 tx(cnt)=cnt*50 loop repeat 3 ty(cnt)=cnt*40 loop repeat 3,3 ty(cnt)=200-(cnt*40) loop tkt=1 } if tks(c)=0 { ty(c)=ty(c)+3 if ty(c)>500 : tks(c)=1 pos tx(c),ty(c) gmode 2 gcopy 1,98,0,37,48 } if tks(c)=1 { ty(c)=500 } repeat 8 tkm=tkm+tks(cnt) loop if tkm=8 { tkm=0 tkt=0 tk=3 } else { tkm=0 } } if tk=3 { color 180,180,180 : boxf 50,180,250,320 color 120,120,120 : boxf 65,240,235,275 color 0,0,0 : pos 60,180 : font "",50,2 : mes "CLEAR" pos 65,240 : font "",30,2 : mes "SCORE:"+scr pos 65,290 : font "",16 : mes "※エンターキーでもう一度" redraw 1 repeat stick key if key&32 : break wait 1 loop goto *start } return *tkshot r=rnd(8) : e=rnd(8) if tss(r)=0 { tsx(r)=tx(r)+8 : tsy(r)=ty(r)+16 tdx(r)=((rnd(4)+7)-2*4) : tdy(r)=(rnd(2)+1)*8 tss(r)=1 } repeat 8 c=cnt if tss(c)=1 { pos tsx(c),tsy(c) : gcopy 1,35,12,12,12 tsx(c)+=tdx(c) : tsy(c)+=tdy(c) if (tsx(c)<0)|(tsx(c)>312)|(tsy(c)>512) : tss(c)=0 } loop return *check if tk=1 { repeat 8 if (sx(cnt)+12>=tx(c))&(sx(cnt)<=tx(c)+51)&(sy(cnt)+12>=ty(c))&(sy(cnt)<=ty(c)+48) { gcopy 1,135,0,36,48 tks(c)=1 scr=scr+10 ty(c)=500 } loop } if tk=2 { repeat 8 if (sx(cnt)+12>=tx(c))&(sx(cnt)<=tx(c)+37)&(sy(cnt)+12>=ty(c))&(sy(cnt)<=ty(c)+48) { gcopy 1,135,0,36,48 tks(c)=1 scr=scr+10 ty(c)=500 } loop } if (mx+35>=tsx(c))&(mx<=tsx(c)+12)&(my+48>=tsy(c))&(my<=tsy(c)+12) { color 180,180,180 : boxf 50,180,250,320 color 120,120,120 : boxf 65,240,235,275 color 0,0,0 : pos 60,190 : font "",30,2 : mes "GAMEOVER" pos 65,240 : font "",30,2 : mes "SCORE:"+scr pos 65,290 : font "",16 : mes "※エンターキーでもう一度" redraw 1 repeat stick key if key&32 : break wait 1 loop goto *start } return
|
|
iconサブルーチンでスコアを表示するようにしただけですw
