HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2008
0522
シューティングゲームについて10解決


リンク

2008/5/22(Thu) 22:49:22|NO.15998

こんばんは。初めてのプログラミングでわからない所があり、
いろいろなサイトを探しサンプルスクリプト等をみて調べてやってみたのですが
やっぱりわからなくて・・・なのでHSP3の先輩の方々に聞こうと思い書き込みしました。
自分は、本を買いHSP3を始めたので、本の解説が載っている所まではできました
より楽しくプレイできるように改造を加えたいと思ってます。
どうか、ご指南よろしくお願いします。(少し長くなります・・・すいません)


*hazime randomize ; 乱数パターンを不定に buffer 1 ; ウィンドウ1をバッファ画面として用意 picload "shot_chrs.bmp" ; 使用する画像を読み込む wxs=320 :wys=400 ; screen 0,wxs,wys ; メイン画面(ウィンドウ0)を320×400ドットで出す title "マキシ of シューティング" ; タイトルバーにタイトル表示 font "Century Gothic",16 ; フォント指定 mmload "shot.wav" ; 効果音を読み込む mmload "hit.wav",1 ; mmload "bomb.wav",2 ; picload "title.bmp",1 ; タイトル画面 gosub *pse ; loop *start stg+ ; cls 4 :color 255,255,255 ; ステージ表示 pos 128,192 :mes "STAGE "+stg ; gosub *pse ; fnm="bgm"+strf("%02d",stg\3)+".mid" ; mmload fnm,3,1 ; BGMを読み込み、 mmplay 3 ; 鳴らす buffer 2 ; 背景とスクロールの設定 fnm="back"+strf("%02d",stg\3)+".bmp" ; picload fnm ; ssp=ginfo_winy-wys ; px=144 :py=352 ; 自機の初期座標 hp+=10 ; ライフ tmx=3 ; 自機弾の数 dim tx,tmx :dim ty,tmx ; 自機弾の座標の配列変数 dim tf,tmx ; 自機弾フラグの配列変数 nrm=3*stg ; 敵ノルマ emx=stg/2+2 ; 敵の数 dim ex,emx :dim ey,emx ; 敵の座標の配列変数 dim dx,emx :dim dy,emx ; 敵の移動方向の配列変数 dim ehp,emx ; esp=6 ; 敵の移動速度 foreach ex :c=cnt ; 敵の初期配置を設定 gosub *enmset ; loop ; etmx=8 ; 敵弾の数 dim etx,etmx :dim ety,etmx ; 敵弾の座標の配列変数 dim tdx,etmx :dim tdy,etmx ; 敵弾の移動方向の配列変数 dim etf,etmx ; 敵弾フラグの配列変数 gsel 0 ; メイン画面選択 *main redraw 0 ; 画面に反映しない(仮想画面は書き換わる) gmode 1 ; ノーマルコピーモード scr=(scr+ssp)\wys ; コピー元座標算出 pos 0,scr :gcopy 2,0,0,wxs,wys-scr ; if scr!0 { pos 0,0 ; 背景画像をコピー gcopy 2,0,wys-scr,wxs,scr ; } ; gmode 2 ; 透明色コピーモード if hp>0 { stick ky,15 ; キー入力値取得 if ky&1 :px=limit(px-8,8,280) ; 自機座標の加減算 if ky&4 :px=limit(px+8,8,280) ; if ky&2 :py=limit(py-8,8,360) ; if ky&8 :py=limit(py+8,8,360) ; pos px,py ; (px,py)座標に位置指定 gcopy 1,0,68,34,35 ; 自機表示( バッファ選択 ,縦 ,横 ,縦 ,横 ) } foreach tf :c=cnt if tf(c)=0 { ; if ky&16 { mmplay 0 ; 自機弾の発射セット tx(c)=px+8 :ty(c)=py-16 ; tf(c)=1 :ky=0 ; } } else :ty(c)-=16 :if ty(c)<0 :tf(c)=0 ; 自機弾を進める if tf(c)=1 :gosub *hitchk ; 発射中の自機弾チェック loop if (nrm>ecn)&(emx>ecn) { ; ノルマ数以下なら敵を発生 c=rnd(emx) :if ehp(c)<1 :gosub *enmset ; } foreach ehp :c=cnt if ehp(c)>0 { if r=0 :gosub *enmvec ; 敵の動きを乱数で決定 x=ex(c) :ex(c)+=dx(c) if (ex(c)<8)|(wxs-40<ex(c)) :ex(c)=x :dx(c)=-dx(c) ; 左右の壁で反転 y=ey(c) :ey(c)+=dy(c) ; ey(c) c=縦の動き if (ey(c)<-24)|(wys-8<ey(c)) :gosub *enmpoi ; 画面下に消えたら再配置 r=rnd(10) pos ex(c),ey(c) gcopy 1,96,4,37,35 ; 敵表示( バッファ選択 ,縦 ,横 ,縦 ,横 ) } loop r=rnd(etmx) :e=rnd(emx) ; 敵弾の発射セット if (etf(r)=0)&(ehp(e)>0) { ; etx(r)=ex(e)+8 :ety(r)=ey(e)+16 ; tdx(r)=(rnd(5)-2)*4 :tdy(r)=(rnd(2)+1)*8 ; etf(r)=1 } foreach etf :c=cnt if etf(c)=1 { ; 敵弾と自機の当たり判定 if (abs(px-etx(c))<16)&(abs(py-ety(c))<16) { ; mmplay 1 :etf(c)=0 :hp- :gosub *bom_p ; 爆発をセット } pos etx(c),ety(c) :gcopy 1,80,0,16,16 ; 敵弾の表示 etx(c)+=tdx(c) :ety(c)+=tdy(c) ; tdy(c)とtdx(c)=弾速が変わるタイミング  etx(c)=弾横移動 if (etx(c)<0)|(etx(c)>304)|(ety(c)>384) :etf(c)=0 ; 移動の処理 } loop color 255,255,255 ; pos 273,363 :mes strf("%05d",sc*10) ; スコア表示 pos 257,380 :mes "Enemy "+nrm ; 敵撃墜ノルマ表示 pos 8,wys-32 :mes "HP "+hp ; 自機の耐久力表示 if bmc>0 { bmc- :pos bmx,bmy ; gcopy 1,32*(2-bmc),32,32,32 ; 爆発アニメ表示 } redraw 1 ; 画面の更新 wait 5 ; 0.05秒待つ foreach ehp :c=cnt if (ehp(c)>0)&(abs(px-ex(c))<24)&(abs(py-ey(c))<24) { ; 自機と敵の当たり判定 hp-=ehp(c) :ehp(c)=0 :gosub *bom_e ; 爆発をセット } ; loop if (hp>0)&(ecn>0) :goto *main ; 自機と敵が健在なら *main にジャンプ if bmc>0 :goto *main ; 爆発中なら *main にジャンプ mmstop redraw 1 ; ゲームオーバー処理 if stg>9 { ; pos 112,192 :mes "クリア!" ; pos 115,225 ; goto *owaru ; } goto *start ; 敵の初期座標・移動方向をセット *enmset ehp(c)=3 :ecn+ ; 敵の発生 *enmpoi ex(c)=rnd(wxs-32) :ey(c)=-24 ; 初期座標 *enmvec dx(c)=(rnd(5)-2)*esp :dy(c)=rnd(3)*esp ; 移動方向 return ; 自機弾と敵の当たり判定 *hitchk foreach ehp if (ehp(cnt)>0)&(abs(ex(cnt)-tx(c))<24)&(abs(ey(cnt)-ty(c))<32) { mmplay 1 :tf(c)=0 :ehp(cnt)- if ehp(cnt)<1 :gosub *bom_e ; 耐久値<1なら敵1機撃墜 } else { pos tx(c),ty(c) ; 自機弾の表示 gcopy 1,0,68,34,35 ; ( バッファ選択 ,縦 ,横 ,縦 ,横 ) } loop return ; 爆発アニメのセット ; *bom_e bmc=3 :bmx=ex(cnt) :bmy=ey(cnt) ecn- :nrm- :sc+ :mmplay 2 *bom_p if hp<1 :bmc=3 :bmx=px :bmy=py :mmplay 2 return ; キー入力待ち *pse wait 1 stick ky :if ky=16 :return goto *pse *owaru dialog "GAME SET \n最初からしますか?",2,"GAME SET" if stat =6 :goto *hazimari end
質問は4つあります。
一つ目は
メインになる敵を打ち落としたり、次のステージ移行等は問題なくできるのですが、
ステージ10でHPに関係なく終わらしたいため *owari の部分を作ってます。
ダイアログはしっかり出てきて、ちゃんと作動しています。ここまではいいのですが
「最初からしますか?」と問い「はい」と答えるとステージ1に行くのではなく、
そのままステージ11に行ってしまうのです。
どうすれば、ステージ1に戻れるでしょうか。

二つ目は
自機と敵機の当たり判定はいいのですが
自機と敵弾の当たり判定がズレています。
いろいろ弄くって、どうすれば正常な位置にいけるかやってみたのですが
それもわからず断念しています・・・どこの数値が判定と対応しているのでしょうか?

三つ目は
敵の種類を増やしたいのですが、どのように処理すればいいでしょうか?
移動、弾数、出現数、耐久値、ほとんどを変えたいのですが・・・

四つ目は
シューティングでは必ずといっていいほどある
いわゆる「ボム」を作りたいのですが。
こちらもどのようにすればいいでしょうか?

長文・駄文本当にすいません。
どうかご指南お願いします。



この記事に返信する


アイソレ

リンク

2008/5/22(Thu) 23:05:39|NO.15999

まず、作っているのをそのままスクリプトを持ってくるのではなく
こちらで実行して動作できるような感じにした方がいいですよ。
なのでキャラクタの部分は記号で、背景はboxfのなどで、
BGMなどや爆発表示のも抜いて、もっとスッキリ
としたスクリプトでないと皆さんは答えてはくれないとは思いますよ。



リンク

2008/5/22(Thu) 23:48:19|NO.16000

アイソレさん。ご指摘ありがとうございます。

*hazime randomize buffer 1 ; ウィンドウ1をバッファ画面として用意 wxs=320 :wys=400 ; screen 0,wxs,wys ; メイン画面(ウィンドウ0)を320×400ドットで出す font "Century Gothic",16 ; フォント指定 gosub *pse ; *start stg+ ; cls 4 :color 255,255,255 ; ステージ表示 pos 128,192 :mes "STAGE "+stg ; gosub *pse px=144 :py=352 ; 自機の初期座標 hp=10 ; 自機の耐久値 tmx=3 ; 自機弾の数 dim tx,tmx :dim ty,tmx ; 自機弾の座標の配列変数 dim tf,tmx ; 自機弾フラグの配列変数 nrm=3*stg ; 敵ノルマ emx=stg/2+2 ; 敵の数 dim ex,emx :dim ey,emx ; 敵の座標の配列変数 dim dx,emx :dim dy,emx ; 敵の移動方向の配列変数 dim ehp,emx esp=6 ; 敵の移動速度 foreach ex :c=cnt ; 敵の初期配置を設定 gosub *enmset ; loop ; etmx=8 ; 敵弾の数 dim etx,etmx :dim ety,etmx ; 敵弾の座標の配列変数 dim tdx,etmx :dim tdy,etmx ; 敵弾の移動方向の配列変数 dim etf,etmx ; 敵弾フラグの配列変数 *main redraw 0 ; 画面に反映しない(仮想画面は書き換わる) color 0,0,0 ; 色を黒に選択 boxf 0,0,319,399 ; 画面を塗りつぶす if hp>0 { stick ky,15 ; キー入力値取得 if ky&1 :px=limit(px-8,8,280) ; 自機座標の加減算 if ky&4 :px=limit(px+8,8,280) ; if ky&2 :py=limit(py-8,8,360) ; if ky&8 :py=limit(py+8,8,360) ; pos px,py ; (px,py)座標に位置指定 gcopy 1,0,0,32,32 ; ウィンドウ1から自機の部分をコピー } foreach tf :c=cnt if tf(c)=0 { ; if ky&16 { mmplay 0 ; 自機弾の発射セット tx(c)=px+8 :ty(c)=py-16 ; tf(c)=1 :ky=0 ; } ; } else :ty(c)-=16 :if ty(c)<0 :tf(c)=0 ; 自機弾を進める if tf(c)=1 :gosub *hitchk ; 発射中の自機弾チェック loop if (nrm>ecn)&(emx>ecn) { ; ノルマ数以下なら敵を発生 c=rnd(emx) :if ehp(c)<1 :gosub *enmset ; } foreach ehp :c=cnt if ehp(c)>0 { if r=0 :gosub *enmvec ; 敵の動きを乱数で決定 x=ex(c) :ex(c)+=dx(c) ; if (ex(c)<8)|(wxs-40<ex(c)) :ex(c)=x :dx(c)=-dx(c) ; 左右の壁で反転 y=ey(c) :ey(c)+=dy(c) ; if (ey(c)<-24)|(wys-8<ey(c)) :gosub *enmpoi ; 画面下に消えたら再配置 r=rnd(10) ; pos ex(c),ey(c) ; (ex(c),ey(c))座標に位置指定 gcopy 1,32,0,32,32 ; ウィンドウ1から敵の画像部分をコピー } loop r=rnd(etmx) :e=rnd(emx) ; 敵弾の発射セット if (etf(r)=0)&(ehp(e)>0) { ; etx(r)=ex(e)+8 :ety(r)=ey(e)+16 ; tdx(r)=(rnd(5)-2)*4 :tdy(r)=(rnd(2)+1)*8 ; etf(r)=1 ; } foreach etf :c=cnt if etf(c)=1 { ; 敵弾と自機の当たり判定 if (abs(px-etx(c))<16)&(abs(py-ety(c))<16) { ; mmplay 1 :etf(c)=0 :hp- } pos etx(c),ety(c) :gcopy 1,80,0,16,16 ; 敵弾の表示 etx(c)+=tdx(c) :ety(c)+=tdy(c) ; 移動の処理 if (etx(c)<0)|(etx(c)>304)|(ety(c)>384) :etf(c)=0 ; } loop color 255,255,255 ; pos 8,wys-32 :mes "HP "+hp ; 自機の耐久力表示 color 255,255,255 ; pos 273,363 :mes strf("%05d",sc*10) ; スコア表示 pos 257,380 :mes "Enemy "+nrm ; 敵撃墜ノルマ表示 pos 8,wys-32 :mes "HP "+hp ; 自機の耐久力表示 redraw 1 ; 画面操作の結果を反映(画面の更新) wait 5 ; 0.05秒待つ foreach ehp :c=cnt if (ehp(c)>0)&(abs(px-ex(c))<24)&(abs(py-ey(c))<24) { ; 自機と敵の当たり判定 hp-=ehp(c) :ehp(c)=0 } ; loop if (hp>0)&(ecn>0) :goto *main ; 自機と敵が健在なら *main にジャンプ redraw 1 ; ゲームオーバー処理 if stg>9 { ; pos 112,192 :mes "クリア!" ; pos 115,225 ; goto *owaru ; } goto *start ; --- サブルーチン --- ; 敵の初期座標・移動方向をセット ; *enmset ehp(c)=3 :ecn+ ; 敵の発生 *enmpoi ex(c)=rnd(wxs-32) :ey(c)=-24 ; 初期座標 *enmvec dx(c)=(rnd(5)-2)*esp :dy(c)=rnd(3)*esp ; 移動方向 return ; 自機弾と敵の当たり判定 ; *hitchk foreach ehp if (ehp(cnt)>0)&(abs(ex(cnt)-tx(c))<24)&(abs(ey(cnt)-ty(c))<32) { mmplay 1 :tf(c)=0 :ehp(cnt)- if ehp(cnt)<1 ; 耐久値<1なら敵1機撃墜 } else { pos tx(c),ty(c) ; 自機弾の表示 gcopy 1,64,0,16,16 ; } loop return *pse wait 1 stick ky :if ky=16 :return goto *pse *owaru dialog "GAME SET \n最初からしますか?",2,"GAME SET" if stat =6 :goto *hazime end
キャラクタの部分を記号にする方法がわからず、スペース?みたいな感じになってます。
それ以外は大丈夫だと思います。
それでは、お願いいたします。



アイソレ

リンク

2008/5/22(Thu) 23:48:31|NO.16001

まあ、とりあえずですが、まちがっていることをいくつか指摘します
1、最後の終わるのところはgoto *hazimeでないですか?
 もしこのまま実行するとエラーだと思います
2、1番目の質問は、stgの変数を初期化してないから11の数字になるので
  stg=0で初期化しましょう。
3 あとこのスクリプトでは、自機がクリアしても、敵を倒しても
 次のステージに進んでしまうのではないですか?

あとはスクリプトをこちらでも実行できるように改造してから
じゃないと何ともいえません。(ではなくて実行できないと
見ただけではデバックが大変なので)



jill

リンク

2008/5/22(Thu) 23:54:02|NO.16002

画像や音声のリソースが無く実行できないので、あってるかどうか分かりませんが、一様参考に

1.*hazimeの最初の方に
stg=0
を入れてステージ数格納先の変数を初期化すればよいと思います。
2.142行目のコメントに
; 自機と敵の当たり判定
とあります。 ifで判定しています。最初の()が敵機の耐久力で0以上、つまり存在しているか
次の2つの()が自機と敵機のx及びy座標で、自機から敵機の座標を引いた数(ぶつかる一歩手前)が24ドットより小さければ、
当たった事になります。因みに敵弾は16ドットより小さければ、になっています。
それぞれ24という数字を変えたら判定位置が変わると思います。

3.37行目の自機弾を見てください。同じように

bmx=3 ; 自機ボムの数 dim bx,bmx :dim by,bmx ; 自機ボムの座標の配列変数 dim bf,bmx ; 自機ボムフラグの配列変数
などとしてボムの変数を作成して、81行目のように発射と移動等作れば良いと思います。

4.は敵機と書かれたコメント行をみて、どういう処理をしているか分からないと先ず無理なので
よく見て理解すれば出来ると思います。
変数の確保、移動用の座標、判定で1機分作成してください。理解出来てきたらそれぞれ既存のスクリプト
を使いまわして無駄をなくしていったら良いと思います。



アイソレ

リンク

2008/5/23(Fri) 00:30:59|NO.16004

jillさん説明うまい・・・・(^^;;

すいません。修正です。
3、自機のライフがなくなっても、敵を倒しても
次のステージに進んでしまうのではないですか?
でした。
あとはjillさんの仰る通りです。

ついでにいってしまうと。今ここのために作ったスクリプト
ですと、スコアも敵の数も更新というか、変化せず
また通り過ぎたり、倒したりしたら・・あとノルマが残っていても
敵が出現しなくなってしまいます。



リンク

2008/5/23(Fri) 01:23:54|NO.16006

アイソレさん。ありがとうございます!
1.はい。指摘されて気づきました;
  最初は *hazimari も作っていろいろ弄ってたので、そこで間違えたようです。
  申し訳ありませんでした。

2.なるほど!これで一番納得がいかなかった部分が解消されます!
  自分は、全ての命令クリアみたいな命令を使うのかと思ってました
  ありがとうございます!

3.これはわざとです。
  「ステージ10までプレイしてもらい、獲得したスコアを競う」
  というゲームにしたいと思っているのです。
  今のままだと、死なないようにしたら、最高得点が1650点?だったと思います
  なので、
  ハイスコア表示&ハイスコア記録。残りライフで変動するスコア
  ボーナスステージ。取得スコアの違う敵。ボーナスターゲット 等
  を追加していき、より楽しめたらいいなと考えています。

jillさんも、ありがとうございます!
1.これに関しては、アイソレさんの「2」と同じです
  どちらも本当にありがとうございます!

2.教えていただいたのに申し訳ないのですが
  自機と敵の弾の当たり判定がどうも左にズレてるようなのです。

foreach etf :c=cnt if etf(c)=1 { ; 敵弾と自機の当たり判定 if (abs(px-etx(c))<16)&(abs(py-ety(c))<16) { ; mmplay 1 :etf(c)=0 :hp- }
  の所です。
  16を変えたら、判定場所が変わるまではわかってるのですが
  (左側の16が横。右側の16が縦だと思ってます)
  なんと言えばいいのかよくわからないので、わかりにくいと思いますが
  この16を変えても、判定場所が移動するのではなく、判定する範囲が広がるだけ、だと思うのです。
  多分?ですが、判定の中心地が決まっていて
  そこから左右に 16pixel 広がるのだと思います。
  そして、その中心地を決めている命令がわからないのです。
  何度も申し訳ありませんが、教えてください。お願い致します。

3.わかりました!

if (ehp(cnt)>0)&(abs(ex(cnt)-tx(c))<24)&(abs(ey(cnt)-ty(c))<32)
  だと、24と32が弾の範囲ですよね?
  これを広げて、画像と効果音をつければいいという事ですね
  がんばってみます!

4.ここが一番難しそうですが、がんばってみます。
  
アイソレさん、jillさん
二人とも本当にありがとうございます。
ですが、当たり判定が未だわかってません;
できれば、また教えてください。
本当にありがとうございました。



アイソレ

リンク

2008/5/23(Fri) 01:52:38|NO.16007

あれは仕様でしたか・・・(^^;

今日は仕事帰りで眠いので頭が回っていませんが。
(間違っていたらすみません)
絶対値(abs)を使わないでやってみてはどうでしょうか?
(当たり判定の意味がわかってないとだめかもしれませんが)



jill

リンク

2008/5/23(Fri) 19:34:34|NO.16044

アイヤーすっかり勘違いしてました。
てっきり自機と敵機の判定がずれていると思ってました。
よく読んだら敵弾ですね、しかも判定のサイズがずれているのではなく、中心からずれていると

実行できていないので多分ですが、敵弾の表示が判定の後に来ているのでズレてるように見える
のだと思います。
敵弾の表示を判定よりも上に持っていって様子みてください。



アイソレ

リンク

2008/5/23(Fri) 19:54:06|NO.16048

時 貴斗様のサイトで、シューティングの講座について
書かれています。非常にためになると思いますので参考にしては
いかがでしょうか?(参考書だけや、こちらでの言葉の説明だけでは
少し限界がありますので)

ボムのことや当たり判定の事を含めいろいろなことが書いてあるので
オススメです。

http://f55.aaa.livedoor.jp/~mclass/hsplecture/index.htm



リンク

2008/5/24(Sat) 01:27:40|NO.16058

jillさん。ありがとうございます。
今から、そのように修正し、試してみようと思います。

アイソレさん。ありがとうございます。
まだ少ししか見てませんが、とても参考になると思いました。
このようなサイトを教えてもらいありがとうございました。

わかりにくい説明。みにくくて実行のできないスクリプト。等
面倒な質問をしたのに丁寧に教えていただき本当にありがとうございます。
また、何かありましたらその時もどうか、よろしくお願い致します。



ONION software Copyright 1997-2023(c) All rights reserved.