Стала задача автоматизировать сборку GUI для одного проекта X.
Худож��ик делает все свои дела в photoshop и отдает их программистам. Программисты, в свою очередь, сами как-то вытягивают текстуры или атласы и с помощью утилы позиционируют каждый отдельный элемент на stage флешки, далее ручкам добавляют все текстовые поля, эффекты, прописывают всем этим элементам координаты, которые получили благодаря утилите. В итоге получается очень долгая и мучительная работа, а если учесть, что это делает еще и программист — это АД.
Программисту приходится:
Я уже не говорю о том случае, когда что-то поменяется.
*учитывается, что каждый отдельный слой — это 1 элемент на сцене.
Вот так выглядит заготовка самого psd:

Откроем Adobe ExtendScript Toolkit и поменяем target:

Если у вас нет такой вкладки, тогда советую обновить photoshop. Я боролся с этим пока не нашел сборку с Adobe Application Manager в комплекте.
Основа основ:
Далее нам необходимо подключить либу для работы с JSON, поскольку стандартный js не хочет работать.
Сама либа немаленькая, поэтому положил отдельно. Все что внутри нужно просто скопировать в документ скрипта, поскольку мы будем делать один документ, чтобы его с легкостью переносить.
jam_lib
Константы необходимые для идентификации типа с которым работаем
Основные переменные в скрипте
Далее говорим Старт, и просим выбрать место сохранения результата в формате JSON (туда же добавятся и текстуры).
Проверка на валидность выбранного пути и запуск скрипта.
Функция main — наша точка входа выполнения.
Функция парса группы листов
Парсинг самого листа.
Сам парсинг сохранения текстуры выглядит так:
И 2 фун. для отображения слоев.
После нажимаем F5 в редакторе, указываем путь и ждем надписи «Готово», также можно видеть как скрипт что-то делает на экране(постоянно все меняется).
Результат можно наблюдать в каталоге, который указали при старте:

Сам JSON файл:
Далее собираем обычный атлас текстур, Я делаю это с помощью TexturePackerGUI (не забываем указывать формат Sparrow / Starling)
и кидаем в собранный на скорую руку движок. Сам результат видно через N секунд компиляции:

Статья получилась немаленькая, поэтому я решил вынести полный код скрипта в исходник(starling мини движок, асеты, скрипт photoshop). Доступно по ссылке:https://www.dropbox.com/s/8jurdz2ze4qzz18/pr.zip
1 Текущая реализация
Худож��ик делает все свои дела в photoshop и отдает их программистам. Программисты, в свою очередь, сами как-то вытягивают текстуры или атласы и с помощью утилы позиционируют каждый отдельный элемент на stage флешки, далее ручкам добавляют все текстовые поля, эффекты, прописывают всем этим элементам координаты, которые получили благодаря утилите. В итоге получается очень долгая и мучительная работа, а если учесть, что это делает еще и программист — это АД.
1.1 Текущие проблемы
Программисту приходится:
- долго и мучительно выгонять все текстуры из проекта
- позиционировать все элементы
- создавать экземпляры классов и задавать им нужные свойства
- подбирать цвет текста, размер
- подбирать эффект, если такой имеется
- по 3 миллиона раз запускаться и проверять
Я уже не говорю о том случае, когда что-то поменяется.
2 Решение
- Скрипт, который из psd выгоняет JSON со всеми настройками и параметрами + текстуры всех элементов на сцене.
- Собираем в атлас
- Движок для клиента (flash), который все это дело собирает в кучу.
2.1 Ограничения
- Небольшая подготовка psd перед экспортом, а именно объединение всех слоев и эффектов объекта. Т.е. если есть кнопка и над ней слой с бликом, то эти слои нужно объединить.
- Все исходники psd должны быть с расширением проекта на flash
- Необходимо растрировать все слои (возможно дальше пофикшу)
2.2 Что нам понадобится
- Adobe Photoshop CC
- Adobe ExtendScript Toolkit CS5
- TexturePackerGUI
- intel ideja + (starling)
- Немного знаний JS && AS
3 Подготовка psd
*учитывается, что каждый отдельный слой — это 1 элемент на сцене.
Вот так выглядит заготовка самого psd:

3.1 Написание скрипта jsx
Откроем Adobe ExtendScript Toolkit и поменяем target:

Если у вас нет такой вкладки, тогда советую обновить photoshop. Я боролся с этим пока не нашел сборку с Adobe Application Manager в комплекте.
3.1.1 Скрипт
Основа основ:
#target photoshop //это нужно для информирования с чем мы работаем app.bringToFront(); //чтобы не открывать уже открытый экземпляр приложения
Далее нам необходимо подключить либу для работы с JSON, поскольку стандартный js не хочет работать.
Сама либа немаленькая, поэтому положил отдельно. Все что внутри нужно просто скопировать в документ скрипта, поскольку мы будем делать один документ, чтобы его с легкостью переносить.
jam_lib
Константы необходимые для идентификации типа с которым работаем
var TYPE_SPRITE = "sprite"; var TYPE_TEXT = "text"; var TYPE_COLLECTION = "collection";
Основные переменные в скрипте
var arts = app.activeDocument.artLayers//все Нормальные слои в документе var sets = app.activeDocument.layerSets;//все группы слоев var respont = new Object();//обж. который будет подвержен сериализации и сохранению var arr = new Array();//обж. всех листов для сохранения var u = 0;//индекс в обж. сохранения var width_document = app.activeDocument.width.value; var heigth_document = app.activeDocument.height.value;
Далее говорим Старт, и просим выбрать место сохранения результата в формате JSON (туда же добавятся и текстуры).
alert("Старт!"); var defaultInFolder = new Folder ("C:\\"); var jsonFilter ="JSON Text Files:*.json,All Files:*.*"; var inFile = defaultInFolder.saveDlg ("Open JSON text file:", jsonFilter);
Проверка на валидность выбранного пути и запуск скрипта.
if(inFile) main();
Функция main — наша точка входа выполнения.
function main() { for(var j=0; j<arts.length; j++) {//Проверяем все обычные листы respont[u] = setLayers(arts[j]); //положить в обж. результата парса листа u+=1; } for(var i = 0;i<sets.length;i++)//проверяем все группы листов { respont[u] = setSets(sets[i]); //положить в обж. результат парса группы u+=1; } for(var i = 0;i<arr.length;i++)//проходим все листы и сохраняем их { visible(false);//прячем все visibleElement(arr[i],true);//делаем видимым один нужный лист saveLayer (arr[i]);//сохраняем документ } visible(true);//делаем видимым все листы jamUtils.writeJsonFile (inFile, respont, 4);//сохраняем в документ наш обж. alert ("Готово!"); }
Функция парса группы листов
function setSets(set) { var res = new Object(); res["type"] = TYPE_COLLECTION; res["name"] = set.name; for(var j=0; j<set.artLayers.length ; j++) { res[j] = setLayers(set.artLayers[j]); //вызываем парс как у обычного листа } return res; }
Парсинг самого листа.
function setLayers(el) { var res= new Object(); var x; var y; x = el.bounds[0].value; y = el.bounds[1].value; res["x"] = x; res["y"] = y; res["alpha"] = Math.round(el.opacity)/100;//альфу к диапазону 0-1 res["name"] = el.name.replace(/\s+/g, '');//удаляем все пробелы с имени try{//нехитрая конструкция проверки на текстовое поле var textItem = el.textItem res["type"] = TYPE_TEXT;//если тут еще не вылетел эксепшен, значит, это текст res["color"] = textItem.color.rgb.hexValue; res["font"] = textItem.font; res["size"] = Math.round(textItem.size.value); res["contents"] = textItem.contents; res["width"] = Math.round(textItem.width.value); res["height"] = Math.round(textItem.height.value); }catch(e) { res["type"] = TYPE_SPRITE; } arr.push(el); return res; }
Сам парсинг сохранения текстуры выглядит так:
function saveLayer(layer) { try{ var textItem = layer.textItem //это текст, то пропускаем его сохранение как текстуры return; }catch(e){ } activeDocument.activeLayer = layer; var o = layer.opacity; //получаем координаты и размеры текстур var xx = (layer.bounds[0].value); var yy = (layer.bounds[1].value); var ww = (layer.bounds[2].value); var hh = (layer.bounds[3].value); var shape = [ [xx, yy], [ww,yy], [ww,hh], [xx,hh] ]; app.activeDocument.selection.select(shape);//выделяем область текстуры app.activeDocument.selection.translate(new UnitValue(-xx,"px"),new UnitValue(-yy,"px"));//сдвигаем ее в 0 0 app.activeDocument.selection.deselect();//уберем выделенную область app.activeDocument.resizeCanvas(new UnitValue(ww-xx, "px"), new UnitValue(hh-yy, "px"), AnchorPosition.TOPLEFT);//изменяем размер документа к размеру текстуры activeDocument.activeLayer.opacity = 100;//альфу текстуре 100 var saveFile= File(inFile.path+"/"+layer.name.replace(/\s+/g, '')+".png"); SavePNG(saveFile);//именно сохранение activeDocument.activeLayer.opacity = o;//возвращаем альфу слоя app.activeDocument.resizeCanvas(new UnitValue(width_document, "px"), new UnitValue(heigth_document, "px"), AnchorPosition.TOPLEFT);//возвращаем размеры слоя app.activeDocument. activeLayer.translate(new UnitValue(xx,"px"),new UnitValue(yy,"px"));//возвращаем позицию слоя } function SavePNG(saveFile){ var pngOpts = new ExportOptionsSaveForWeb; pngOpts.format = SaveDocumentType.PNG pngOpts.PNG8 = false; pngOpts.transparency = true; pngOpts.interlaced = false; pngOpts.quality = 100; activeDocument.exportDocument(new File(saveFile),ExportType.SAVEFORWEB,pngOpts); }
И 2 фун. для отображения слоев.
function visibleElement(sprite,flag) { sprite.visible = flag; } function visible(flag) { for(var i = 0;i<arr.length;i++) { arr[i].visible = flag; } }
3.2 Результат
После нажимаем F5 в редакторе, указываем путь и ждем надписи «Готово», также можно видеть как скрипт что-то делает на экране(постоянно все меняется).
Результат можно наблюдать в каталоге, который указали при старте:

Сам JSON файл:
{ "0": { "x": 205, "y": 53, "alpha": 1, "name": "magic", "type": "text", "color": "0006FC", "font": "Verdana", "size": 30, "contents": "Тут у нас волшебный текст", "width": 417, "height": 180 }, "1": { "x": 458, "y": 281, "alpha": 1, "name": "el5", "type": "sprite" }, ... "6": { "type": "collection", "name": "btn", "0": { "x": 300, "y": 537, "alpha": 1, "name": "btn_art", "type": "sprite" } } }
Далее собираем обычный атлас текстур, Я делаю это с помощью TexturePackerGUI (не забываем указывать формат Sparrow / Starling)
и кидаем в собранный на скорую руку движок. Сам результат видно через N секунд компиляции:

Статья получилась немаленькая, поэтому я решил вынести полный код скрипта в исходник(starling мини движок, асеты, скрипт photoshop). Доступно по ссылке:https://www.dropbox.com/s/8jurdz2ze4qzz18/pr.zip