关闭

【libgdx】2D地图块(tileset)地图出现缝隙(gap / bleeding)的问题

标签: libgdx游戏制作
509人阅读 评论(0) 收藏 举报
分类:

最近按官方wiki写地图块代码时遇到此问题:在Tiled里画好地图,一切都按wiki步骤来,当把地图显示出来,相机在地图上移动时,会发现地图块之间偶尔会出现缝隙(或者是黑线、白线,根据clear用的填充色不同而不同),用英文来描述,就是tiles之间有gap或white/black line,更专业一点的叫法就是tile bleeding。
借用一下别人的图
这里写图片描述
于是google了一顿,终于找到算是OK的解决办法了。
据说此问题是libgdx论坛的日经问题,每隔几天就会有人问,因为一直也没有十分优雅的解决方案,目前唯一据说比较实用的解决办法其原理也是囧得不行,听起来就让人脱力,而给出解答的人往往也都是三言两语,说的都是那种“说起来容易做起来巨麻烦”的话,让人摸不到头脑。于是仍然一直有人在问,恶性循环。。。
然后我终于看到了一篇博客,给出了简单详细的解决办法:http://thekemiren.blogspot.jp/2014/07/tile-bleeding-in-libgdx-using-tiled.html
(注意得翻墙)

我把自己搜到的相关知识总结一下:
首先这个问题让人想到的就是filter方案的问题,是不是误用了linear,而其实应该换成nearest。用过unity3D或者熟习openGL的人估计首先都会想到这个。但是可惜不是,据说libgdx里的OrthogonalTiledMapRenderer渲染器默认用的就是nearest,还有一说这个也不是特别好改(或是改了之后效果不好?感觉论坛上的人都各执一词),总之此路不通。
解决方案二,考虑到之所以出现这种问题,是因为相机(camera)在移动的时候,移动值的类型是float,精度十分高,所以当恰好移动到某一小精度时,可能会导致某两个相邻图块的渲染出现了1象素的位置偏差(比如左边的图块x坐标舍了点,右边的图块x坐标入了点,于是他俩之间出现了一个1象素的纵向的缝)。综上所述,想到的解决办法就是,不让相机的移动有如此高的精度,比如可以让移动的最小单位是0.2,不足0.2的可以补上或者舍掉,这样移动的时候就不会产生缝隙了。更极端的做法是干脆让相机按int精度移动。
这种解决方案在修改相册移动的同时必须也修改画面上物体的移动,不然会觉得物体在画面上各种抖动。而且更糟糕的是,它或许不能完全解决问题。比如我上面说的0.2精度,在原大画面时看起来很完美,但是如果画面被放大或缩小,那么这问题可能会再次出现,只能再不断降低精度。降成int就能百分百解决问题了么?似乎并没有人能给出这样的保证。而且把物体的移动精度降成int的同时也削弱了我们游戏的灵敏平滑程度,这也并不是我们所期望的。
第三种解决方案,也就是最终解决方案了,同时也是最麻烦最让人无语但是却又不得不承认是最有效的一个。做法就是:给一大张tileset里的每一个小图块(tile),都加上1个象素的勾边(gutter)。这里特别强调这个gutter,用的不是常见的padding也不是spacing也更不是margin什么的(妈个币的这几个破词我特么纠结好久,论坛上的老外们也是经常分不清楚地瞎叫),虽然挺多人声称那个勾边叫padding,但是这叫法很误导人,我觉得最准确还是应该叫gutter。至于区别,gutter跟padding/spacing最大的区别是,它增加的这一个象素的勾边,不是透明的,也不是填充某种单色(比如黑色、白色),而是根据图块而产生的一个色的延伸。比如某图块的左边缘一纵列象素都是深绿色,那么相应在左边产生的勾边也是深绿色,如果要是一纵列从红到蓝的渐变色,那么产生的勾边也应该是一个象素列从上到下的渐变色。如下图:
原图:尺寸32x32
这里写图片描述

1象素的透明边(padding/spacing)尺寸34x34
这里写图片描述

1象素的色边(gutter)尺寸34x34
这里写图片描述

到这里,大家应该明白这种解法的原理了。假如我用的是32x32的地图块,加了gutter之后就相当于用的是带1象素边缘的34x34图块,但是那多出的一个象素是彼此重叠放置的(在Tiled地图编辑器里可以这样设置),所以看起来仍然是32x32的图块。那么当再因为相机移动而产生1个象素的缝隙时,原本相互重叠的那一个象素就会露出来,但是因为已经勾上边了,所以就算露出来也很难用肉眼看出来这一破绽…………
听起来真是超级囧,非常有悖于大部分程序员一直追求的“优雅”。而且这种解法还导致了一个效能的问题……你的素材可能因此而尺寸不再是2的幂数值了。比如我的256x1024的tileset图片勾了边之后就变成272x1088……虽然libgdx也能hold得住这种尺寸的图片,但是这完全跟官方wiki中口口声声说的“尽量使用2的幂作为图片的尺寸”这一good practice法则相矛盾,但是很遗憾,这确实是官方论坛上目前给出的最有效解决方案,所以也难怪此问题会成为官方论坛上的日经问题了。
而且说到给图片加gutter这件事,如果不是拼好的素材,而是自己用texturepacker现从一个文件夹打包成atlas的素材那还好,直接改改配置再重新打包就好了。但是如果你只有一张完整的tilset素材,由许多张tile图片拼成(比如直接从RPG Maker的RTP素材里copy过来的那种)。这尼玛一个个加起来岂不是要了人命?打开PS,把图片拆成一块一块,然后再扩大画布,给每一块图片一象素一象素地勾上一个边,卧槽,光听就想死了。程序员们肯定想马上写个程序来帮忙做此事了。事实上貌似确实已经有些这样的现成程序了,我在google code上看到一个,但是不知道怎么搞,所以没试。我试了另一种,使用一款名叫GIMP的免费图片编辑软件,它有一个小插件可以帮忙完成此事。http://registry.gimp.org/node/26044
使用时需要这样配置参数:(我懒得自己截图了,用的上面我给的那个博客里的图)
这里写图片描述
就可以完成勾边。而在Tiled里,也一定要设置好margin和spacing(按上面截图勾出来的tileset的话,应该margin是1,spacing是2),才能正常地画地图。
然后直接用到程序里,不用特地为它们写什么,最终效果就非常OK了。不使劲看根本看不出来(对不明真相的玩家来说,使劲看都看不出来)

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:30336次
    • 积分:704
    • 等级:
    • 排名:千里之外
    • 原创:13篇
    • 转载:0篇
    • 译文:28篇
    • 评论:1条
    文章分类
    最新评论