前章の続きです。
最初の予定では、自機・敵機共にダメージ制で自機弾に数種のウェポンを持っているとのことでした。
それについてはまた後ほど出てきますのでお楽しみに。
まずは前章最後に書く(ダウンロードできる)予定だったスクリプトを書きます。
#define WX 640
#define WY 480
#define SIZE 25
#define TSIZE 10
#define TMAX 40
#define TSPEED 8
#define MSPEED 5
#define ENMSPEED 10
#define ENMMAX 8
#define STAR 1000
#include "motion.as"
dim count,1
dim mx,1
dim my,1
dim cartridge,TMAX
dim tx,TMAX
dim ty,TMAX
dim enemy,ENMMAX
dim enmx,ENMMAX
dim enmy,ENMMAX
dim direction,ENMMAX
dim tm1,30
dim tm2,30
mx=WX-SIZE/2
my=WY-50
tm1=1,1,1,1,1,2,2,2,2,2,1,1,2,1,2,2,1,1,3,3,1,3,1,3,3,1,2,2,3,4
tm2.0 = 30, 70, 110, 130, 150, 200, 240, 275, 310, 340
tm2.10 = 365, 415, 440, 460, 480, 500, 525, 540, 560, 590
tm2.20 = 600, 620, 650, 675, 700, 730, 740, 750, 760, 850
randomize
buffer 2,WX,WY*2
color 1,1,1 : boxf : color 255,255,255
repeat STAR
rnd tmp,WX
rnd tmp.1,WY
pset tmp,tmp.1
loop
pos 0,WY : gcopy 2,0,0,WX,WY
buffer 3,256,SIZE*2
color : boxf
color ,,255
font "MS 明朝",10
pos 0,0 : mes "●"
color 230,150
pos 0,TSIZE : mes "●"
color 200
font "MS 明朝",SIZE
pos TSIZE,0 : mes "▲"
color ,200
pos SIZE+TSIZE,0 : mes "▼"
color ,150,150
pos SIZE*2+TSIZE,0 : mes "▼"
color 100,100
pos SIZE*3+TSIZE,0 : mes "▼"
color 230,230
font "MS 明朝",SIZE*2
pos SIZE*4+TSIZE,-5 : mes "▼"
repeat 256
color 255-cnt,cnt
line cnt,SIZE*2-10,cnt,SIZE*2
loop
; ---------- ココまでが準備 ----------
gsel 0
gmode 2
*main
redraw 0
gosub *back
gosub *body
gosub *tama
gosub *action
gosub *enmgene
gosub *enmaction
redraw
await 10
count+
goto *main
*back
pos 0,0 : gcopy 2,0,-count\WY+WY,WX,WY
return
*body
pos mx,my : gcopy 3,TSIZE,0,SIZE,SIZE
repeat ENMMAX
if enemy.cnt=1 : pos enmx.cnt,enmy.cnt : gcopy 3,SIZE+TSIZE,0,SIZE,SIZE
if enemy.cnt=2 : pos enmx.cnt,enmy.cnt : gcopy 3,SIZE*2+TSIZE,0,SIZE,SIZE
if enemy.cnt=3 : pos enmx.cnt,enmy.cnt : gcopy 3,SIZE*3+TSIZE,0,SIZE,SIZE
if enemy.cnt=4 : pos enmx.cnt,enmy.cnt : gcopy 3,SIZE*4+TSIZE,0,SIZE*2,SIZE*2-10
loop
return
*tama
repeat TMAX
if cartridge.cnt=1 {
pos tx.cnt,ty.cnt : gcopy 3,0,0,TSIZE,TSIZE
ty.cnt-=8
if -TSIZE>ty.cnt : cartridge.cnt=0
}
loop
return
*action
stick key,31,1
if key&1 : mx-=MSPEED : if mx<0 : mx=0
if key&2 : my-=MSPEED : if my<0 : my=0
if key&4 : mx+=MSPEED : if WX-SIZE<mx : mx=WX-SIZE
if key&8 : my+=MSPEED : if WY-SIZE<my : my=WY-SIZE
if key&16 : if shottime=0 : shottime=5 : gosub *generation : else : shottime-
return
*generation
repeat TMAX
if cartridge.cnt=0 : cartridge.cnt=1 : tx.cnt=SIZE-TSIZE/2+mx : ty.cnt=my-TSIZE : break
loop
return
*enmgene
if tm3>29 : return
if count<tm2.tm3|(tm3.1>=ENMMAX) : return
repeat ENMMAX
if enemy.cnt=0 {
enemy.cnt=tm1.tm3
rnd enmx.cnt,WX/2 : enmx.cnt+=WX/4
enmy.cnt=0
rnd direction.cnt,2 : if enemy.cnt=4 : direction.cnt+
break
}
loop
if tm3<30 : tm3+
tm3.1+
return
*enmaction
repeat ENMMAX
if enemy.cnt=0 : continue
if enemy.cnt : motion cnt
loop
return
前章飛ばしてこの章から始めようとするといきなり長いスクリプトがコメントなしで来るので
着いてこられなくなっても知りません。素直に前章から始めてくださいね。
また初めの方にモジュールが結合されているのも前章知らない方は分からないことでしょう。
さてそれでは上記スクリプトに自機の当たり判定を入れていきましょう。
すべての敵弾とのチェックが必要ですので敵弾数分ループさせ当たり判定をしましょう。
まず準備コメントまでに下記の使用するものを追加してください。
#define ENMTMAX 60 ; 敵弾の最大数 dim clear,1 ; クリアフラグ dim power,1 ; 自機耐久力 dim enmtinfo,ENMTMAX ; 敵弾情報 dim enmtx,ENMTMAX ; 敵弾X座標 dim enmty,ENMTMAX ; 敵弾Y座標 power=150
次にmain,tama,enmactionラベル内に下記を追加してください。
*main
:
gosub *hitcheck ; 自機との当たり判定
if clear : goto *gamestop ; ゲームオーバー=-1 , ゲームクリア=1
:
; repeat-loop間に追加しても構わないが重くなるのでループ外のほうが断然よい
*tama
:
repeat ENMTMAX ; 敵弾の描画
if enmtinfo.cnt=0 : continue
pos enmtx.cnt,enmty.cnt : gcopy 3,0,TSIZE,TSIZE,TSIZE
switch enmtinfo.cnt
case 1 : enmty.cnt+=TSPEED : swbreak
case 2 : enmtx.cnt-=TSPEED*2/3 : enmty.cnt+=TSPEED*2/3 : swbreak
case 3 : enmtx.cnt+=TSPEED*2/3 : enmty.cnt+=TSPEED*2/3 : swbreak
case 4 : enmty.cnt-=TSPEED : swbreak
case 5 : enmtx.cnt-=TSPEED*2/3 : enmty.cnt-=TSPEED*2/3 : swbreak
case 6 : enmtx.cnt+=TSPEED*2/3 : enmty.cnt-=TSPEED*2/3 : swbreak
case 7 : enmtx.cnt-=TSPEED : swbreak
case 8 : enmtx.cnt+=TSPEED
swend
if enmtx.cnt<0|(enmty.cnt<0)|(enmtx.cnt>WX)|(enmty.cnt>WY) : enmtinfo.cnt=0 ; 画面外なら消滅
loop
:
*enmaction ; repeat-loop間に追加すること!
:
if enemy.cnt=3&(enmx.cnt-30<mx)&(enmx.cnt+30>mx) { ; 敵機3の弾発射
rnd tmp,5
if tmp=0 : tmp.1=1 : tmp.2=enmx.cnt : tmp.3=enmy.cnt : gosub *enmtgene
}
if enemy.cnt=4 { ; ボス敵の弾発射
tmp=cnt
rnd tmp.1,20
if tmp.1=0 {
repeat 8,1
tmp.1=cnt
tmp.2=enmx.tmp
tmp.3=enmy.tmp
gosub *enmtgene
loop
}
}
:
そして最後に当たり判定のメインとなる下記3ラベルを作成します。
*hitcheck ; 当たり判定
repeat ENMTMAX
if enmtinfo.cnt=0 : continue
if mx-TSIZE<enmtx.cnt&(mx+SIZE>enmtx.cnt)&(my-TSIZE<enmty.cnt)&(my+SIZE>enmty.cnt) {
power-=2
enmtinfo.cnt=0 ; 弾消滅
}
loop
if power<1 : clear=-1 ; ゲームオーバー
return
*enmtgene ; 敵弾生成
repeat ENMTMAX
if enmtinfo.cnt=0 : enmtinfo.cnt=tmp.1 : enmtx.cnt=tmp.2 : enmty.cnt=tmp.3 : break
loop
return
*gamestop ; ゲーム中断
color : boxf : color 255
font "",32,1
if clear=-1 : pos 248,WY-32/2 : mes"GAME OVER" : else : pos 240,WY-32/2 : mes"GAME CLEAR"
redraw
stop
追加・変更する箇所が多くてどこを言っているのか分かりにくいですが許してください。
耐久力は作成していくゲームバランスを考えて任意の数値に増減してくださいね。
mainラベルの所で書いていますが、変数clearは-1で死亡、1でクリアとして代入されます。
tamaラベルのswitchについてはもう前章触れてありますのでいいですね。
enmactionラベルで当初予定の敵機3とボスが弾を発射するかというところです。
敵機3の場合は、X座標が自機付近に来た時だけ前方に発射するようになっています。
ボス敵の場合は自機の位置に関わらずどこでも8方向に弾を飛ばしてきます。
弾の移動についてはtamaラベルをご覧ください。
弾は同じですがswitchの条件に当たるenmtinfo.cntに入っている弾情報で進行方向が変わります。
弾の斜め移動は縦横と同じだけ進めると大分早いです。
円形に広げて行くには縦横の大体3分の2くらいがいいのではないでしょうかってことで2倍して3で割ってます。
当たり判定で弾との当たりをチェックをしています。
…しかし敵弾とだけでなく敵機本体との当たり判定も必要ですね。
せっかくのダメージ型ですし弾とはダメージを変える(増やす)方向で行きましょうかね。
弾は2ダメージに対し本体は3ダメージ与えるようにしましょう。作っていただく時は自由にしてくださいね。
そうそう。当たり判定をする時に敵の位置と大きさが分からなくてはチェックできません。
大きさは敵によって違う(ボスとザコの2種類だけだが)のでまず大きさを定義しておかなければなりませんね。
縦横の比率が同じでない場合、縦と横それぞれ定義しなければなりませんがここでは同じなのでいいでしょう。
準備コメント内に下記を入れて置いてください。
dim eSIZE,5 ; 0=敵なし,1=ザコ敵1,2=ザコ敵2,3=ザコ敵3,4=ボス敵 eSIZE=0,SIZE,SIZE,SIZE,SIZE*2 ; ザコ敵3種とも自機と同じ,ボス敵は自機の2倍
そして当たり判定をするhitcheckラベルのループ外に下記を追加してください。
repeat ENMMAX if enemy.cnt=0 : continue tmp=enemy.cnt if mx - eSIZE.tmp < enmx.cnt & (mx + SIZE > enmx.cnt) & (my - eSIZE.tmp < enmy.cnt) & (my + SIZE > enmy.cnt) : power -= 3 loop
これで自機に対する当たり判定が付きました。…がどれだけ当たったのか全く分かりません。
あとどれくらい当たっても大丈夫かを示すゲージが表示されている方がよい、ということで
準備ラベルにあらかじめ用意していたゲージを追加します。
どこに追加してもいい(厳密にはどこでもよいわけではない)のですが、
自機との当たり判定直後すぐの方が分かりやすそうということでhitcheckラベルの最後にしましょう。
ゲージは幅256ドットありますので150ダメージで256ドットにするために256÷150をしています。
ようするに1ダメージ1.70666…ドット減るわけですが小数点以下は無視され1ダメージ1ドットです。
そのままだと1×150=150ドット分しか描画されずゲージの緑色部分まで見えません。
精度を上げるためにややこしいのですが初めの256を100倍した25600÷150で1ダメージ170にして、
最後に100で割ることで元の値の精度を上げた結果が求められるわけです。
別に100倍でなく10000倍にして10000で割ったりしてもいいです。精度が上がりますがあまり意味ないかも。
自機耐久力が256以下なので100倍しなくてもゲージが表示されるわけですが256より大きい場合に
1倍で計算していると必ず値は1未満になり小数点は無視され値は0となりゲージが描画されません。
*hitcheck : pos 10,WY-20 : gcopy 3,0,SIZE*2-10,25600/150*power/100,10 ; 耐久力ゲージ return
続いて敵機の当たり判定を入れましょうね。
しかしその前に敵機の耐久力を決めてやらねばなりません。
まずはいつものように準備コメントより前に下記のスクリプトを入れてください。
dim enmp,ENMMAX ; それぞれの敵機の残り耐久力 dim epower,5 ; 敵機の初期耐久値 epower=0,10,20,15,800 ; 別に10発,20発...分というわけではない
上のを入れたら敵生成時(enmgeneラベル)の「if enemy.cnt=0」のカッコ内にソレを設定してあげましょう。
tmp=tm1.tm3 enmp.cnt=epower.tmp
後はhitcheckラベルを下記のように書き換えましょう。
:
repeat ENMMAX ; ココのループ内をこの様に書き換える
tmp=enemy.cnt
tmp.1=eSIZE.tmp
tmp=cnt
repeat TMAX
if cartridge.cnt {
if tx.cnt - tmp.1 < enmx.tmp & (tx.cnt + TSIZE > enmx.tmp) {
if ty.cnt - tmp.1 < enmy.tmp & (ty.cnt + TSIZE > enmy.tmp) {
enmp.tmp-=5
cartridge.cnt=0
}
}
}
loop
tmp=enemy.cnt
if mx - eSIZE.tmp < enmx.cnt & (mx + SIZE > enmx.cnt) & (my - eSIZE.tmp < enmy.cnt) & (my + SIZE > enmy.cnt) : power -= 3
if enmp.cnt < 1 : tm3.1- : if enemy.cnt=4 : clear=1 : enemy.cnt=0 : else : enemy.cnt=0
loop
:
この章初めでも書いたようにウェポンを2種類にするとのことでした。
真っ直ぐだけでなく広範囲に広がり真っ直ぐより与えるダメージは少な目ってことなので
それぞれの弾で与えるダメージも定義しなければなりません。準備コメントまでに
dim dam,2 dam=5,3 ; 0=真っ直ぐ弾のダメージ,1=広範囲弾のダメージ
を入れてtamaラベルの一番初めにある「repeat TMAX」のループを下記の様に書き換えてください。
repeat TMAX switch cartridge.cnt case 1 : ty.cnt-=speed : swbreak case 2 : tx.cnt-=speed*2/3 : ty.cnt-=speed*2/3 : swbreak case 3 : ty.cnt-=speed : swbreak case 4 : tx.cnt+=speed*2/3 : ty.cnt-=speed*2/3 : swbreak swend if cartridge.cnt : pos tx.cnt,ty.cnt : gcopy 3,0,0,TSIZE,TSIZE if -TSIZE>ty.cnt|(-TSIZE>tx.cnt)|(WX<tx.cnt) : cartridge.cnt=0 loop :
そしてこのすぐ上でやった敵機と弾の当たり判定でhitcheckラベルを書き換えると書きました。
そこの二重ループ内に「enmp.tmp-=5」とあったのを次のように書き換えます。
if cartridge.cnt=1 : enmp.tmp-=dam : else : enmp.tmp-=dam.1
後はウェポンの切り替えボタンの設定と切り替えた後弾の生成でどの弾になるかの部分だけです。
別に定義しなくても使えるのでいらないのですが(今までのも)準備コメントに明示的に定義しておきましょう。
dim wepon,1 ; ウェポン番号(0=前方のみ,1=3WAY)
actionラベルにそのウェポン番号を変更するのを加えておきます。
if key&32 : wepon=1-wepon ; ENTERキーで変更する
そしてメインの弾の生成部分であるgenerationラベルを下記のように書き換えれば完成です。
*generation tmp=2 repeat TMAX if cartridge.cnt : continue tx.cnt=SIZE-TSIZE/2+mx : ty.cnt=my-TSIZE if wepon=0 : cartridge.cnt=1 : break cartridge.cnt=tmp tmp+ if tmp>4 : break loop return
コレで与えるダメージが前方のみの5ダメージより弱い3WAYで3ダメージのウェポンが出来ました。
こういったアイテムをいろいろ追加していくと面白いですね。
…とコレで初めに予定していた縦スクロールのシューティングゲームが完成したわけです。
2,3面と追加していきアイテムを出現させたりとアイデアを取り入れて行ってください。
敵機の動きだけでなく弾の動きもモジュール化してもよろしいかと思います。
基本的な部分はどんどん使いまわしの出来る形にしていった方が楽です。
ココで完成したスクリプトの公開をしておきます。参考にご利用ください。コチラからどうぞ。
このままのものに機能追加していってもたいしたものが出来ませんのでいないとは思いますが、
初めにお読みくださいに書いている通り勉強として利用する以外の公開等は控えてください。
別のサイトでの掲示板でそのまま公開して聞くということが以前ありましたが
そういう行為もやめてください(誰とは書きませんが)。
もし自機と敵機の接触で敵機にもダメージを与えたいのであればpower-=3だけでなく
if mx - eSIZE.tmp < enmx.cnt & (mx + SIZE > enmx.cnt) & (my - eSIZE.tmp < enmy.cnt) & (my + SIZE > enmy.cnt) {
power -= 3 : enmp.cnt -= 2
}
としてみることで自機・敵機ともダメージを与える様になりますね。
敵機弾や敵機に接触した時、無敵時間がないため一回分のダメージは少なくても大量に食らうこととなります。
無敵時間を設けるにはpowerの減る所で次のようなinvncbl(変数名は何でもよい)を入れておきます。
if invncbl=0 : power-=2 : invncbl=5
そして変数invncblは当たっていてもいなくても0でない時はターン毎に1ずつ減らしていきます。
つまりヒットの有無に関わらず絶対に通過する場所に下記のように減らすものを追加しておけばイイかと。
if invncbl : invncbl- ; mainラベル内にでも追加しておけばOK!
コレは自機に対する無敵時間ですが敵機にも無敵時間を付けておかないと不平等です(笑
シューティングの難易度を易しくするには必要ないと思いますけどね。
あ、そうそう超重要お知らせがあります。
弾の連続連なりを避けるために変数shottimeにも同じようなトラップを仕掛けていましたが、
弾が発射しているときにショットキーが押されていたら変数shottimeを減らす、としていました。
それでは連打した時、弾が発射されない場合が出てしまいます。
それでは困るので上でやった変数invncblのように
キーが押されていてもいなくてもshottimeが0でないなら減らすようにしなくてはいけません。
ダウンロードできるスクリプトでは修正していますがこの章,前章で出てきたものの修正はしていません。
ご迷惑をおかけしたことをお詫び申し上げます。