游戏开发之Photoshop导出所有图层信息


引言
相信很多游戏开发者,不管是程序、策划、美术都遇到过这样一个问题:程序员通过手拼接出来的UI界面效果往往达不到美术和策划的要求。导致游戏版本不能够如期正常交付。接下来我们跟随亿元程序员一起探讨一下如何优化这一个问题。
问题是如何产生的?
首先我们清楚,游戏开发在一个团队里,往往是多部门多人协作完成。主要包括以下步骤:
1.需求分析和规划
2.美术设计和素材准备
3.编程和开发
4.测试和调试
5.发布和上线
6.运营和持续更新
7.客户支持和反馈处理
往往我们的问题产生于美术设计和编程开发之间,美术设计的素材通过审核之后,会把素材和效果图提供到程序,程序再按照美术效果图一比一手工拼接。但是由于拼接界面是一个非常精细的活,稍有不慎就会导致素材之间有一定的偏差,从而导致UI整体效果达不到预期的效果,从而造成返工。
如何避免这个问题
通常我们要避免程序拼接效果达不到预期的问题,需要非常规范化的协作流程:
1.与美术进行清晰明确的沟通,确保理解并达成一致的设计目标。
2.在UI拼接前,与美术一起审查效果图,并将不一致的地方进行标注和记录。
3.确保程序员和美术之间有良好的协作和沟通,及时解决和调整不一致的地方。
4.在实际拼接过程中,尽可能使用可视化工具或编辑器,以便直观地展示实际效果。
5.进行多次迭代和测试,及时修复和调整不一致的问题。
6.定期召开项目评审会议,让所有相关人员共同审查和确认最终效果。
7.若出现无法解决的问题,寻求专业人士的帮助或寻找合适的替代方案。
只要我们规范化地遵守上述流程,我们就能大概率避免产生这个问题。
构思
有没有一种可能,程序在拿到美术素材的时候,界面已经是拼接完成的状态,程序只需要编写相应的代码绑定相关的素材以及游戏逻辑就可以完成游戏功能的开发?
答案是有的。其实美术在设计素材完成和审核的时候,效果往往就已经达到了最优的状态。这个时候只要原封不动地将素材给到程序即可。
Photoshop导出所有图层信息
游戏素材在PS里面一般是以不同的图层形式存在,设计完成后,会把所有图层导出成PNG。正常导出的话,我们游戏素材的位置摆放信息不会保存下来。因此我们要解决的问题就是如何把图层的重要信息导出来。
经过研究,Photoshop 通过脚本支持外部自动化。什么意思呢?就是说Photoshop 能够执行我们自定义的脚本,从而去解决我们的需求。我们可以利用 JavaScript 支持编写可以在 Windows 或 macOS 上运行的 Photoshop 脚本。
通过文档的查阅,我们了解到要导出所有图层信息,要用到以下几个API:
获取当前文档中的所有图层:
var layers = app.activeDocument.layers;
获取指定图层的名称、类型、可见性等属性:
var layer = app.activeDocument.layers[0];var name = layer.name;var type = layer.kind;var visible = layer.visible;
获取图层的像素数据:
var layer = app.activeDocument.layers[0];var bounds = layer.bounds;var x = bounds[0].value;var y = bounds[1].value;var width = bounds[2].value - bounds[0].value;var height = bounds[3].value - bounds[1].value;
导出文件:
var path = "";var file = new File(path);file.open("w");file.write(content);file.close();
我们通过这几个API编写完脚本之后,可以选择“文件”>“脚本”,然后从列表中选择脚本。脚本列表包含以 .js 或 .jsx 扩展名存储以及在 Photoshop 2022/Presets/Scripts 文件夹中存储的所有脚本文件,我们要提前把编写好的脚本放到此文件夹中。要运行存储在其他位置的脚本,请选择文件 > 脚本 > 浏览,然后浏览到该脚本。
实践
实践过程由作者自己编写的微信小游戏《填色之旅》提供,大家可以自行搜索体验。首先这个游戏的核心玩法是把从一张完整的图片分割出来的一系列碎片填回到正确的位置,全部填完则游戏通关。
原工作流程:美术将关卡一张完整的图片分割成若干色块给到程序,程序根据效果图将不同的色块在编辑器从新拼凑到一起。这样的工作流程会因为坐标的偏差导致图片会出现“漏色”情况,也就是上面说到的因为人为原因导致效果达不到预期。
所以我们采取了直接导出图层信息,然后通过工具直接生成所需要的关卡。流程如下:
1.首先美术将关卡的原图拆分,形成众多关卡碎片。

2.编写我们核心的Photoshop脚本,核心js代码如下:
function changeLayerName(doc, name, isRoot) {    var content = "";    var layers = doc.layers;    if (layers) {        for (var i = 0; i < layers.length; i++) {            var layer = layers[i];            layer.name = name + "_" + [i]; //修改图层名字            var bounds = layer.bounds;            var x = bounds[0].value;            var y = bounds[1].value;            if (!(isRoot && i == 0)) {                content = content + ",";            }            content = content + "\"" + layer.name + ".png\":{\"x\": " + x + ",\"y\": " + y + "}";            content = content + changeLayerName(layer, layer.name, false); //递归处理        }    }    return content;}
3.将脚本放到Photoshop的脚本目录。

4.然后在PS菜单 然后在 文件->脚本 中找到自己的脚本点击执行。

5.或者通过 文件->打开 直接执行我们编写好的脚本。

6.脚本执行完毕,所有图层导出成png,并且生成自定义的data.json文件,里面记录了每个图片素材准确的坐标位置。

7.笔者用的是Egret引擎,所以再根据导出信息用工具生成引擎所需要的ui皮肤文件。这个工具其实可以优化到Photoshop脚本里,c#代码如下:
static void GenLevel(DirectoryInfo di, StreamWriter sw, JObject jObject){    DirectoryInfo[] dis = di.GetDirectories();    for (int i = 0; i < dis.Length; i++)    {        GenLevel(dis[i], sw, jObject); //递归    }    string cur = di.FullName;    FileInfo[] fi = di.GetFiles("*.png");    bool bFirst = true;    int offsetX = 0, offsetY = 0;    foreach (FileInfo item in fi)    {        JToken jToken = jObject.GetValue(item.Name); //通过data.json获取到散件的坐标信息        int x = Math.Max(0, ((int)jToken["x"]));        int y = ((int)jToken["y"]);        Bitmap bitmap = new Bitmap(item.FullName);        if(bFirst)        {            bFirst = false;            offsetX = x;            offsetY = y;            string folderName = di.Name;            sw.WriteLine("\t\t<e:Group width=\"{0}\" height=\"{1}\" scaleX=\"1\" scaleY=\"1\" visible=\"true\" horizontalCenter=\"0\" verticalCenter=\"0\" x=\"{2}\" y=\"{3}\" name=\"{4}\">", bitmap.Width, bitmap.Height, x - offsetX, y - offsetY, folderName);        }        sw.WriteLine("\t\t\t<e:Image width=\"{0}\" height=\"{1}\" x=\"{3}\" y=\"{4}\" alpha=\"1\" visible=\"true\" source=\"{2}\"/>", bitmap.Width, bitmap.Height, item.Name.Replace('.', '_'), x - offsetX, y - offsetY);    }    sw.WriteLine("\t\t</e:Group>");}
8.执行脚本生成我们需要的ui皮肤。

总结
笔者通过一个简单的小游戏给大家实践了一个美术从Photoshop 直接生成引擎所需要的ui皮肤文件。当然小游戏只是用到其中最基本的坐标属性。做成了适合自己项目使用的工具。大家可以根据这篇文档的思路,构建适合自己项目、甚至合适当今主流的游戏引擎的脚本。
但是也有不足的地方,美术在做素材的时候,一般是自己命名图层,想要完美地生成所需要的ui编辑文件,还得更加细致规范化地命名图层。这个问题就交给大家自行研究了。
本文完整源码可以通过关注"亿元程序员",发送"Photoshop"获取。
游戏名字"填色之旅",欢迎大家搜索体验。
关注我,给大家分享更多更好的技术、实用的编程技巧。
觉得本文有帮助的可以点个赞和在看,请作者喝个咖啡。谢谢大家。

点击微信公众号 关注我们
到顶部