Sprite Sheet Editor 0.5.6有一个很重大的Bug,在保存metadata的时候,我将frame的ow/oh属性保存成了与w/h属性相同的值。

根据Sprite Sheet Editor修剪每帧中的空白区域的原理说明可以知道,对于剪切过空白的帧来说,ow和oh是还原原始帧大小的关键。如果这两个值出错,会导致无法取得动画的正确尺寸。

好在这个是可以回溯的。可以通过比较某个Label包含的所有帧的尺寸,通过ox/oy和w/h计算出每帧的实际尺寸,最大的那一个,就是该Label中的所有帧的统一ow/oh属性值。

使用这个方法,得到的实际值,甚至比原来通过Sprite Sheet Editor进行手工设定的值更小,也就是更加节省内存。

选择什么工具处理?AS3有强悍的E4X,JAVA和BASH也不错。但我正好想学习下Vim脚本,就用它了!

处理思路:

  • metadata中的 <labels>标签中保存所有Label的帧索引;
  • 取得每个Label的帧索引,获取每帧的行号,保存;
  • 针对每个Label进行处理,通过Label中每帧的ox/oy/w/h计算出ow/oh;
  • 记录每个Label中最大的ow/oh;
  • 用最大的ow/oh替换该Label中所有帧的ow/oh;
  • 循环处理所有Label。

错误的XML文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
" 转换Sprite Sheet Editor 0.5.6版生成的错误XML文件
" zrong (zrongzrong@gmail.com) 2011-09-02
" 获取当前目录下的所有xml文件
let xmls = split(glob("*.xml"), "\")
" 执行批量修复工作
for b:xml in xmls
echom 'progress '.b:xml
call RepareWH(b:xml)
endfor
" 修复file参数提供的xml文件
function! RepareWH(file)
exec 'sp '.a:file
normal gg
let labelStart = search('')+1
" 找不到Label,处理所有帧
if labelStart <= 1
echom 'label not found'
let framesLine = GetFrames()
call WriteFrames(range(len(framesLine)), framesLine)
update
close
return
endif
let labelEnd = search('<\/labels>')-1
let labels = []
" 将所有的label名称与对应的帧索引写入一个List
" List中的每一项是一个字典,name是label名称,index帧索引的数组(字符串形式保存)
for i in range(labelStart, labelEnd)
let labelMatch = matchlist(getline(i), '<\(\w\+\)>\([0-9,]\+\)')
call add(labels, {'name':labelMatch[1], 'index':split(labelMatch[2], ',')})
endfor
normal gg
let framesLine = GetFrames()
echom 'find '.len(framesLine).' frames'
" 修复所有的label
for label in labels
echo 'progress label '.label.name
call WriteFrames(label.index, framesLine)
endfor
update
close
endfunction
" 将所有的frame块转换成字典,并存入list
function! GetFrames()
let framesLine = []
while search('','',line('$'))
let frameStart = line(".")+1
let frameEnd = search('<\/frame>')-1
call add(framesLine, ParseFrame(frameStart, frameEnd))
endwhile
return framesLine
endfunction
" 将一帧的信息转换成字典,并返回
function! ParseFrame(start, end)
let aFrame = {}
let reg = '<\(\w\+\)>\([-0-9]\+\)'
for lineIndex in range(a:start, a:end)
let matchFrame = matchlist(getline(lineIndex), reg)
let aFrame[matchFrame[1]] = str2nr(matchFrame[2])
" 写入ow和oh的行号方便后面替换
if matchFrame[1] =~ 'ow'
let aFrame.owl = lineIndex
endif
if matchFrame[1] =~ 'oh'
let aFrame.ohl = lineIndex
endif
endfor
return aFrame
endfunction
" 计算真实尺寸的最大值,将最大值写入这一组帧
function! WriteFrames(frameIndexs, framesLine)
let owMax = 0
let ohMax = 0
for index in a:frameIndexs
"echo '== progress frame '.index
let l:frame = a:framesLine[str2nr(index)]
" 如果修剪尺寸小于原始尺寸,则说明该帧没有问题
if l:frame.w < l:frame.ow && l:frame.h < l:frame.oh
"echom 'this frame '.index.' is not problem'
continue
endif
" 真实的帧大小,是用修剪大小减去偏移值
let trueW = l:frame.w - l:frame.ox
let trueH = l:frame.h - l:frame.oy
" 更新真实帧大小的最大值
if trueW > owMax
let owMax = trueW
endif
if trueH > ohMax
let ohMax = trueH
endif
endfor
if owMax > 0 && ohMax > 0
" 写入帧的真实大小
for index in a:frameIndexs
let l:frame = a:framesLine[str2nr(index)]
let ows = substitute(getline(l:frame.owl), '\d\+', owMax, '')
let ohs = substitute(getline(l:frame.ohl), '\d\+', ohMax, '')
echo '== write frame '.index.' line:'.l:frame.owl.','.l:frame.ohl.' w:'.owMax.' h:'.ohMax
call setline(l:frame.owl, ows)
call setline(l:frame.ohl, ohs)
endfor
endif
endfunction

留言

2011-09-13
次访问