敵が弾を撃つ(3/4) |
4.敵の弾を移動する |
存在する弾だけを移動します。固定小数の座標(smeshotx,smeshoty)に移動量(smeshotdx,smeshotdy)を足しこみます。足した後、整数の座標(eshotx,eshoty)に直します。
弾が画面の外に出たら、消去します。
repeat 100
if eshotf.cnt=1 {
smeshotx.cnt=smeshotx.cnt+smeshotdx.cnt
eshotx.cnt=smeshotx.cnt>>8
smeshoty.cnt=smeshoty.cnt+smeshotdy.cnt
eshoty.cnt=smeshoty.cnt>>8
if (eshotx.cnt+8<=0)|(eshotx.cnt>=xsize)|(eshoty.cnt+8<=0)|
(eshoty.cnt>=ysize) { eshotf.cnt=0 }
}
loop
表示する時や、自機との当たり判定を行う時には、(eshotx,eshoty)を使います。だったらsmeshotx、smeshotyはいらないんじゃないの? と思う方がいるかもしれません。つまり、
eshotx.cnt=eshotx.cnt+(smeshotdx.cnt>>8)
eshoty.cnt=eshoty.cnt+(smeshotdy.cnt>>8)
で十分なんじゃないかと。これは、敵弾の移動処理を行うたびに、小数点以下を切り捨ててしまうという事です。すると誤差がどんどん大きくなっていき、自機に向かっていってくれません。
5.敵の弾を表示する |
敵の弾を表示します。
repeat 100
if eshotf.cnt=1 {
gdx=eshotx.cnt:gdy=eshoty.cnt
gdox=$70:gdoy=0
gdw=8:gdh=8
gosub *Graphic_Draw
}
loop
以上をまとめますと、敵が弾を撃つ処理は以下のようになります。
; プログラム起動時の初期設定 #include "hspext.as" ; sin,cosの値 dim vsin,256 dim vcos,256 repeat 256 emcos x,cnt emsin y,cnt vcos.cnt=x vsin.cnt=y loop ; 敵の弾の変数宣言 dim eshotf,100 dim eshotx,100:dim eshoty,100 dim smeshotx,100:dim smeshoty,100 dim smeshotdx,100:dim smeshotdy,100 ; ステージスタート時の初期設定 repeat 100 eshotf.cnt=0 loop ; メインループ ; 敵弾の移動 repeat 100 if eshotf.cnt=1 { smeshotx.cnt=smeshotx.cnt+smeshotdx.cnt eshotx.cnt=smeshotx.cnt>>8 smeshoty.cnt=smeshoty.cnt+smeshotdy.cnt eshoty.cnt=smeshoty.cnt>>8 if (eshotx.cnt+8<=0)|(eshotx.cnt>=xsize)|(eshoty.cnt+8<=0)| (eshoty.cnt>=ysize) { eshotf.cnt=0 } } loop ; 敵弾の出現 repeat 10 if (enemyf.cnt=1)&(enemyx.cnt>=0)&(enemyx.cnt<=(xsize-32))&(enemyy.cnt>=0) &(enemyy.cnt<=(ysize-32))&(enemycnt.cnt\64=0) { n=cnt repeat 100 if eshotf.cnt=0 { eshotf.cnt=1 eshotx.cnt=enemyx.n+12 eshoty.cnt=enemyy.n+12 smeshotx.cnt=eshotx.cnt<<8 smeshoty.cnt=eshoty.cnt<<8 ematan r,playerx+12-eshotx.cnt ,playery+12-eshoty.cnt r=(192-r)&255 smeshotdx.cnt=6*vcos.r smeshotdy.cnt=6*vsin.r break } loop } loop ; 敵弾を描画 repeat 100 if eshotf.cnt=1 { gdx=eshotx.cnt:gdy=eshoty.cnt gdox=$70:gdoy=0 gdw=8:gdh=8 gosub *Graphic_Draw } loop見栄えのために長い命令文には途中に改行を入れていますが、実際には改行を入れるとエラーになったり、動作がおかしくなったりします。
実行画面
ひとくちメモ: |
・角度についての補足 |
HSPEXTの角度は0度が0.0、360度が1.0ですが、いちいち頭の中で固定小数に直さなくても、0から始まって256で一周する角度だと思った方が、考えやすいかと思います。(1あたり360/256=1.41度)
|
・HSPEXTのマニュアル |
HSPEXTのマニュアルは、HSPをインストールしたフォルダ(HSP Ver2.6の場合、デフォルトではC:\Program Files\hsp26)の、docsフォルダの下にあります。hspext.txtです。この中には、他にもHSPDX.DLLのマニュアル(hspdx.txt)等、いろいろなドキュメントが入っています。 これらは、直にテキストファイルを開いてもいいのですが、HSPをインストールしたフォルダにあるindex.htmをブラウザで開くと、メニューから選んで読めるので、そっちの方がいいです。 自分が作ったゲームをインターネット等で配布する場合には、ゲームの実行ファイルがあるフォルダにdllファイルをコピーする必要があります。本講座の場合、hmm.dllとhspext.dllです。hspext.dllは、HSPをインストールしたフォルダにあります。 |
・難易度の調整 |
今、敵が弾を撃つ間隔を64回に1回という大きめの間隔にしています。そのため、結果的に1匹の敵は1回しか弾を撃ちません。まだ敵と自機の弾の当たり判定を作っていないので分からないのですが、ひょっとしたら敵が弾を撃つ前にほとんど撃破してしまって、全然弾を撃ってこないという事態になるかもしれません。逆に、64回に1回でもまだ小さいかもしれません。これは、当たり判定を作ってみないと分かりません。他にも、敵の出現間隔、1度に何匹出すか、自機の弾の出現間隔、画面内に何発まで存在できるか、といった数値は、難易度に大きくかかわってくるものです。開発の進行に伴って、うまくなければ調整する必要があります。
|
・優先順位と比較演算子 |
計算には、優先順位があります。例えばa+b*cという計算は、掛け算b*cが先に行われ、aとその結果を足します。つまり、掛け算の方が足し算より優先順位が高いのです。しかし、HSPでは自動的に優先順位を判別してくれません。左から順に計算されます。つまり、HSPではa+b*cは(a+b)*cと同じです。先にやってほしい計算を、カッコで囲む必要があります。つまり、HSPではa+b*cをa+(b*c)と書きます。 "+","*","/","\"等は「演算子」といいます。if文の条件式の中に出てくる"=","!",">","<="等も、実は「比較演算子」という演算子なのです。これは、条件が成り立てば1、成り立たなければ0を返します。a>8という計算の答は、aが8より大きい時1、aが8以下の時0になります。(1は真、0は偽を表します。) ですから、if文以外でもこれらの計算を行うことができます。 a=3 b=a=3 c=a>5 この場合、bには1が、cには0が代入されます。なお、各行の2文字目の"="は「代入」であって比較演算子ではありません。 if 条件式 { 命令 } は、条件式を計算し、その結果が0でなければ命令を実行し、0だったら実行しないようになっているのです。条件式には、比較演算子以外の演算子を使った式も書けます。 a=1 if a { mes "abc" } b=0 if b { mes "de" } if a+b { mes "fgh" } stop この実行結果は、"abc"と"fgh"が表示され、"de"は表示されません。 if w+x>y+z { …… } という書き方をすると、演算は左から順に行われるので、 if ((w+x)>y)+z { …… } と同じ意味になってしまいます。w+xがyより大きい時、"if 1+z { …… }"という意味に、w+xがy以下の時、"if 0+z { …… }"という意味になります。 「もしw+xがy+zより大きいならば」、という意味にしたい時には、y+zの方を先に計算しなければなりませんから、 if w+x>(y+z) { …… } と書く必要があります。 |