主にMSX関係のコンテンツが置いてあります。

1セクタゲーム作成に挑戦-9

コード縮小

サブルーチンを処理の流れに組み込む

サブルーチン化していた部分をメインルーチンに組み込んでみました。

callとretで4バイト削減出来るのですが、retが複数だとジャンプ命令に置き換えなくては駄目なので少ししか削れていないはずです(最初は数えてましたがだんだん面倒に…)。

座標計算を8bitに

スプライトの座標は8bitですが、アクションゲームは滑らかさが命ということで小数部分の管理もしていました。

ワイヤーアクションを考えていたときは画面外の座標も管理したかったので、整数10bit+小数6bit。

ワイヤーアクションをやめたので管理しやすいように整数8bit+小数8bit。

そして今回コード削減のため、プレイヤーのy座標以外は整数8bitに。

これによりプレイヤーキャラクタの左右移動速度、障害物の移動速度の調整が粗くなりましたが致し方ありません。

メッセージ表示処理の削除

それでもまだまだメモリが足りないので、GAME OVERやSCOREの文字表示ルーチンをすべて削除し、文字データも削除しました。

完成したゲームではスコア以外の文字は何も出力されません。

アニメパターンの簡略化

アニメパターンは1フレーム単位で切り替えると高速すぎて不格好なのでカウンタを使って速度管理していました。

そのコード削るとなると、1フレームごとの切り換えになっています。

それならと、アニメーションを丸々削除してみたのですが、やっぱりアニメーションがないと味気ないので1フレーム切り換えですがアニメーション自体は残しました。

結果

なんとかコードを削って、結果512バイトとなりました。

ギリギリピッタリ(ワークエリア除く)収まったようです。

これは1画面プログラムよりかなり難しいですね。BASICならPRINT文で対処できるものも、イチから組む必要があるので512バイトでは全然足りません。

ちょっとした問題点は残っていて、ゲームオーバー時に障害物に触れていないように見えることがあります。

これはスプライトを移動する過程で重なった瞬間があったもので、表示タイミングによって発生する現象のようです。このコード制限ではどうしようもできず仕様となります。

完成したゲームがこちらです。

移動速度などを調整した結果こんな感じとなりました(リプレイ時はスペースキーではなくカーソルキーに変更しました)。

最高得点はこちら。1万点を目指してプレイするのが良い難易度かもしれません。

512バイト制限のゲーム制作、軽い気持ちで始めたのですが思った以上に厳しい制限ですね。

ゲーム制作の観点からはもう少し緩い制限のほうが楽しめそうです。

ダウンロード

バイナリ

1SEC.BIN

BASIC上で、bload"1sec.bin",rで実行できます。

ソース(クリックで展開)
; 1secgame
;ワークエリア-------------------------------------------------------------------
forclr: equ 0f3d9h ;前景色
bakclr: equ 0f3eah ;背景色
bdrclr: equ 0f3ebh ;周辺色
csry: equ 0f3dch ;カーソルy座標
csrx: equ 0f3ddh ;カーソルx座標
cliksw: equ 0f3dbh ;クリック音スイッチ
statfl: equ 0f3e7h ;vdpステータスレジスタ0
scncnt: equ 0f3f6h ;キースキャン時間間隔
;bios---------------------------------------------------------------------------
chgmod: equ 005fh ;スクリーンモード変更
;a=モード
;forclr=前景色
;bakclr=背景色
;bdrclr=周辺色
wrtvrm: equ 004dh ;vram書き込み hl=アドレス a=データ
ldirvm: equ 005ch ;vramへブロック転送hl=メモリ,de=vram,bc=長さ
chput: equ 00a2h ;1文字表示,a=文字
gttrig: equ 00d8h ;トリガチェック
cls: equ 00c3h ;画面クリア
erafnk: equ 00cch ;ファンクションキー削除
gtstck: equ 00d5h ;ジョイスティック入力
;-------------------------------------------------------------------------------
org 9000h
start: ;screen1:color15,1,12
ld hl,0c01h
ld (bakclr),hl ;背景色周辺色
ld a,0fh
ld (forclr),a ;前景色
xor a
ld (cliksw),a ;クリック音スイッチ
inc a ;a=スクリーンモード
call chgmod ;screen1:color15,1,12
call erafnk ;key off
;vramスプライト定義
ld hl,spplayer
ld de,3800h
ld bc,8*3
call ldirvm


;メインルーチン-------------------------------------------------
mainst: ;初期化--------------------------------------------------------
;0埋め
xor a
ld (plmd + 1),a ;プレイヤー動作フラグ初期化
ld hl,ply
ld (hl),a
ld de,ply+1
ld bc,workend - ply - 1
ldir
;障害物座標初期化
ld b,30
ld a,b
ld (obscnt),a ;障害物発生カウンタ
ld hl,obstw
initl0: ld (hl),209 ;y座標上位
ld de,4
add hl,de
djnz initl0

;プレイヤー状態初期化
ld a,plgline ;y=120
ld (ply),a
ld hl,plyzinival ;y増分初期値
ld (plyz),hl
;初期表示
call putsprite ;障害物の消去、プレイヤーの表示

loop: ;プレイヤー処理-------------------------------------------------
playersub: xor a
call gttrig
ld b,a
ld a,(ploldt)
xor b
ld a,b
ld (ploldt),a
jr z,plmd
ld a,b
or a
jr z,plmd
;ジャンプ処理開始-----------------------------------------------
ld (plmd + 1),a
ld hl,plyzinival ;増分加算数初期値
ld (plyz),hl

;動作確認
plmd: ld a,0 ;プレイヤー動作:0=走り,0以外=ジャンプ
or a
jr nz,jump
;走り-----------------------------------------------------------
;得点加算
call scinc
;x座標処理
ld a,(plx)
sub 1 ;プレイヤーを後ろに
jr nc,psubx0
xor a ;左端座標
psubx0: ld (plx),a
;アニメーション-------------------------------------------------
ld a,(scncnt)
and 1
ld (plp),a
jr obsocc
jump: ;ジャンプ処理---------------------------------------------------
;x座標処理
ld a,(plx)
inc a ;プレイヤーを前に
cp plxline ;右端チェック
jr c,psubx1
ld a,plxline
psubx1: ld (plx),a
;y座標処理
ld a,(ply)
ld h,a
ld a,(plyl)
ld l,a
ld de,(plyz) ;y増分
add hl,de
ld a,h
cp 210 ;天井判定ライン
jr c,psub1
ld hl,0 ;天井に付いた
psub1: ;着地判定
ld a,h
cp plgline ;地上ライン
jr c,psub2:
;着地
xor a
ld (plmd + 1),a ;動作=走り
ld h,plgline
psub2: ld a,h
ld (ply),a
ld a,l
ld (plyl),a
;増分処理
ex de,hl
ld de,plyzval ;増分変化量
add hl,de
ld (plyz),hl

;障害物発生-----------------------------------------------------
obsocc: ld a,(obscnt)
dec a ;障害物発生カウント
jr z,obso0
ld (obscnt),a
jr obsomv
obso0: ;次の障害物発生までのカウント
ld a,14
ld (obscnt),a ;次の発生のカウンタ

rnd: ld a,0
add a,a
ld b,a
ld a,r
add a,b
ld (rnd+1),a
and 00001111b ;ランダムで0-15を作成
;1の数により奇数個ならP=0,偶数個ならP=1
jp po,obso1 ;P=0,1の数が奇数ならランダム位置の発生

;発生箇所算出
;P=1ならプレイヤー位置に発生
ld a,(ply)
srl a
srl a
srl a
obso1:
ld (obso2+1),a

ld e,a
ld d,0
ld hl,sccnt
add hl,de ;hl=ラインカウンタ

;スプライト空き探す
ex de,hl ;de=ラインカウンタ
ld b,30
ld hl,obstw ;
obso3: ld a,(hl) ;yh
cp 209
jr z,obso4
inc hl
inc hl
inc hl
inc hl
djnz obso3
jr obsomv



obso4: ex de,hl
ld a,(hl)
cp 3
jr nc,obsomv ;3個以上既に障害物があるなら発生処理終了
inc (hl)
ex de,hl

obso2: ld a,0
sla a
sla a
sla a
ld (hl),a ;yh
inc hl
ld (hl),255 ;xh
inc hl
ld (hl),e ;addrl
inc hl
ld (hl),d ;addrh

;障害物移動-----------------------------------------------------
obsomv: ld b,30
ld ix,obstw
obsm0: ld a,(ix+0) ;yh
cp 209
jr nz,obsm1
obsm2: ld de,4
add ix,de
djnz obsm0
jr puts
obsm1: ld a,(ix+1) ;xh
sub 2
ld (ix+1),a ;xh
jr nc,obsm2
;消去
ld (ix+0),209 ;yh

ld l,(ix+2) ;addrl
ld h,(ix+3) ;addrh
dec (hl)
jr obsm2
;---------------------------------------------------------------
puts:
;in a,(99h)
;and 00100000b
;jr nz,gameover

;キャラクタ全表示
call putsprite

;得点-----------------------------------------------------------
scput: ld hl,0101h
ld (csry),hl
ld b,4
ld hl,score
ld a,30h
scput0: rld
call chput
rld
call chput
rld
inc hl
djnz scput0
;得点加算
call scinc

ld a,(statfl)
and 00100000b
jp z,loop


;ゲームオーバー処理---------------------------------------------
gameover:
govr0: xor a
call gtstck
or a
jr z,govr0
jp mainst
;サブルーチン-----------------------------------------------------------------------------
;キャラクタ全表示
putsprite:
ld hl,1b7fh
ld de,ply
ld c,11
ld a,(plp)
ld b,a
call putsp

ld b,30
putsplp: push bc
ld b,2
ld c,6
call putsp
inc de
inc de
pop bc
djnz putsplp
ret
;得点加算--------------------------------------------------------
scinc: ld b,4
ld c,1
ld hl,score+3
or a
scinc0: ld a,(hl)
adc a,c
daa
ld (hl),a
ld c,0
dec hl
djnz scinc0
ret
;---------------------------------------------------------------
;スプライト表示
;hl=vramアドレス,de=ワーク座標y,c=カラー,b=パターン
putsp: ld a,(de) ;y上位
push af
inc de
ld a,(de) ;x上位
push af
inc de
ld a,b ;パターン
push af
ld a,c
call wrtvrm ;色書き込み
dec hl
pop af
call wrtvrm ;パターン書き込み
dec hl
pop af
ld b,a
pop af
cp 209
jr z,putsp2
ld c,a
ld a,b
call wrtvrm ;x書き込み
dec hl
ld a,c
call wrtvrm ;y書き込み
dec hl
ret
putsp2: dec hl
call wrtvrm ;y書き込み
inc hl
ld a,b
call wrtvrm ;x書き込み
dec hl
dec hl
ret


;障害物グラフィックパターン
spplayer: db 0fch,7eh,6ah,0e0h,0feh,7fh,7ch,82h
spplayer1: db 0fch,7eh,6ah,60h,0ffh,0feh,7ch,14h
spobst: db 3ch,42h,8dh,85h,0c1h,0b1h,42h,3ch
codeend:
codesize: equ codeend - start
;ゲーム用ワーク-----------------------------------------------------------------
ply: ds 1
plx: ds 1

obstw: ds 4*30 ;y=db,x=db,add=dw

plyl: ds 1 ;プレイヤーy座標小数
plxl: ds 1 ;プレイヤーx座標小数
plyz: ds 2 ;プレイヤーy座標増分
plyzinival: equ 0fa00h ;プレイヤーy座標増分初期値
plyzval: equ 0080h ;プレイヤーy座標増分変化量
plp: ds 1 ;パターン

ploldt: ds 1 ;1つ前のトリガ状態,0=押されていない,255=押されている
plgline: equ 120 ;プレイヤー地面座標
plxline: equ 216 ;プレイヤー最右座標
obscnt: ds 1 ;障害物カウンタ
sccnt: ds 24
score: ds 4
workend: