Toolkitly

九宫格编辑器

在面板或按钮上标出四条切割线,实时看它在任意尺寸下的样子——中间是平铺而不是拉伸—— 然后带走 PNG、.9.png,或者你的引擎要的那几个数字。免费、无需注册, 所有像素都留在你的浏览器里。

不会上传任何文件——图片在你的浏览器里切割和重绘。

怎么设置一个九宫格

四个数字,外加一个决定边框能不能活下来的设置。

  1. 1载入面板图把 PNG、WebP、GIF 或 JPEG 拖到虚线框里,或点击选择文件,也可以直接从剪贴板粘贴。
  2. 2把线放在不能变形的那部分往里一点拖动它们,或者直接填四个数字。角上有花纹就放在花纹外侧,圆角边框就过去一两个像素。 中间那个虚线框就是会被重复的部分。
  3. 3保持在「平铺」然后切到「拉伸」再切回来。在像素画上这个差别一点都不含蓄, 而这正是这个工具存在的理由。
  4. 4拿走数字或者文件四个数直接填进 Godot 或 Unity。想要文件的话, 导出缩放后的 PNG 或者 .9.png。

中间部分为什么该平铺而不是拉伸

两者干的是同一件事:把四角之间的空间填满。区别在于填的时候对像素做了什么。

拉伸是把目标位置映射回原图去采样。 3 像素宽的边框要铺满 40 像素,就得用 3 个像素造出 40 个; 而这个比例不是整数,于是有些原始像素占了 2 个目标像素,有些占了 3 个。 开着平滑滤镜边框会糊;关掉平滑——像素画管线就是关掉的——边缘还是硬的, 但粗细会明显地忽宽忽窄。

平铺按原始尺寸重复中间部分。每个像素永远是作者画它时那么大。 代价是中间那块必须是经得起重复的东西——纯色填充, 或者周期能整除进这块区域的花纹。

CSS 的 border-image 默认拉伸,除非你写 border-image-repeat: repeat。Godot 的 NinePatchRect 默认拉伸, 除非把 Axis Stretch Mode 设成 Tile。Unity 的 Sliced 精灵默认拉伸, 除非选 Tiled。三者的默认值对像素画来说都是错的—— 这就是为什么那么多像素 UI 的边框会随着面板变大而变粗。

那四个数字,各引擎的写法

每一种实现要的都是同样这四个距离, 它们只在「叫什么名字」和「按什么顺序写」上有分歧。

Godot 把它们放在 NinePatchRect 上,叫 patch_margin_leftpatch_margin_toppatch_margin_rightpatch_margin_bottom。 有名字,不会填错。

Unity 把它们放在精灵上:Sprite Editor → Border。 这个字段是 Vector4,顺序是左、下、右、上。 这个顺序别的地方都不用,中间两个一调换, 做出来的面板看着几乎是对的,直到上下边距不一样才露馅。

CSS 写作 border-image-slice, 顺序是上、右、下、左——和 margin 一样; 想让中间那块也画出来就加 fill

Android 和 LibGDX 根本不收数字: 它们读 .9.png 外面那圈 1 像素的标记边—— 这也是那个导出选项存在的原因。

什么时候用得上

对话框和面板

一张 24×24 的面板图能撑起游戏里所有尺寸的窗口, 占用的贴图内存只有逐个画的零头。

宽度跟着文字走的按钮

按钮宽度随文本变化时,边框不能跟着变粗。这就是标准答案。

血条和进度条

两端的圆头保持原大小,中间部分伸长—— 就是一个上下边距为 0 的九宫格。

素材进引擎之前先验一遍

在还没进引擎的时候就看到面板放到 3 倍是什么样, 而不是等截图出来才发现边框在抖。

导出格式

PNG——预览尺寸下的成品图, 适合尺寸固定、不想在运行时再算一遍的情况。

.9.png——图外面加一圈 1 像素标记边, Android 和 LibGDX 读的就是这个格式。这圈边是生成的, 不会有那种让手工文件被判为格式错误的多余像素。

JSON——四个边距值, 外加已经按 Godot 的属性名和 Unity 的顺序排好的同一组数字, 拿过去不用再手动调顺序。

在引擎里怎么设

边距只是一半,拉伸模式是另一半。

Godot

NinePatchRect,填四个 patch margin, 然后两个轴的 Axis Stretch Mode 都设成 Tile。 贴图的 Filter 也保持 Nearest

Unity

Sprite Editor → Border,然后用 Image 组件、 Image Type 选 Sliced——像素画选 Tiled。 Filter Mode 用 Point,Compression 用 None

CSS

border-image-slicefillborder-image-repeat: repeat, 再加 image-rendering: pixelated

常见问题

什么是九宫格缩放?

一种缩放方式:图片的四个角保持原始大小,四条边和中间部分拉大去填满其余空间。对话框、按钮、血条能做成任意尺寸而边框粗细不变,靠的就是它。定义它只需要四个数字——每条边到切割线的距离,其余一切都是从这四个数推出来的。

为什么我的像素画边框一拉伸就不对劲?

因为拉伸是在重采样。手工画的 3 像素边框,被拉到 40 像素宽,就得用 3 个像素造出 40 个;由于比例不是整数,有些原始像素变成 2 个像素宽,有些变成 3 个。没有变糊,但粗细肉眼可见地忽宽忽窄。平铺则是按原始尺寸重复中间部分,每个像素都还是原来那么大。本工具默认平铺;而 CSS border-image 和大多数引擎默认拉伸——问题通常就出在那里。

在 Godot 里该填哪些数字?

NinePatchRect 有 patch_margin_left、patch_margin_top、patch_margin_right、patch_margin_bottom 四个属性,就是这里显示的四个数。像素画还要把 Axis Stretch Mode 设成 Tile——默认是 Stretch。工具里按 Godot 自己的顺序把四个值列出来了。

Unity 呢?

Unity 把这件事放在精灵本身:打开 Sprite Editor,设置 Border。坑在顺序上——Unity 的 border 是一个 Vector4,顺序是「左、下、右、上」,和 Godot、CSS、Android 用的顺序都不一样。填错了会把上下边距对调,看起来几乎是对的,但就是不对。工具按 Unity 的顺序单独列了一行,可以直接抄。

.9.png 是什么?

Android 的 NinePatch 格式:同一张图,外面加一圈 1 像素的边,边上的黑色像素标出哪些列和行可以拉伸。LibGDX 也认。这圈边的其余部分必须完全透明——多出一个像素就会被当成第二个拉伸区域,这也是手工做的 .9.png 经常被判为格式错误的原因。本工具导出的那圈边是生成的,不会有这个问题。

切割线该放在哪?

放在「不能变形的那部分」刚刚往里一点。角上有装饰花纹的面板,就放在花纹外侧;普通的圆角边框,放在圆弧过去一两个像素。中间那块是会被重复的部分,所以它应该是那种翻倍之后看起来还一样的东西——纯色填充,或者周期能整除进这块区域的花纹。

图片会被上传到服务器吗?

不会。图片是用浏览器的 Canvas API 在本地解码、切割和重绘的。没有任何数据离开你的电脑,页面加载完之后断网也照样能用。

相关教程

相关工具