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

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

方針転換

512バイトって思ったより厳しい制限でした。

そんなキツイ制限があるのにMSX1でPCGのドットスクロールみたいな、特別な機能を盛り込むこと自体が無謀だったようです。

恐らくはゲームを作り上げるのも大変なはず。

というわけで、改心いたしましてMSXの機能を素直に使ったゲームにしたいと思います。

再考

表示するキャラクタは全てスプライトで賄うことにします。

横並び制限に気を付ければ32キャラクタ表示できるので、そこそこな量が表示できます。

キャラクタからスプライトにすることにより、ドット単位の表示が可能になるので、キャラクタのパターン作成コードがごっそり不要になりコードサイズ的に有利です。

あと、DOSプログラムもやめます。ページ0に読み込まれるせいでソースの記述がややこしくなったり、高位アドレスに転送など無駄な処理が増えます。

BASIC環境のBLOADで読めるバイナリファイルなら直接任意のアドレスから始められるし、読み込まれた時点でBIOSも出ているので好都合です。

デザイン

スプライトはこの3つ。早速プログラムしてみます。

ソース(クリックで展開)
; 1secgame
;ワークエリア-------------------------------------------------------------------
exptbl: equ 0fcc1h ;main romのスロット
forclr: equ 0f3d9h ;前景色
bakclr: equ 0f3eah ;背景色
bdrclr: equ 0f3ebh ;周辺色
csry: equ 0f3dch ;カーソルy座標
csrx: equ 0f3ddh ;カーソルx座標
cliksw: equ 0f3dbh ;クリック音スイッチ
;bios---------------------------------------------------------------------------
calslt: equ 001ch ;スロットの指定アドレスをコール iy,ix
chgmod: equ 005fh ;スクリーンモード変更
;a=モード
;forclr=前景色
;bakclr=背景色
;bdrclr=周辺色
filvrm: equ 0056h ;vramを埋める hl=アドレスbc=長さa=データ
setwrt: equ 0053h ;vramアドレスセット hl=アドレス
wrtvrm: equ 004dh ;vram書き込み hl=アドレス a=データ
rdslt: equ 000ch ;スロットの指定アドレスを読む
;hl=アドレス a=読み込み値
enaslt: equ 0024h ;スロット切り替え
ldirvm: equ 005ch ;vramへブロック転送hl=メモリ,de=vram,bc=長さ
chput: equ 00a2h ;1文字表示,a=文字
gttrig: equ 00d8h ;トリガチェック
cls: equ 00c3h ;画面クリア
;-------------------------------------------------------------------------------
org 9000h

start: ;screen1:color15,1,12

ld a,15
ld (forclr),a
ld a,12
ld (bdrclr),a
xor a
ld (cliksw),a
inc a
ld (bakclr),a
call chgmod ;screen1:color15,1,12

;vramスプライト定義
ld hl,spplayer
ld de,3800h
ld bc,8*3
call ldirvm

;メインルーチン
mainst: call init

loop: call playersub
call putsprite
;ゲームオーバー判定
ld hl,(ply)
ld a,h
rl l
rla
rl l
rla
cp 192
jr nc,gameover ;画面外ゲームオーバ
jr loop

;プレイヤー処理-------------------------------------------------
playersub: ;x座標処理
ld hl,(plx)
ld de,(plxz)
add hl,de
ld (plx),hl
;y座標処理
ld hl,(ply)
ld de,(plyz)
add hl,de
ld a,h
or a
jp p,psub0
ld hl,0 ;天井に付いた
psub0: ld (ply),hl
;増分処理
ex de,hl
ld de,0020h ;増分変化量
add hl,de
ld (plyz),hl
ret
;ゲームオーバー処理---------------------------------------------
gameover: ld a,10
ld (csry),a
ld a,12
ld (csrx),a
ld hl,gmovr
call print
ld b,10
call wait
govr0: xor a
call gttrig
or a
jr z,govr0
govr1: xor a
call gttrig
or a
jr nz,govr1
call 00c3h
jr mainst

;初期化--------------------------------------------------------
;座標初期化
init: ld b,32
ld hl,plx
initl0: ld (hl),0 ;x座標下位
inc hl
ld (hl),0 ;x座標上位
inc hl
ld (hl),40h ;y座標下位
inc hl
ld (hl),34h ;y座標上位
inc hl
djnz initl0

;プレイヤー状態初期化
ld hl,2000h ;x=128
ld (plx),hl
ld hl,1800h ;y=96
ld (ply),hl

ld hl,00c0h ;=3.0
ld (plxz),hl
ld hl,0fe80h ;=-6.0
ld (plyz),hl
;フック初期化
xor a
ld (hkf),a
ret
;---------------------------------------------------------------
;キャラクタ全表示
putsprite: ld hl,1b00h
ld de,plx
ld c,11
ld b,0
call putsp
ld c,07
ld b,1
call putsp

ld b,30
putsplp: push bc
ld b,2
ld c,6
call putsp
pop bc
djnz putsplp
ret
;---------------------------------------------------------------
;スプライト表示
;hl=vramアドレス,de=ワーク座標x,c=カラー,b=パターン
;x座標がマイナスか256以上なら表示しない
putsp: push hl
ld a,(de) ;x下位
inc de
ld l,a
ld a,(de) ;x上位
inc de
push af
and 11000000b ;9bit目10bit目のみ取り出し
jp m,putsp0 ;マイナス座標
jr nz,putsp0 ;画面外座標
pop af
;整数8bitの取り出し
rl l
rla
rl l
rla
ld (spx + 1),a ;x書き込み
ld a,(de) ;y下位
inc de
ld l,a
ld a,(de)
inc de
;整数8bitの取り出し
rl l
rla
rl l
rla
pop hl
call wrtvrm ;y座標書き込み
inc hl
spx: ld a,0 ;x
call wrtvrm ;x座標書き込み
inc hl
ld a,b
call wrtvrm ;パターン書き込み
inc hl
ld a,c
call wrtvrm ;色書き込み
inc hl
ret
putsp0: ;マイナスx座標
pop af
pop hl
ld a,209
call wrtvrm ;y座標書き込み
inc hl ;x
inc hl ;pat
inc hl ;color
inc hl ;next
inc de
inc de
ret

;wait-----------------------------------------------------------
wait: ;b=ウエイト数 1/60単位
waitl0: halt
djnz waitl0
ret
;文字列表示-----------------------------------------------------
;hl=文字列アドレス
print: ld a,(hl)
inc hl
cp '$' ;終端文字
ret z
call chput
jr print
;文字列データ
gmovr: dm 'GAME OVER$'
;障害物グラフィックパターン
spplayer: db 0fch,7eh,6ah,0e0h,0feh,7fh,7ch,82h
sphook: db 0eh,18h,19h,1fh,0eh,00h,00h,00h
spobst: db 3ch,42h,8dh,85h,0c1h,0b1h,42h,3ch
codeend:
codesize: equ codeend - start
;ゲーム用ワーク-----------------------------------------------------------------
plx: dw 0
ply: dw 0
hkx: dw 0
hky: dw 0
obstw: ds 4*30 ;x=dw,y=db

plxz: dw 0 ;プレイヤーx座標増分
plyz: dw 0 ;プレイヤーy座標増分

hkf: db 0 ;0=off,1=射出,2=戻り,3=ロック
hkcdef: equ 5
hkzdef: equ 3
hkc: db 0 ;カウンタ

ゲーム処理の中核となる部分、大まかな流れを作成しゲームオーバーからリプレイをとりあえず入れてみました。

動画はこちらです。

ピョーンと飛んで、放物線を描きながら画面外になるとゲームオーバー。スペースキーでリプレイ。

ゲームとして外枠となる流れだけ作った感じで、ここから色々機能を追加しなくてはいけません。

しかし、この時点でコードの容量(ワークエリアは除きます)は338バイト。

この段階で作ろうとしているゲームイメージは

  • プレイヤーは何もしないと自然落下する
  • スペースキーを押すとフックを斜め45度に射出。スペースキーを離すとその位置で空中に固定
  • 固定すると、ブランコのように左右に揺れる
  • 適切な位置でもう一度スペースキーを押すと固定は解除され、その時点の勢いで前方や上方にすすむ。
  • 障害物が右から流れてきて、当たったり、画面下に落ちるとゲームオーバー
  • というワイヤーアクション風のゲームを考えていたわけですが、どうもこれらの要素を入れられる余裕はなさそうです。