Chapter.2 自機弾の処理ルーチン製作
[Chapter2 制作物]

今回は、自機弾の動き処理を組み込んでいきます。
発射処理は、BASIC で実現し、実際の飛んでいく座標計算を機械語にしていきます。

■ビルド用のファイルを編集
自機弾の軌道計算処理は、sca_shot.asm に記述することにします。

そのため、アセンブルソースとして sca_shot.asm が追加になることと、そのアセンブル結果である sca_shot.o を
リンクする処理が追加になるため、ビルド用のファイルに、それらの情報を追記しなければなりません。

まずは、mk.bat に、sca_shot.asm のアセンブル行を追記します。
追記する行を、プログラム1 に示します。

プログラム1. mk.bat に追記する行
echo [ASSEMBLE] sca_shot.asm
as-z80 -o sca_shot.o sca_shot.asm
		

link-z80 がアセンブル結果をリンクする指示であるため、この行の時点で全てのアセンブルが終わってなければなりません。
なので、追記する場所は、link-z80 の行より上にします。

次に、chapter2.link です。chapter1.link と比べて プログラム2 の行が追加になります。

プログラム2. chapter2.link に追記する行
sca_shot.o
		

-im chapter2 は、出力設定です。
「chapter2.ihx と chapter2.map を出力してください」と link-z80 に指示しています。
-im の i が ihx, m が map を出力してくださいという意味になってます。

2行目以降は、リンクする *.o のファイル名を列挙しています。
上から順にリンクされるので、test_main.o が最初に無ければなりません。
それ以降の順番は、動作に影響を及ぼしません。結合結果の並び順が入れ替わるだけです。

これで、ビルド用ファイルの編集は完了です。

■sc_shot.asm の作成
前回、sc_player.asm を作ったのと同じ要領で作成します。

処理ルーチンとしては、表1 に示すものを用意します。

表1. 自機弾の処理ルーチン一覧
処理ルーチン名 内容
shot_init 自機弾(1つ)の情報メモリを初期化する
shot_move 自機弾(1つ)の移動処理
shot_fire 自機弾の発射処理

自機弾の情報メモリとして、図1.のような構造のメモリを用意します。


図1. 自機弾の情報メモリ構造

自機の情報メモリと、サイズと一部情報が共通のオフセット位置になっていることが確認出来ると思います。
これは、共通にすることで、「同じ処理をする場合に、同じサブルーチンを流用できる」という効果を得るためです。
たとえば、自機スプライト表示と、自機弾スプライト表示は、同じ処理なので、同じサブルーチンを使えるわけです。

以下に、個別に説明します。

■shot_init
ゲーム開始時に、自機弾を初期化する処理です。
プログラムの内容を、プログラム1 に示します。

プログラム1. 自機弾(1つ)の初期化処理
shot_init::
		push	hl
		push	ix
		pop		hl
		xor		a
		ld		b, #5
shot_init_loop:
		ld		(hl), a
		inc		hl
		djnz	shot_init_loop
		pop		hl
		ret
		

最初の push hl は、最後の pop hl に対応しており、hl レジスタの内容を待避しているだけの命令です。
次に続く push ix/ pop hl は、hl ← ix の代入処理になっています。(ld hl, ix という命令は存在しない)
あとは、(hl+0)〜(hl+4) の 5byte を 0 クリアする処理です。
情報メモリのサイズは、8byte ですが、未使用の領域はクリアする必要はないので、5byte だけクリアしてます。

■shot_move
ゲームのメインループで呼び出される自機弾の移動処理です。
単純に上へ移動して、画面外に出たら消滅するだけの処理です。
プログラムの内容を、プログラム2 に示します。

プログラム2. 自機弾の移動処理
shot_move::
		; この弾が発射中でなければ何もしない
		ld		a, SCA_INFO_SHOT_POWER(ix)
		or		a
		jr		nz, shot_move_active
shot_move_inactive:
		ld		SCA_INFO_YH(ix), #212			; 非表示
		ld		SCA_INFO_SHOT_POWER(ix), #0		; 発射中でない
		ret
shot_move_active:
		; 弾を上に動かす
		ld		a, SCA_INFO_YH(ix)
		sub		#8
		jr		c, shot_move_inactive
		ld		SCA_INFO_YH(ix), a
		ret
		

いきなり SCA_INFO_SHOT_POWER という名前が出てきますが、これは sca_info.asm で定義してあります。
図1 を見て貰えば、SCA_INFO_SHOT_POWER は、4 であることは分かります。しかし、プログラムで

ld a, 4(ix)
と、記述してしまうと、後で見たときに、図1 も併せて見なければならず、面倒です。
大きなプログラムを作るときは、人間が注意して確認しなければならない部分は狭い範囲に維持することが重要です。
プログラムを小さいサブルーチンに分割するのと同じで、こういう情報も「別途表を参照」「別途図を参照」というのを
なるべく少なくしたり、名前を付けて覚えやすくしたりすることで、気楽に作れるようになります。

ということで、SCA_INFO_SHOT_POWER は、4 と同じ意味です。
自機弾情報メモリの中の SCA_INFO_SHOT_POWER は、その自機弾が持つ威力を示してます。
たとえば、SCA_INFO_SHOT_POWER のメモリ内容が 10 で、耐久力 100 の敵に衝突した場合、その敵の耐久力は 90 に減らし、
耐久力が 0 を割ったら、その敵は破壊されるという動作にする予定です。

わざわざ威力を示すメモリを用意しているのは、パワーアップアイテムで自機弾の威力が増すことを想定しているためです。
パワーアップした瞬間に、既に発射済みの弾までパワーアップするのはおかしい・・という観点で、自機弾毎に威力を保持しておく
ことにしました。

ついでに、威力ゼロの自機弾は、「発射中ではない」という情報も兼ねてます。
プログラム2 の最初の3命令は、発射中でなければ移動処理はしない判断をしてます。
shot_move_inactive からの3命令は、「発射中でない場合」と「画面外に出た場合」に処理されます。
座標を画面外に移動して、威力ゼロに更新してます。

shot_move_active 以降は、実際に移動させる処理です。
Y座標 SCA_INFO_YH(ix) から 8 を引いてみて、桁借りが発生=0を割った場合に、「画面外に出た」と判断して shot_move_inactive へ飛びます。
画面外に出なかった場合は、Y座標を更新して抜けます。

■shot_fire
自機弾の発射処理です。
トリガ判定などは、現段階では BASIC 任せなので、「発射することが確定した」ときに、発射準備を行うルーチンになります。

プログラムの内容を、プログラム3 に示します。

プログラム3. 自機弾の発射処理
shot_fire::
		; 発射中でない弾を検索する
		ld		b, #3
		ld		de, #SCA_INFO_SIZE
shot_fire_loop:
		; 現在着目している弾は、発射中か?
		ld		a, SCA_INFO_SHOT_POWER(iy)
		or		a
		jr		z, shot_fire_found
		add		iy, de
		djnz	shot_fire_loop
		; 空いてる弾が無いので発射を諦める
		ret
shot_fire_found:
		; 発射処理
		ld		a, SCA_INFO_XH(ix)
		ld		SCA_INFO_XH(iy), a
		ld		a, SCA_INFO_YH(ix)
		ld		SCA_INFO_YH(iy), a
		ld		a, SCA_INFO_PLAYER_SHOT_POWER(ix)
		ld		SCA_INFO_SHOT_POWER(iy), a
		ret
		

自機弾は、最大で3つ表示出来る仕様にします。
まずは、3つの自機弾情報メモリの中で、「発射中でない弾」を探します。

最初の2命令は、3つの検索を行うので、3回ループを示す ld b, #3 と、自機弾情報メモリの1つ分のサイズを示す ld de, #SCA_INFO_SIZE を
代入しています。

shot_fire_loop からの5命令が、「発射中でない弾」を探すループです。
着目している自機弾情報メモリから、SCA_INFO_SHOT_POWER を読み出し、0 かどうか判断します。
0 の場合は、「発射中でない弾」なので、実際の発射処理である shot_fire_found へ飛びます。
0 でなかった場合は、その自機弾は諦めて、次の自機弾情報メモリの調査に遷移します。
3つとも発射中の場合は、発射そのものを諦めて ret します。

shot_fire_found の実際の発射処理は、自機の位置を自機弾情報にコピーしてから、SCA_INFO_SHOT_POWER に自機情報メモリにある "弾の威力" を
コピーして完了です。

■その他
chapter.1 のプログラムでは、自機の情報メモリのオフセット指定を直値で記入していました。
これを自機弾と同じように SCA_INFO_XH 等の値を利用するように書き換えてます。



[▲トップページへ]