スプライトの当たり判定

いよいよ問題の当たり判定処理です。今までとはちょっと違ったやり方になります。「キャラクタ一つ一つに対し、一つ一つ当たり判定をする」という基本は変わりないのですが、その「当たり判定」のやり方が根本的に違います。es_typeで設定したスプライトの種類を使い、es_findで検索、es_checkで判定する、という流れになります。


;■ 敵移動と当たり判定
*enemymove
	enemy=0
	repeat
		es_find enemy,8,enemy		; 敵(8)スプライト検索
		if enemy=-1 : break
		es_get ex,enemy,3		; x座標取得
		es_get ey,enemy,5		; y座標取得
		es_get en,enemy,12		; キャラクタ番号取得
		if en=31 : gosub *enemy1
		if en=32 : gosub *enemy2
		if en=33 : gosub *enemy3
		es_apos enemy,exv.enemy,eyv.enemy,100+level
		et.enemy++			; タイマー

		es_check temp,enemy,4		; 自機弾(4)との当たり判定
		if temp>0 {
			ef.enemy--
			es_get wx,temp,3
			es_get wy,temp,5
			es_kill temp		; 自機弾削除
			if ef.enemy>0 {
				es_new temp,505
				es_set temp,wx,wy+5,7
						; 自機弾爆風設置
				es_type temp,16
						; 効果type値(16)
				es_adir temp,32,200
						; 自機弾爆風移動指示
				es_flag temp,$8306
						; 消失タイマー
				snd 3
				score++
			}
			else {
				es_kill enemy	; 敵削除
				repeat 8
					es_new temp,600
					es_set temp,ex+5,ey+5,21
						; 爆風設置
					es_type temp,16
						; 効果type値(16)
					es_adir temp,cnt*8,400
						; 爆風移動指示
					es_flag temp,$8314
						; 消失タイマー
				loop
				snd 2
				gosub *messageborn
			}
		}
		enemy++
	loop
return

repeat〜loopの回数指定なし無限ループを使うので、非常に注意が必要です。対象スプライトが見つからなかったらループから抜ける処理は必須です。もしこれを忘れてスクリプトの実行をしてしまうと、CTRL+ALT+DELも効かない、ALT+F4も効かない、電源コンセントを引っこ抜くしかないという悲惨な状況になります。もしテストするのが怖かったら「await 0」をrepeat〜loopのどこかに入れましょう。これさえやっておけば、ALT+F4での強制終了だけは可能になります^^;

何故こんなことをしなければならないかというと、es_findはスプライト番号の若い方から順番に検索し、該当スプライトが見つかるとそこで処理が終わってしまう為です。そこで、処理の終わったスプライトの次の番号から再度検索をする必要があるのです。この一連の処理を行うには、repeat〜loopの無限ループを使うのが一番効率がいいものと思われます。もっといい方法がある人は教えてください^^;

スクリプトを順番に見ていきましょう。まずes_findで存在する敵スプライトの検索をします。ここで活躍するのがes_typeで設定したtype値です。これは、当たり判定処理では必ず使うのにhtmlの命令別マニュアルには記載されていない(リファレンスを読みなさい、と書いてあります^^;)ちょっと都合の悪い奴です。ではまずリファレンスの説明から抜粋します。この説明文は非常にわかりやすいです。



・スプライトtype値の設定について

	スプライトのtype値は、ゲームなどで物体の識別をする時に有効に使うこと
	ができます。type値は、es_type命令で設定することができます。
	この値は、ユーザーの好きに設定することができる識別用の値となります。
	設定できる値は、

		1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768

	の計16種類です。
	es_set命令でスプライトを設定した直後は、type値は1になっています。
	この値は、衝突判定やスプライトの検索対象を指定するのに使用されます。
	スプライトが示す物体の種別を登録しておくのが主な利用法です。

	たとえば、シューティングゲームで自機はtype1、敵はtype2、敵のミサイル
	はtype4、自分のミサイルはtype8、といった感じでtype値をスプライトを出す
	時に設定しておきます。
	こうしておけば、自機が敵か、または敵ミサイルに衝突しているかを判定
	する場合にチェックがしやすくなります。es_check命令では、複数のtype値を
	同時に判定できるので、この例で言うと自機のスプライトに対して、
	敵(type2)と敵ミサイル(type4)が衝突しているかを調べて自分の生死を決める
	ことができます。
	また、自分のミサイルが敵に衝突しているかを判定する場合には、まず
	es_find命令でtype8のスプライトだけを検索して、その1つ1つが、敵(type2)
	と衝突しているかを判定すればいいわけです。

	このようにtype値をあらかじめ割り振っておくことで、スプライトの管理を
	スマートに行なうことが可能です。

いかがでしょうか?まさにtype値さまさまといった感じです(笑)。ところで、な〜んでtype値ってこんな飛び飛びの数字なんだろうな〜と思った人もいるんじゃないでしょうか?思わなかった人は読み飛ばしてください。これは2進法に直すとよくわかります。要するにコンピュータ的な処理で、なるべく容量を少なく識別をさせるには2進法が一番だからです。

10進法2進法16進法
1%0000000000000001$0001
2%0000000000000010$0002
4%0000000000000100$0004
8%0000000000001000$0008
16%0000000000010000$0010
32%0000000000100000$0020
64%0000000001000000$0040
128%0000000010000000$0080
256%0000000100000000$0100
512%0000001000000000$0200
1024%0000010000000000$0400
2048%0000100000000000$0800
4096%0001000000000000$1000
8192%0010000000000000$2000
16384%0100000000000000$4000
32768%1000000000000000$8000

type値がこのように割り振られているので、複数のtype値の判定や検索も可能なのです。例えばtype値8のスプライトとtype値8192のスプライトを検索する場合、こういった形になります。

10進法2進法16進法
8%0000000000001000$0008
8192%0010000000000000$2000
8200%0010000000001000$2008

2進法の部分を見ると一番良くわかりますが、別々の位置がスイッチになってるのがよくわかると思います。要するにこうやってコンピュータは識別をしてるのです。

余談はこのくらいにして。

要するに、例えば自機のtype値を(1)、自機弾を(2)、敵機を(4)、敵弾を(8)といった具合に設定しておけば、es_findで検索→es_checkで判定という処理ができる、ということです。原理はややこしいですが、処理は格段に楽になりますし、負荷も少なくできます。標準命令だけでの当たり判定ルーチンを列記してみましょう。


;■ 敵移動
*enemymove
	repeat emax
		et.cnt++
		if ef.cnt<1 : continue
		if en.cnt=1 : gosub *enemy1
		if en.cnt=2 : gosub *enemy2
		if en.cnt=3 : gosub *enemy3
		if ef.cnt<1 : continue
		ent=cnt
		repeat wmax
			if wf.cnt<1 : continue
			ddx=(ex.ent+25)-(wx.cnt+12) : if ddx<0 : ddx=-ddx
			ddy=(ey.ent+25)-(wy.cnt+25) : if ddy<0 : ddy=-ddy
			if (ddx<20)&(ddy<40) {
				ef.ent-- : wf.cnt=0
				if ef.ent>0 {
					pos wx.cnt,wy.cnt
					gcopy 2,175,25,25,25
					snd 4
					score++
				}
				else {
					pos ex.ent,ey.ent
					gcopy 2,200,0,50,50
					snd 2
					gosub *messageborn
				}
			}
		loop
	loop
return


このように二重ループを使って処理してましたね。仮に「emax=200」で「wmax=10」だとすると、ここだけで2000回のループを行うことになります。実際にはcontinueを使って処理飛ばしをしているので、全ての処理を2000回行っているわけではないのですが、やはり負荷は大きいです。処理速度の減退の大きな理由になります。ところがスプライトのes_checkを使った処理の場合、確実に画面上に表示されてる対象スプライト数だけしか処理を行いません。それどころか対象スプライトが無い場合は全く処理を行わないですむのです。せっかくDirectXを使って画面描写が速くなっても、それ以外の部分で処理が遅くなってては意味がありません。だからこのes_checkは非常に大きな意味があるし、使い応えもあるのです。

前へ戻る 改造記メニューへ戻る 次へ進む