您的位置:首页 > 产品设计 > UI/UE

UI制作中的九宫格批量输出

2014-05-29 23:07 633 查看
游戏的UI制作中,出于对资源的压缩和重用,会对一些有规则的图片划分九宫格,例如下图



中间部分如果是纯色的话,完全可以挖去,然后在U3D的图集精灵的border中设置对应的top,right,bottom,left,这样既可以节省资源,又可以重用到不同大小的但具有一样颜色的地方。

传统的photoshop可以挖去中间部分,但是项目中的美术大哥觉得还是批量处理比较有效率,所以用Air写了一个批量处理九宫格图片的工具。

在这个工具中,美术需要把九宫格的四个border值填充到名字,顺序为top, right, bottom, left例如



top=20px, right=20px, bottom=20px, left=20px,那么图片的命名为Button#21#22#23#24.png

(Button#top#right#bottom#left.png)

这样多个图片导入工具中,导出来的效果



这样资源和可重用度都得到很好的提升。

工具是用air来做的,核心源码如下

private static var file:File = new File();
private var fileOutput:File = new File();
private static var fileStream:FileStream = new FileStream();
private var loader:Loader = new Loader();
private var bit:Bitmap = new Bitmap();
private var bytes:ByteArray = new ByteArray;
private static const SLICE_LIST_LENGTH:int = 9;
private static const SPLIT_ROW_COUNT:int = 3;
private static const SPLIT_COL_COUNT:int = 3;
private static var _transformMatrix:Matrix;
private static var _splitRow:Vector.<int>;
private static var _splitCol:Vector.<int>;
private static var _rect:Rectangle;
private static var _dstPoint:Point;
private var m_iIndex:int = 0;
private var m_arrFile:Array;
private var fileAns:File;

//mxml OnInit初始化函数
private function init():void
{
_splitRow = new Vector.<int>(SPLIT_ROW_COUNT + 1, true);
_splitCol = new Vector.<int>(SPLIT_COL_COUNT + 1, true);
_rect = new Rectangle();
_dstPoint = new Point();
_transformMatrix = new Matrix();

}
//点击按钮后弹出文件夹选择对话框,目前只支持png文件
private function onImport(e:MouseEvent):void
{
file.addEventListener(FileListEvent.SELECT_MULTIPLE, this.onSelect);
file.browseForOpenMultiple("请选择png文件(可选择多个)", [new FileFilter("png文件","*.png;")]);
}
//选择图片,可以多个以及输出文件夹
//文件的命名规范是 abc#top#right#bottom#left.png
private function onSelect(e:FileListEvent):void
{
m_arrFile = e.files;
fileOutput.addEventListener(Event.SELECT, this.OnDoIt);
fileOutput.browserForDirectory("请
4000
选择输出的文件夹");
}
//串行顺序处理图片
private function OnDoIt(e:Event):void
{
fileAns = e.target as File;
m_iIndex = 0;
DealFile(m_arrFile(m_iIndex));
}
//读取图片,转成二进制
private function DealFile(file:File):void
{
var fileByte:ByteArray = new ByteArray();
var fs:FileStream = new FileStream();
fs.open(file, FileMode.READ);
fs.readBytes(fileByte, 0, fs.bytesAvailable);
fs.close();
var myLoader:Loader = new Loader();
myLoader.unload();
myLoader.loadBytes(fileByte);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, image_completeHandler);
}
//把图片的二进制转成bitmapData
private function image_completeHandler(event:Event):void
{
bit.bitmapData = Bitmap(event.currentTarget.content).bitmapData;
Export();
}
//把图片的中间部分挖空,导出图片
private function Export():void
{
var pngSource:BitmapData = new BitmapData(bit.width,bit.height,true,0);
pngSource.draw(bit.bitmapData);
var sName:String = m_arrFile[m_iIndex].name.replace(".png","");
trace(sName);
var arrName:Array = sName.split("#");
//width = left + right; height = top + bottom;
var ansPng:BitmapData = createScaleBitmapData(pngSource,int(arrName[2])+int(arrName[4]),int(arrName[1])+int(arrName[3]),int(arrName[1]),int(arrName[2]),int(arrName[3]),int(arrName[4]));
//用到PNGEncoder库,把bitmapData转成二进制
var ba:ByteArray = PNGEncoder.encode(ansPng);
//重命名,后面添加_Nine
var ff:File = fileAns.resolvePath(m_arrFile[m_iIndex].name.replace(".png","_Nine.png"));
//写入文件
var fileStream:FileStream = new FileStream();
fileStream.open(ff, FileMode.WRITE);
fileStream.writeBytes(ba);
fileStream.close();
//顺序执行后面的图片
if(++m_iIndex < m_arrFile.length)
{
DealFile(m_arrFile[m_iIndex]);
}
}

private static function createScaleBitmapData(link:BitmapData, width:int, height:int, top:int, right:int, bottom:int, left:int):BitmapData
{
if(width < left + right)
{
width = left + right;
}
if(height < top + bottom)
{
height = top + bottom;
}
var result:BitmapData = new BitmapData(width, height, true, 0);
//获取九宫格9个小块的BitmapData
var gridList:Vector.<BitmapData> = createBitmapDataGridList(link, top, right, bottom, left);
updateSplitData(width, height, top, right, bottom, left);
for(var i:int = 0; i < SPLIT_COL_COUNT; i++)
{
for(var j:int = 0; j < SPLIT_ROW_COUNT; j++)
{
var grid:BitmapData = gridList[i * 3 + j];
if(_splitRow[j + 1] - _splitRow[j]==0 || _splitCol[i + 1] - _splitCol[i] == 0)
{
continue;
}
//把原点平移到对应slice的左上角
_transformMatrix.a = (_splitRow[j + 1] - splitRow[j]) / grid.width;
_transformMatrix.b = 0;
_transformMatrix.c = 0;
_transformMatrix.d = (_splitCol[i + 1] - _splitCol[i]) / grid.height;
_transformMatrix.tx = _splitRow[j];
_transformMatrix.ty = _splitCol[i];
result.draw(grid, _transformMatrix);
}
}
return result;
}
//存储9个小图片的BitmapData
private static function createBitmapDataGridList(link:BitmapData, top:int, right:int, bottom:int, left:int) : Vector.<BitmapData>
{
var source:BitmapData = link;
if((top + bottom) > source.height || (left + right) > source.width)
{
throw new Error("图片九宫格参数设置错误:左右切片宽度之和不能大于图片宽度,上下切片高度之和不能大于图片高度!");
}
var result:Vector.<BitmapData> = new Vector.<BitmapData>(SLICE_LIST_LENGTH, true);
updateSplitData(source.width, source.height, top, right, bottom, left);
for(var i:int = 0; i < SPLIT_COL_COUNT; i++)
{
for(var j:int = 0; j < SPLIT_ROW_COUNT; j++)
{
_rect.x = _splitRow[j];
_rect.y = _splitCol[i];
_rect.width = _splitRow[j+1] - _splitRow[j];
_rect.height = _splitCol[i+1] - _splitCol[i];
if(_rect.width == 0 || _rect.height == 0)
{
continue;
}
var bmpd:BitmapData = new BitmapData(_rect.width, _rect.height, true, 0);
bmpd.copyPixels(source, _rect, _dstPoint);
result[i * 3 + j] = bmpd;
}
}
return result;
}
//划分9个小块的位置线
private static function updateSplitData(width:int, height:int, top:int, right:int, bottom:int, left:int):void
{
_splitRow[0] = 0;
_splitRow[1] = left;
_splitRow[2] = width - right;
_splitRow[3] = width;
_splitCol[0] = 0;
_splitCol[1] = top;
_splitCol[2] = height - bottom;
_splitCol[3] = height;
}


原理是先把九宫格的九个小块的bitmapData记录到一个数组里面,然后根据划分的top,right,bottom,left的大小取出对应的bitmapData拼成新图。

特别地,如果是三宫格,如下图



所有引用这张精灵图的宽度都是原大小228px,固定不变的,不能拉伸水平方向,那么需要把left和right设为width的一半,垂直方向可以拉伸,还是20px。同理如果是垂直方向不能拉伸,固定不变,则top和bottom设为height的一半。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  游戏开发 九宫格 UI