作为一个常年折腾2D游戏素材的人,我几乎每天都要在Aseprite和Unity2D之间来回倒腾。很多刚开始做平台游戏的朋友,拿到Aseprite的第一反应是:这不就是个像素画软件吗?我画个方块存成PNG拖进Unity不就行了?真这么干,十个里有八个会遇到素材模糊、瓦片对不齐、碰撞体乱飞这些糟心事。这篇东西我会把这套从零开始的瓦片地图素材制作流程,一步一步拆开揉碎讲清楚,包括怎么在Aseprite里画出能无缝拼接的瓦片、怎么把图集正确切回Unity里用、还有Rule Tile自动拼接和碰撞体配置这些真正影响手感的关键点。全程都会按平台游戏(Platformer)这个具体场景来走,刚好想入门的,或者已经在用但总感觉哪里不对劲的,这篇应该能帮你把整个链路打通。
1. 整体思路与工作流设计
1.1 为什么平台游戏需要单独设计瓦片素材
平台游戏的地图特点是重复度高、模块化明显。一整片森林地面,本质上就是同一个泥土块的横向循环;一段断崖边缘,则需要单独的“尽头”块来保证视觉闭合。如果你用一整张超长图片去拼地图,后期改关卡地形会非常痛苦,碰撞区域也不好布置。瓦片地图的核心思路,是把大世界拆成若干相同尺寸的小格子,用图块拼接来构建地形,这样无论地图多大,资源只占用一套素材。
Aseprite在这个流程里扮演的角色就是“瓦片生产车间”。它的网格显示、图层结构、索引色模式都天然适合像素级创作,而且导出时可以精确控制透明通道和边缘,不会像Photoshop那样非得调一堆压缩选项才能导出一张干净的图集。Unity2D这边,Tilemap系统配合Tile Palette就是“施工队”,负责把瓦片摆到场景里,并通过Rule Tile之类的扩展自动处理邻接关系。
我在设计工作流的时候,会明确划分三个阶段:第一,在Aseprite里画好所有需要的瓦片变体并导出一张规整的图集;第二,在Unity里配置图片导入参数,用Sprite Editor切片,建Tile Palette;第三,做规则瓦片并铺设地形,最后检查碰撞体的表现。三个阶段各管各的,不容易乱。
1.2 像素尺寸规划:从16x16到32x32的选择逻辑
瓦片的像素尺寸是所有后续工作开展的前提。Unity里有一个核心概念叫Pixels Per Unit(PPU),意思是一格Unity单位长度对应多少像素。对于平台游戏,16x16像素的瓦片配合PPU=16是最常见的复古分辨率,人物按32x64像素来画,整体会呈现典型的8-bit/16-bit时代观感。32x32像素的瓦片配合PPU=32则适合细节更丰富的作品,人物通常有64x64以上像素。
这里的换算逻辑并不复杂:如果瓦片是16x16像素,PPU设为16,那么一个瓦片在Unity的世界坐标中就正好是1x1单位,Tilemap默认Cell Size也是1,这样铺出来的地图数值上非常干净。假如你把16x16的瓦片放进PPU=100的工程,每个瓦片就只有0.16个单位大小,Tilemap里摆放时会出现大量小数坐标,碰撞体和物理计算都容易产生微小的误差累积。所以最省心的方案,就是让瓦片的像素边长直接等于PPU的数值。
在这个阶段还应该想清楚另一个问题:需要哪些瓦片变体。平台游戏最基础的地形素材,至少要有泥土填充块、草地顶面块、左右边缘块、角落块、独立平台块、装饰点缀(草、花、石头)这几类。我建议在动手画之前先把瓦片清单列出来,画的过程中就不会出现“地基铺了一半发现没有靠墙的块”这种尴尬情况。
2. Aseprite端绘制:从配置画布到导出图集
2.1 新建文档时的关键参数与图层规划
打开Aseprite,新建文档时直接设成16x16或32x32,颜色模式选RGBA。虽然Aseprite支持索引色(Indexed),但早期阶段用RGBA更安全,因为Unity这边对透明通道的处理更友好,避免索引色导出时把透明度压缩出硬边。
背景层的处理是很多新手容易忽略的点。默认新建文档会有一个白色背景层,画瓦片之前要把这个背景层删掉或者让它在导出时不可见,否则PNG会带一个不透明的白色底,铺到Unity里就把地面变成一块块白板了。正确做法是保留透明画布,所有元素画在图层组里,导出时背景保持全透明。
图层规划建议这样:一组“泥土基底”在最底层,一组“草地顶面”在中间,一组“高光阴影”在最上层。以16x16地面瓦片为例,泥土基底用棕色系铺满整个格子,草地顶面用绿色系占住最上面4~5行像素,再用深绿色在草丛下沿加一条1像素的阴影,顺便在泥土区域点几个深棕色噪点。画完之后把三个图层合并。注意最后合并时要选中所有可见图层再Ctrl+Shift+E,这样导出的图集才是单一图层,方便Unity这边切割。
2.2 无缝拼接的核心技巧
无缝拼接是瓦片绘制里最关键的关卡。一个地面块要能被无限复制而不出现视觉断裂,关键在左右两边和上下两边的像素要能跟相邻块自然接上。我的做法是:在Aseprite里开启网格视图(View -> Grid),然后先画出中心部分的纹理,最后再处理边缘4条边。
处理左右衔接时,有一个百试百灵的方法:先把左边边缘列复制到右边边缘列,再微调中间的过渡像素。更简单的思路是让纹理设计本身保持周期性,比如在16x16的块里设计一段在横向上从第0列到第15列周期性重复的暖绿色草丛,画的时候从中间向两边扩展,左右边缘自然就能对齐。到了“草地顶面”这一行,不要画成标准的水平直线,而是让草叶尖在Y轴方向上有2~3像素的高低起伏,同时保证两端的宽度一致,这样铺出去的一整条地面才会有手绘感而不是贴图感。
泥土纹路同样要遵循这条规则:噪点位置不能出现在边缘列导致被切成两半。如果草率地在第0列画了一个噪点,左右拼接时这个噪点就会变成两个碎片出现在瓦片接缝两侧,特别显眼。
2.3 边缘瓦片与角落瓦片的画法
基础地面块做完之后,要画“草地边缘块”。这个块的用途是放在一条草地的尽头,视觉上草皮在这里结束并露出泥土断面。在16x16画布里,做法是复制一份基础地面块,然后把草皮层往左推进到只占前8列,右边露出的泥土面用深棕色作垂直断口,再在断口边缘加1像素亮色模拟受光面。
角落块需要特别注意方向:左上角、右上角、左下角、右下角是四种不同素材。偷懒的办法是画好一个再用Aseprite的Sprite -> Sprite Properties做水平/垂直翻转生成其他三个变体。但在实际生产中我经常直接手动改,因为翻转后光影方向会变得不自然,尤其是光源在左上方的场景,翻转后高光会跑到右边去。手动画角落块时,只要把握好草皮在L形区域内的走势,其余部分露出泥土即可。
2.4 在Aseprite里导出图集的正确姿势
瓦片画完后,需要把多个瓦片排列到同一张图上导出,Unity才好一次性切出来。我习惯的做法是在Aseprite里建立一个新文档,尺寸由瓦片数量和排列方式决定,比如16x16瓦片做成4x2排列,那新文档就是64x32像素。然后把每一块瓦片对应的Aseprite文件内的像素内容复制黏贴到对应位置,彼此之间保留1~2像素的透明间隔,这样Unity的Sprite Editor按网格切割时不会切到邻接瓦片的内容。
导出时用File -> Export选择PNG,勾选“Sprite Sheet”模式(Aseprite术语叫Sprite Sheet export),把Layers全部打勾,确保透明背景。输出设置中要注意,缩放保持100%,不要开Rotation,不要开Trim,否则图集尺寸会变化导致Unity切割网格对不上。更稳妥的做法是,Aseprite的导出窗口里有“Padding”选项,设成1或2像素的透明边框,可以防止后续用纹理集时出现边缘溢色。
3. Unity端导入与Tilemap搭建
3.1 图片导入参数:纹理过滤与压缩设置的坑
图集做好了,把它拖进Unity Assets文件夹。这一步的导入设置如果配错,后面全白搭。在Inspector里选中这张PNG,Texture Type改成Sprite(2D and UI)。Sprite Mode选择Multiple,因为我们要在同一张图里切出多个瓦片。Pixels Per Unit填16(对应16x16瓦片,32x32瓦片就填32)。
Filter Mode必须选Point (no filter)。像素画用Bilinear或Trilinear会糊成一片,原本锋利的像素边缘会像隔了一层毛玻璃。这一点在2D平台游戏里几乎没有商量余地,只要素材是像素风,Filter Mode就该是Point。接下来还要把Compression改成None,确保Unity不会对纹理做二次压缩导致边缘渗色和模糊。很多新手在这步偷懒,选了个Default,结果瓦片在地图里看起来像褪了色一样。
另外,Generate Mip Maps这个选项建议关闭。2D游戏中摄影机通常不会让瓦片剧烈缩放,mipmap不仅白占内存,还会在部分平台上引起瓦片缝隙闪白线的现象。这些参数设完,点击Apply,再看Sprite Editor。
3.2 Sprite Editor切图:Automatic切割的局限性
打开Sprite Editor之前,先确认右上角“Slice”菜单。选择Grid By Cell Size,并填入16x16的像素尺寸。如果图集是按4x2排列,这里可以输入X=16,Y=16,然后按Slice。Aseprite导出时有透明边框的同学,需要把Pixel Size的X和Y设成瓦片尺寸加边框宽度,也就是18x18,切出来的Sprite内容才正确。
还有一个细节值得花时间确认:每个Sprite的Pivot(轴心点)是不是在Bottom Left或Center。对瓦片来说,我通常选Bottom Left,因为Tile Palette在场景里放置瓦片时,会以Pivot作为贴地的锚点。如果你用Center做地面瓦片的Pivot,那么瓦片的一半会陷到地面以下,视觉上铺完后还得微调Y坐标,非常麻烦。
3.3 搭建Tile Palette工作区
切完图集,Window -> 2D -> Tile Palette,点窗口上的Create New Palette,取名叫PlatformTiles。在右侧把刚才切好的瓦片逐一拖进Palette窗口。建议在Palette里按逻辑分组摆放:第一排放地面系列变体,第二排放边缘和角落,第三排放装饰。这样绘制Tilemap时找起来眼不累。
Tile Palette在Unity 6里已经整合到2D Tilemap Editor流程中,操作上变化不大。点击Palette里某块瓦片,用画笔工具在场景中的Tilemap物体上刷,就能铺出瓦片。但这里有个很关键的前置步骤:先在场景里建一个Tilemap物体。右键Hierarchy -> 2D Object -> Tilemap,同名创建的Grid会自动把Tilemap作为子物体。如果直接往空场景上刷,Unity会报没有Tilemap的错误。
3.4 碰撞体配置:Tilemap Collider和Composite Collider的组合
有画面没碰撞,角色踩上去会掉下去。给Tilemap物体添加Tilemap Collider 2D后,系统会根据每个瓦片的Sprite轮廓生成碰撞区域,但单独使用它有个明显问题:相邻瓦片之间会生成多余的碰撞边,角色跳跃时身体可能在这些微小缝隙上抖动甚至卡住。
正确做法是再添加一个Composite Collider 2D,并把Tilemap Collider 2D的Used By Composite勾选上。此时Unity会自动合并所有瓦片的碰撞面,形成一整块干净的凸多边形。这里注意,加Composite Collider时它会提示自动添加Rigidbody 2D,把Rigidbody 2D的Body Type设为Static,不然地面会受重力影响掉下去。这套组合的物理表现非常稳,我用它做过上百块长平台,没有一次出现角色在接缝处卡顿的情况。
在配置Platform Effector 2D这种单向平台时,还要注意一个额外细节:如果做了只能从下往上跳的薄平台,需要在瓦片素材里专门画一块“平台顶面”,并为这块瓦片单独设置Sprite的Physics Shape,避免碰撞体把平台两侧也封死。
4. 进阶优化:Rule Tile、图层排序与摄像机设置
4.1 规则瓦片自动拼接的原理与实操
手动铺瓦片虽然直观,但画一条长地面时要摆一堆相邻块,效率不高。Unity的2D Tilemap Extras包提供了Rule Tile的解决方案。Rule Tile的逻辑是:根据当前瓦片周围邻居的填充情况,自动选择对应的瓦片变体来拼接。举例来说,草地地面的左侧如果有空格,Rule Tile会自动换成“右边缘块”;上下左右都有草地,就用“填充块”。
要使用Rule Tile,先通过Package Manager安装2D Tilemap Extras(在Unity Registry里搜索“Tilemap Extras”)。然后在Project里右键Create -> 2D -> Tiles -> Rule Tile。点开这个Rule Tile资产,你会看到左侧是变体列表,右侧是邻居规则矩阵,矩阵中心代表当前瓦片,周围八个格子可以分别设置成“这个位置必须有什么”或“这个位置不能有什么”。
我通常这样做:先把草地的“填充块”“上边缘”“左边缘”“右边缘”“左上角”“右上角”逐个拖入Rule Tile的瓦片槽位,然后为每一种变体设置对应规则。比如左边缘块的规则,就是左侧邻居设为“非草地”,右上邻居和右下邻居也设为“非草地”,其余方向随便。这样在Tile Palette里选中Rule Tile,在地图上只刷中心部分,系统会自动把四周的变体匹配出来。平台游戏里大段大段的森林地形,用这个方式刷简直爽快。
4.2 排序图层与像素摄影机的配合
2D游戏默认情况下,设置不好排序,瓦片可能会盖住角色或跟背景混在一起。最简单也最稳定的分层方式:给不同的Tilemap物体设置不同的Sorting Layer。背景层放在最底层,然后是地面Tilemap层,玩家角色层放在地面之上,最上面是装饰层和前景层。同一个Sorting Layer内,还可以用Order in Layer区分先后,但平台游戏里我更喜欢把可交互的地面、单向平台、背景装饰分别放进不同Sorting Layer,省去以后互相对Order的麻烦。
像素摄影机这边,更推荐用现成的Pixel Perfect Camera组件。Unity官方包2D Pixel Perfect中提供了这个组件,把PPU设为16时,摄影机会自动把渲染分辨率对齐到整数倍,避免像素大小不均匀导致的画面抖动和闪烁。记得开启Crop Frame的“Upscale Render Texture”选项,输出到屏幕时画面才干净。否则,同一块瓦片在不同屏幕上可能偶尔出现0.5像素宽度的视觉差异。
4.3 装饰瓦片的做法:让地图不显得“太监听”
纯泥土地面很容易让人审美疲劳,我通常会在素材库里额外画几块松散的石块和草叶装饰。这类装饰瓦片在设计上有个关键原则:碰撞区域要比视觉区域小一圈。做法是在Sprite Editor里选中装饰瓦片,点击Custom Physics Shape,手动拖拽出一个比实际图像范围小1到2像素的碰撞轮廓。这样玩家路过时不会因为一个小小的草叶而像撞到墙一样被绊住,视觉上又有丰富的层次感。
此外,装饰瓦片的摆放建议“少量多处”,每铺约十块基础地面时点缀一块装饰,而不是密集地铺一整片。平台游戏的可玩性来源于玩家对地形信息的快速判断,装饰过多会干扰割跳点的识别。我见过很多新人往地面上撒满草和花结果根本看不清落脚点在哪,这个度一定要把握好。
5. 常见问题排查与避坑实录
5.1 瓦片间出现细白线的完整排查方案
这是做瓦片地图最常遇到的问题:地图上的瓦片明明拼得很整齐,运行游戏时接缝处却时不时闪现一条细细的白线或黑线。绝大多数情况下是Filter Mode和Compression没设对。Filter Mode的Bilinear会把相邻像素混在一起,当摄影机有细微移动时,纹理边缘就露出一条半透明的混合像素。先把Filter Mode改成Point并且关闭Compression,通常能解决一半的问题。
如果还有白线,就要检查图集切片的边缘是否带上了邻接瓦片的透明像素。Aseprite导出时,在瓦片之间隔开1~2像素并启用了透明边框的话,Unity这边用Grid By Cell Size切图时要把透明边框算进去。还有一种稳妥的办法:给每块Sprite在Sprite Editor里,把Mesh Type改成Full Rect,同时把Sprite的Border手动设为0。这一招能消除大部分由物理模型裁剪引起的缝隙闪线。
5.2 像素画面模糊或边缘泛白的原因
如果运行画面里的瓦片边缘出现类似“轻度水彩渗开”的效果,八成是纹理压缩引起的。Unity在移动平台会把纹理自动压缩成ASTC或ETC格式,这种格式为了减体积会丢失颜色精度,透明边缘就会泛白或泛灰。在导入设置里把Compression选成None,并在Build Setting里关掉Texture Compression的Override选项,就能从源头解决。
再检查一下摄像机是不是在看非整数倍缩放。假设关掉了Pixel Perfect Camera,或者自己手动把摄像机Orthographic Size设成了带小数的值(比如5.34),瓦片就会被拉伸到非整数像素上,看起来自然发虚。Pixel Perfect Camera组件的核心价值就在这里:它保证每个像素对齐整数屏幕像素,画面锐利不糊。
5.3 角色跨过瓦片拼接处时发生抖动
这个坑通常不是素材问题,而是碰撞体问题。当Tilemap使用单独的Tilemap Collider 2D而没有Composite Collider 2D时,相邻瓦片之间会有极小的碰撞缝,角色以较高速度跨越时,刚体会在这些缝隙上产生细微的垂直位移,表现出来就是“抖了一下”。我个人强烈建议所有静态地面统一使用Composite Collider 2D合并碰撞体。如果做单向平台还发生类似抖动,检查Platform Effector 2D的Use One Way属性的同时,留意角色的Rigidbody 2D Collision Detection是否设成了Continuous。
5.4 问题排查速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 瓦片接缝处有细白线/黑线 | Filter Mode不是Point、纹理被压缩、Sprite边缘渗色 | 设为Point、Compression改为None、检查Aseprite导出边框 |
| 瓦片画面发糊 | 摄像机非整数缩放、纹理mipmap开启 | 使用Pixel Perfect Camera、关闭Mip Maps |
| 瓦片颜色发灰偏色 | 纹理压缩格式导致颜色精度丢失 | Compression改成None,取消平台压缩Override |
| 角色跑过接缝抖动 | Tilemap碰撞体未合并、Detection模式太低 | 添加Composite Collider 2D、Collision Detection改Continuous |
| Tile Palette绘制无反应 | 场景中没有Tilemap物体,或瓦片Pivot异常 | 添加2D Object -> Tilemap,检查Sprite Pivot |
| 瓦片在Aseprite里正常但Unity里偏移 | PPU与瓦片像素尺寸不匹配 | 确保PPU等于瓦片像素边长,如16x16配PPU=16 |
| 装饰瓦片挡住角色 | 排序图层设置错误 | 确认装饰层Sorting Layer低于角色层 |
| 边缘瓦片匹配不正确 | Rule Tile规则矩阵未正确配置邻居条件 | 逐个检查规则矩阵的邻居条件,确保上下左右及对角线设置完整 |
5.5 实战工作流中的三个小建议
第一,每隔一段时间就导出一次“最早版本”的瓦片图集。看着只是一堆简单方块的初版素材,其实非常适合用来验证Unity里的导入参数、切片设置和碰撞体表现。等到所有技术链路跑通,再回头精修细节,会比直接画完最终版再导入高效得多,改了三个小时的草叶细节,最终却在导入设置上出问题,实在赔本。
第二,不要忽视Aseprite的“对称绘制”功能。开启对称轴后,画左右对称的边缘块或角落块非常方便。但记住对称轴位置一定要对准画布中线,不然导出的图集左右两半会出现1像素偏移。
第三,做瓦片时要刻意限制调色板颜色数量。画完一个土块后,从色板中选颜色时始终围绕已经出现的几种棕色和绿色进行明度微调,这样整张地图的视觉统一性会非常高。如果每个瓦片都重新配一套新颜色,铺出来的地图就会有明显的“拼贴感”,那是最低级的视觉穿帮。
我在实际项目中最深的体会是,瓦片素材的制作永远是服务于关卡设计需求的。同一个草地块,在快节奏的跑酷平台游戏里可能只需要极简的配色和极少装饰,而在解谜探索类平台游戏里则可以做得更丰富。抓住Aseprite画图、Unity导入和Rule Tile拼接这条主线,遇到任何新需求都能快速扩展素材库。这个基础工作流跑顺之后,不妨试着做一个复刻《Celeste》经典“山顶起步关卡”的小Demo,一旦跑通了你就会对瓦片地图的整个生产链路有非常扎实的掌握。