GB/GBC汉化经验分享之十九--11x11字体的拼字程序 心得研究

六级用户 RangerMarsh 1天前 261

十九、11x11字体的拼字程序


这一部分来看一下如何采用拼字的方法来进行文字的显示。11x11的字体已经可以完美的显示绝大部分的汉字,并且通过拼字在相同的空间里可以多显示一半的文字,可以得到更好的游戏体验。

如果知道游戏中图像显示的原理就很容易理解拼字程序是如何来实现的了。比如这里是一个11x11的“保字,它实际上是分成了四个Tile,每个Tile8个字节,对应一个16进制的数值保存在Rom

19-01.png

如果把这些16进制的数换算成二进制的数就一目了然了。

19-02.png

0对应背景,1对应黑点,所有的黑点就组成了文字。而对于一个11x11的字来说有很多空间是没有利用上的。我们拼字时,就是把每一个字节一分为二(二进制的高四位和低四位),等于把一个字从横向上分成4份,丢掉最后一份空白的,然后每两个字的前三部分重新组合,实现6Tile显示2个字。

我们先导入合适的字体,字体选择SimSun,大小选择小四,其他设置如下,注意要确保字符在最左侧

19-03.png

下面就是程序大概的内容,主程序WriteMiddle包括4个部分:

WordLocation用于计算出所要显示的字符在字库中的位置这个和之前的一样,可以直接借用。

接下来Write11x11是用来完成拼字操作的程序。

VRAMWrite是将拼完的字符对应的4Tile写到VRAM中的程序。

MAPWrite将这些Tile写到MAP上从而可以在屏幕上显示对应的汉字。

注意后两个程序和之前的会稍有区别。

10:4100

WriteMiddle:

push  hl

push  de

push  bc

push  af

call WordLocation

call Write11x11

call VRAMWrite

pop af

pop bc

pop de

pop hl

call MAPWrite

ret

 

在进行拼字操作时我们需要判断当前操作的是第一个字还是第二个字,我们把这个信息保存在DA02,同时拼字操作需要在WRAM中完成,要在WRAM中找一块足够大的未使用的区域,这里我们选择DA10DA9F这一块。

10:4230

Write11x11:

call WriteWord0

ld  a,(DA02)

cp a,1

jp  z,WriteWord2

call WriteWord1

Write11end:

ld  hl,DA02

inc  (hl)

ret

WriteWord2:

ld  hl,DA50

ld  de,DA30

call WordMix

call WriteWordM

jr  Write11end

 

首先,调用程序WriteWord0把字符的4TileRom中读写到DA50这里

10:4260

WriteWord0:

ld  b,40

ld  de,DA50

call TileRead

ret

 

这里面TileRead程序是负责把字符的Tile读出来的,因为要切换Bank,所以这个程序放在Bank 0。字库的Bank号与之前一样,直接将字库对应的编码减去20得到

0:3FA0

TileRead:

ld  a,(DA01)

sub a,20

push hl

call 2A21

pop hl

call Readhl2de

push hl

call 2A30

pop hl

ret

 

Readhl2de程序根据b的循环值从hl读出文本信息到de,这里多个程序都会用到,因为也涉及到在不同的Bank上都会调用这个程序,所以也放在Bank 0

0:3F99

Readhl2de:

ldi  a,(hl)

ld   (de),a

inc  de

dec  b

jr     nz,Readhl2de

ret

 

当判断出是第一个字的时候(DA02初始值为0),就调用程序WriteWord1把字符信息从DA50中读写到DA10,因为第一个字不需要拼字,所以直接放到DA10这里,后面会直接调用程序写入VRAM。完成后会给DA02的值加1

10:4270

WriteWord1:

ld  b,40

ld  de,DA10

ld  hl,DA50

call Readhl2de

ret

 

如果判断出是第二个字的话,就执行WriteWord2对应的程序来进行拼字。

WordMix程序实现拼字,把hl的字符的前4位右移4位到低位和de的字节相加实现拼字,把hl的字符的后4位左移4位保存到hl用于后续操作。将DA50开始的编码与DA30这里的编码进行拼字操作,连续操作40次,刚好把后一个字与前一个字拼完

10:4290

WordMix:

ld   c,40

MixNext:

ld   a,(hl)

ld   b,a

srl  b

srl  b

srl  b

srl  b

ld   a,(de)

add  b

ld   (de),a

ld   a,(hl)

ld   b,a

sla  b

sla  b

sla  b

sla  b

ld   (hl),b

inc  hl

inc  de

dec c

jr     nz,MixNext

ret 

 

然后调用程序WriteWordM,把拼好的字放到DA10这里准备写入VRAM

10:4280

WriteWordM:

ld  b,40

ld  de,DA10

ld  hl,DA30

call  Readhl2de

ret

 

写入VRAM的程序VRAMwrite也和之前略有不同,这里直接从DA10这里写40个字节到VRAM就可以了,写完把de保存到DA04DA05

10:4300

VRAMwrite:

call  VRAMaddr

ld  b,40

ld  hl,DA10

judgeVRAM:

ld a,(FF00+41)

and a,03

cp a,00

jr nz,judgeVRAM

ldi  a,(hl)

ld   (de),a

inc  de

dec  b

jr nz,judgeVRAM

ld a,d

ld (DA04),a

ld a,e

ld (DA05),a

ret 

 

计算VRAM中地址的VRAMaddr程序也不一样。因为第二个字的左半部分其实是和第一个字的右半部分重叠的,所以要多一步判断是否为第二个字的步骤。判断出是第二个字之后,VRAM地址要减20

10:4350

VRAMaddr:

ld hl,DA04

ldi a,(hl)

cp a,0

jr  nz,VRAMaddread

VRAMreset:

ld  a,C0

ldd  (hl),a

ld  a,90

ldi  (hl),a

VRAMaddread:

ld d,a

ld e,(hl)

ld a,(DA02)

cp a,2

jr nz,VRAMend

ld a,e

sub 20

ld e,a

jr nc,VRAMend

dec d

jr VRAMend

VRAMend:

ld a,d

cp a,97

jr z,VRAMreset

call VRAMTile

ret

 

这里的VRAM初始地址设置到了90C0就是为减20留下缓冲。这个游戏里VRAM空间足够大,没什么问题。如果VRAM空间比较小的话,就要另外考虑了。

计算Tile编号的程序VRAMTile还是和之前一样

10:4330

VRAMTile:

ld   a,d

swap a

and    a,F0

ld   b,a

ld   a,e

swap a

and    a,0F

add  b

ld (DA07),a

ret

 

接下来是将Tile输出到MAP的程序MAPwrite,,和之前的思路是一样。利用原程序的写Tile方式,de值控制MAP地址,0:3897用于写上半部分,0:389D用于写下半部分,e1后写字的后半部分。文字的第一个Tile编号保存在DA07,开始导入字库时选择的是垂直重组,所以一个字的四个Tile是按照左上、左下、右上、右下存放在VRAM里的,写到MAP时也按照这个顺序来写

10:4400

MAPwrite:

ld a,(DA07)

push af

call 3897

pop af

inc a

push af

call 389D

inc e

pop af

inc a

push af

call 3897

pop af

inc a

call 389D

dec b

call Reset2to0

ret

 

区别是结束时对e值的操作。Reset2to0程序判断当前是第一个字还是第二个字。因为第二个字的左半部分和第一个字是要重叠的,所以如果是第一个字的话e值要减1。如果是第二个字的话,就把DA020,表示下一个会是第一个字。

10:4450

Reset2to0:

ld   a,(DA02)

cp   a,02

jr   nz,   ResetEnd

xor a

ld   (DA02),a

inc e

ResetEnd:

dec e

ret

 

到这里就可以看到,现在游戏中显示的字体就是我们想要的11x11字体拼字的效果。

19-04.png

但还是有些小问题,这是因为换行操作后,程序还是按照之前的字数来计算,实际上此时应该强制设定接下来的是第一个字。所以我们需要在读到1A这个换行操作后,把DA020

通过追踪可以看到程序中读出1A会跳到0:35BF,在这里转出,给DA02赋值00,确保换行后始终是第一个字

0:35BF

jp 3FC4

 

0:3FC4

call ResetDA02

call 3CF7

jp 35C2

 

程序ResetDA02用于将DA020, 把这个程序放在Bank 0,这样如果后面其他地方还要用的话可以直接调用

0:3FB3

ResetDA02:

push af

xor a

ld (DA02),a

pop af

ret

 

这样换行后字体就显示正常了。

19-05.png

采用类似的操作,对于等待输入控制符12也做相应修改,程序中读出12会跳到0:3511,在这里转出,将DA02DA04都归0,确保按A键确认后始终是第一个字,且在VRAM中从头开始写入

0:3511

jp 3FCD

 

0:3FCD

call 3FBA

call 1ED1

jp 3514

 

程序ResetDA04用于将DA02DA040

0:3FBA

ResetDA04:

push af

xor a

ld (DA04),a

ld (DA02),a

pop af

ret

 

到这里我们就完成了11x11拼字的程序,后面就会基于这个版本再去做其他部分的汉化。


上一篇:求助:宝可梦黑2在特定进度必然出现卡死
下一篇:也许是最好的vr(oculus quest2)游玩入门分享
最新回复 (3)
  • 四级用户 jackyjoe 17小时前
    0 2
    感谢分享 不明觉厉
  • 四级用户 minghan0313 17小时前
    0 3
    每次看这种教程我都在感叹第一个做汉化的人是怎么研究出来的。
  • 四级用户 ruanxiaorui 17小时前
    0 4
    汇编语言看着就头大 大佬牛逼
    • 老男人游戏网配套论坛
      5
        立即登录 立即注册
发新帖
本论坛禁止发布SWITCH和PS4相关资源,若有其他侵权内容,请致邮3360342659#qq.com(#替换成@)删除。