|
发表于 2011-1-2 12:26:11
|
显示全部楼层
突然想起这个老帖。我当时竟然说了问题,却没说答案。
其实这里有一个很关键的地方,为什么我不把所有赋值语句都写在一个函数里,然后用if (当前帧数=x)来分别执行他们,而是做成一个个的函数分别调用呢?
我这部动画总共3290帧。如果所有赋值语句都写在一个函数里,然后用然后用if (当前帧数=x)来分别执行他们,那么结果就会变成这样。
if (udg_curframe==1) then
set udg_Data[3]=0x30000000
set udg_Data[7]=0x30000000
set udg_Data[11]=0x30000000
set udg_Data[15]=0x30000000
set udg_Data[19]=0x30000000
set udg_Data[23]=0x30000000
set udg_Data[27]=0x30000000
……
endif
if(udg_curframe==2) then
……
if(udg_curframe==3) then
……
if(udg_curframe==4) then
……
if(udg_curframe==5) then
……
if(udg_curframe==6) then
……
if(udg_curframe==7) then
……
……
……
……
if(udg_curframe==3288) then
……
if(udg_curframe==3289) then
……
if(udg_curframe==3290) then
……
endif
这样的函数看上去没什么问题,但是实际上,这个函数每次被执行时,当前帧数之前的所有if语句至少必定会被执行一次。
也就是,第一帧时,会运行if(udg_curframe==1) 以及给第一帧赋值的内容,第二帧是会执行if(udg_curframe==1) 和if(udg_curframe==2) ,以及给第二帧赋值的语句。虽然它并不会再执行一次给第一帧赋值的语句,但是至少会判断udg_curframe是否等于1。以下同理,当进行到第三帧时,if(udg_curframe==1) 、if(udg_curframe==2) 、if(udg_curframe==3) 全部会被执行一次,然后才执行给第三帧赋值的语句。
这样,一开头虽然不算什么,但是随着帧数的增加,无意义的if语句会被执行得越来越多。当执行到第3290帧时,会先执行3290次无意义的if比较,然后才开始读取第3290帧的数据。
这样的执行效率消耗对每0.06秒执行一次的触发来说是不可接受的。
所以我不采用不断if比较的方案,而是把每一帧写成一个函数,用数组来调用它们。
简单地说,所需要执行的就是
每一次调用udg_datafunc[udg_curframe]
这样,只要用帧数来做数组下标,就可以立刻找到需要赋值的那个函数。并直接进行赋值,不会需要每次都进行那些麻烦的if判断,效率就高多了。
不过这里存在一个问题是,jass里并不存在所谓的“函数数组”。所以直接以数组形式来调用函数是做不到的。
所以这里就需要用到filterfunc出场了。所谓filterfunc其实本来是用来做过滤器东西,用Filter(),参数里头填你想要做成过滤器的函数,就可以以这个函数为蓝本做成一个过滤器。
而filterfunc本身是个可以成为数组的变量……
于是,一半问题解决了,另一半是,如何调用filterfunc呢?显然,没有直接执行filterfunc的函数。
但是我刚说了,filterfunc是用来做过滤器的,那么它自然会在需要过滤的时候被调用。他其实主要是在枚举集合元素时对元素进行过滤用的。
比如,以下函数就是用来枚举单位,并对它们逐一使用过滤器,如果过滤器返回真,就把这个单位丢到指定的单位组里去。
[jass]
native GroupEnumUnitsOfType takes group whichGroup, string unitname, boolexpr filter returns nothing
native GroupEnumUnitsOfPlayer takes group whichGroup, player whichPlayer, boolexpr filter returns nothing
native GroupEnumUnitsOfTypeCounted takes group whichGroup, string unitname, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsInRect takes group whichGroup, rect r, boolexpr filter returns nothing
native GroupEnumUnitsInRectCounted takes group whichGroup, rect r, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsInRange takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
native GroupEnumUnitsInRangeOfLoc takes group whichGroup, location whichLocation, real radius, boolexpr filter returns nothing
native GroupEnumUnitsInRangeCounted takes group whichGroup, real x, real y, real radius, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsInRangeOfLocCounted takes group whichGroup, location whichLocation, real radius, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsSelected takes group whichGroup, player whichPlayer, boolexpr filter returns nothing
[/jass]
而以下函数则用来枚举玩家,并对它们逐一使用过滤器,如果过滤器返回真,就把这个玩家丢到指定的玩家组里去。
[jass]
native ForceEnumPlayers takes force whichForce, boolexpr filter returns nothing
native ForceEnumPlayersCounted takes force whichForce, boolexpr filter, integer countLimit returns nothing
native ForceEnumAllies takes force whichForce, player whichPlayer, boolexpr filter returns nothing
native ForceEnumEnemies takes force whichForce, player whichPlayer, boolexpr filter returns nothing
[/jass]
也许大家注意到,这些函数的过滤器类型其实都是boolexpr,但是filterfunc其实是继承自boolexpr的,所以用filterfunc是成立的。
所以只要执行一次枚举,并把filterfunc作为参数,这样就可以实现对filterfunc的调用了。
使用filterfunc要注意的两点是:
第一,filterfunc不需要返回类型是布尔型,它可以完全没有返回值,这样只会导致所有的元素全部通不过过滤器,却不会导致filterfunc无法被执行。
第二,很容易被大家忽视的一点是,filterfunc是对每一个枚举元素都执行一次,而非枚举结果的集合。所以如果你枚举所有单位类型为A的单位,过滤器用的是枚举单位属于玩家1。而地图上有3个玩家1的单位A,4个玩家2的单位A,那么实际上filterfunc将被执行7次。而非3次。实际上被装入单位组的单位却只有3个。
于是,只要这样做,我们就可以写出用数组方式来调用函数的语句。
先把所有的函数都变成filterfunc装入filterfunc数组中:
……
set udg_df[26]=Filter(function PD26)
set udg_df[27]=Filter(function PD27)
set udg_df[28]=Filter(function PD28)
set udg_df[29]=Filter(function PD29)
set udg_df[30]=Filter(function PD30)
set udg_df[31]=Filter(function PD31)
set udg_df[32]=Filter(function PD32)
set udg_df[33]=Filter(function PD33)
set udg_df[34]=Filter(function PD34)
set udg_df[35]=Filter(function PD35)
set udg_df[36]=Filter(function PD36)
……
这样调用的时候只要使用数组下标就能调用到与帧数相应的函数。
call GroupEnumUnitsOfPlayer(udg_f,udg_p,udg_df[udg_cf])
call DestroyFilter(udg_df[udg_cf])
只要事先在地图上放一个属于玩家udg_p的单位,那么udg_df[udg_cf]就会被调用一次,两个就是两次,三个就是三次。你也可以用别的枚举函数来实现对udg_df[udg_cf]的调用。
DestroyFilter可以用来销毁过滤器,这不是一定必要的,不过如果你想要减小内存消耗的话可以这样做,每次执行后干掉本帧对应的过滤器。毕竟对我这个动画而言,每次运行地图只会播放一次,所以每一帧执行以后就没有留着的必要,直接销毁了事。
这帖子主要就说两件事,1,如何对分支超多的if结构进行优化,第二个就是filterfunc的用法。 |
|