我对2维码的设计又思考了一下,加上了一点碌亩鳌? 9 M- V7 i; Q, N, n; u N# F2 F
这就是校验码。为了便于理解,我制做了一张设计图。 ) j% ^9 F! e) K
这是一张4X4象素的图,这4X4象素代表一个字母,也就是1个2维码,同时对应一个ASCII码。 5 l% F% q- A+ Q, [. M5 e
3 M2 `3 M+ @, e6 T, }" U/ i为什么要使用校验码呢。其实略为思考一下就很容易想到,我们的2维码是显示在有背景的游戏画面上的,所以不可避免可能发生2维码的有色点和背景颜色相同的情况,如果一个像素原本应该是透明的,但是背景的颜色和有色点的颜色正好相同的话,我们的2维码识别程序就会把这个点识别为有色点,这样的话,整个2维码就识别错了。
: }# }% _) v/ `9 h* y3 e
1 n" o [2 B5 [6 R' i' b9 }让我们来看一下示意图.首先让我们来估算一下字幕的数量,不满255的话可以使用8像素的2维码,就是图上的浅黄色的点.如果>255的话就要使用9像素的2维码.校验码表示的是有色点的个数,对应的,使用8像素的2维码的时候使用3像素的校验码,使用9像素的2维码的时候使用4像素的校验码.因为3个2进制数字可以表示1-8,4个2进制数字可以表示1-16.
( `" X7 t# x1 ?( N5 }& M) b& V( e8 J3 a/ K3 Y+ O8 G9 p8 Z9 \
当我们的识别程序发现校验码和2维码的有色点的个数不同的时候,可以输出log,从而找到被错误识别的那个ID。 8 a* G* ~& o% v% ?
4 \9 b# Z, W7 v5 d7 ?9 E; n# N1 r. e--------------------------------------- ; i# y1 o. h2 t% J# G# Y, h
2009.6.6 更新
9 E: `- E+ D% T7 P6 V8 u
4 J/ Q) i- o6 n" _% f看了肥牛还没有完全理解,或者是理解了没有表达清楚.
/ _7 S7 t; C3 {. O) X我再补充说明一下. 9 o- \7 H5 G5 T' Q7 c
9 @/ h/ k) W: ~) }; X7 q我们不妨做一个比方,我们把图片字模库tga看作为一个函数,其中每个象素的前3个字节 FF FF FF就好比是函数的参数,是形参。 ) t1 ~ ^) v0 S9 O8 s
那么实参是什么呢。实参是设定在游戏配置文里的字体颜色。那么函数值是什么呢?函数值是显示到游戏画面上的字体。根据实参,也就是设
3 ]- r% T' k! [8 Q定的字体颜色的不同,那么函数值,也就是最后显示出来的字体颜色也不同。
3 }$ ?! l: n+ n) }! n, F' Z上面的应该比较容易理解,接着我来说明肥牛可能有误解的地方。
1 Z9 T$ G' s+ ~7 g5 W' |0 B我说有色点是FF FF FF FF,透明点是FF FF FF 00,这仅仅是指tga图片字库里的数据是这样的。 & w& {9 Q' n- ` i$ h a
你可以看作一个函数的内部有这些数据。
* ]- M6 W# }9 f- g% p一旦字体被显示出来,相当于显示的是上面这个tga图片字库函数的值。
8 }% w$ K5 A: l9 u2 [假设我们设定的字体颜色是 AA AA AA,那么上面的有色点被变换为AA AA AA FF,而透明点则把游戏画面上对应位置的像素颜色显示出来。 ( u0 `7 J4 a+ N+ H9 t5 N- [% {! Q
所以,一旦字体被显示到屏幕上以后,那个3X3的小块里面的颜色状况就
7 i3 T( t& [! `4 {# g. L) \$ u+ q* [2 H
不是 有色点是FF FF FF FF,透明点是FF FF FF 00 * g+ O- ^3 @. R, v
而是 有色点是AA AA AA FF,杂色点是 游戏原来像素的颜色 (32bit) ! v/ s( ], t! r. T: }
: M0 ~% \% G4 r% z) n5 Z9 @
我们从log里可以看出,游戏是运行在32bit模式下的。 ) \# ?- U) W+ U$ K& u% ~1 Q
22:11:58: D3D9 : Created D3D9 Rendering Window 'Ankh - Heart of Osiris' : 1024x768, 32bpp
2 u- f y# L; i) J, a+ y4 i2 s s6 Z
好,我们再回过头来看看。对于透明色的问题,解释到这里,应该明白了吧。
; t% G) d. e1 V# U$ _ k
' r9 w: ?0 N& ~! A我就没想明白透明像素叠加到背景上以后怎么再读取出来。 ) p( {$ R1 ?* Z( T( M3 {; g
透明像素叠加到背景上以后就不是透明的了,我们自然可以把它和字体的颜色区分开来。 ! C N/ A) C) h2 u
为了防止通过透明像素透出来的游戏原来的像素的颜色和字体的颜色一样,我们引入了校验码。
" F4 Z$ l+ B/ m校验码的读取也很简单,校验码和字体是用同一种颜色显示的,比方说字体颜色是AA AA AA FF,那校验码的颜色也是AA AA AA FF。 9 [ ]$ Y! ?; X! l; r6 V9 }: n5 m
`. `6 R: f) C6 l% g. `. U从设计图上可以看出,校验码显示的位置是固定的,所以我们可以判断出校验码的3,4个点中有几个点是AA AA AA FF。校验码的每一位的颜色和AA AA AA FF是否相同的状态,可以看作0和1,这样就可以表示8或16种状态,表示3X3 2维码中的和设定字体颜色相同的点的个数。如果这个
- @, v( B+ J& Z. a2 c% n j( R! e个数和实际的3X3 2维码中的和设定字体颜色相同的点的个数不同,那么就表示校验不通过,有识别错误。
1 `0 ` I" C, s2 [. m G
' m1 L8 c. u( V) T# f" ?& J有人也许会说,校验码本身被识别错误了怎么办? " h7 D1 ~) v9 G5 l
这种情况是存在的。校验码不能校验出全部的错误,但是从概率上说,能校验出绝大部分错误。
; s( Q* |8 _ L为什么这么说呢?因为发生错误识别的情况只能是,某个点被多识别了。这里说的某个点是指在游戏背景上和字体颜色相同的点。
- s3 g6 Z. { y9 C7 a4 r" O7 k所以,校验码校验不出来的情况只有一种,这就是校验码和2维码都被多识别了几个点。然后错误的校验码表示的数值和错误的2维码的和字体颜色相同的点的数量碰巧相同。这种情况应该是很低概率的。 & k* y0 h4 N5 G2 |
7 W+ ^7 r9 K! T4 E! l. {最后要说的是,校验码只在游戏测试阶段有用,汉化补丁发布时最好把校验逻辑从proxy dll中去掉,以免影响速度。tga图片本身可以不修改,但是xml文件要修改,把每个字母的划分改动一下。 $ k2 h. p/ z$ [3 l, m: @0 g
从4X4 改为 3X3。就是说要改x,y width,heigh. ( g, W$ K2 L+ \& d# R
" z2 `3 `9 Q: p# ~% @--------------------------------------------------------
$ e+ g0 W7 y% g. M2009.6.15 更新
) }( a t( v( f) [& E- D4 G最近又想了一下2维码的部分,又冒出了新的想法。
1 d4 A: n% K, I" i如果能实现的话,能把现有的方法大大简化,彻底抛弃比较复杂的2维码,还能做到误识别率为0。 * n, M5 h) ^2 |: n1 s7 |
说出来很简单,我们把原来显示在屏幕中部的字幕向下挪动到底部的黑色背景上就行了。 ' i# [. k1 v7 D T% u0 ~
具体怎么挪动只要修改xml里面在y方向的修正值就行了。 / G, k* s6 z5 j2 |$ F8 Z w( H+ e8 k
一旦我们能把原来显示在屏幕中部的字幕向下挪动到底部的黑色背景上的话,我们就能用原来条形码的那套判断方法来判断了。比较复杂的2维码也可以抛弃了。 4 s% l* A: B- m* N# I
当然,我们判断出ID以后,在proxy dll中还是要把对应中文字幕显示在屏幕中部的。
& o9 t: I% F5 C由于字幕的判断都统一到条形码上,我们只要把除主菜单ID外的所有ID都对应到一个12或13位的条形码上即可。 |