找回密码
 点一下
楼主: Renee

[Bad Apple]于是这个是非常土而且其实是凑数的二版

[复制链接]
发表于 2010-1-15 11:57:00 | 显示全部楼层
不是函数指针,不过有点接近。是可以这样用的东西。

不过思路大抵是对的,你可以想象下,为什么我不把所有赋值语句都写在一个函数里,然后用if (当前帧数=x)来分别执行他们,这2种法子有什么样的区别。
回复

使用道具 举报

发表于 2010-1-15 12:24:37 | 显示全部楼层
呃……我想是复杂度不一样吧——放在一个函数里的话每一帧都要判断好几千次,执行效率会大打折扣?
回复

使用道具 举报

发表于 2010-1-15 19:00:31 | 显示全部楼层
finger是finger
filter是filter
不要把finger看成filter
也不要把filter看成finger
回复

使用道具 举报

发表于 2010-1-15 19:04:54 | 显示全部楼层
很明显,头目把它们放在不同的函数里只是为了方便一块儿一块儿地预读,显示的时候并没有什么很费劲儿的判断。
回复

使用道具 举报

发表于 2010-1-15 19:56:47 | 显示全部楼层
遭了,刚才刷新的时候不小心点到投票了,取消不掉……头目不要劈我……
回复

使用道具 举报

发表于 2010-1-15 19:57:50 | 显示全部楼层
引用第22楼软妹于2010-01-15 19:00发表的  :
finger是finger
filter是filter
不要把finger看成filter
也不要把filter看成finger
filter好像是布尔表达式?可是和函数有什么关系?
回复

使用道具 举报

发表于 2010-1-16 22:04:16 | 显示全部楼层
引用第20楼麦德三世于2010-01-15 11:57发表的  :
不是函数指针,不过有点接近。是可以这样用的东西。

不过思路大抵是对的,你可以想象下,为什么我不把所有赋值语句都写在一个函数里,然后用if (当前帧数=x)来分别执行他们,这2种法子有什么样的区别。
哦,我想到了,是不是因为函数运行需要时间,容易导致音频视频时间不同步?
回复

使用道具 举报

发表于 2010-2-4 20:13:11 | 显示全部楼层
吐血~~
回复

使用道具 举报

发表于 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的用法。
回复

使用道具 举报

发表于 2011-1-2 12:35:03 | 显示全部楼层
呃...竟然猜对了一些...
果然是If判断次数过多的问题
回复

使用道具 举报

发表于 2011-1-2 12:43:18 | 显示全部楼层
很好很坟。
回复

使用道具 举报

发表于 2011-1-2 13:04:09 | 显示全部楼层
穿越了么?
回复

使用道具 举报

发表于 2011-1-2 13:05:10 | 显示全部楼层
头目前段时间也有挖了一下 翻译贴之Ⅱ
回复

使用道具 举报

发表于 2011-1-2 13:05:11 | 显示全部楼层
不愧是头,挖坟都这么有风采。
回复

使用道具 举报

发表于 2011-1-2 13:11:17 | 显示全部楼层
头目可没禁止过挖坟哦,只禁止那些为了刷帖子数灌水的挖坟。倒是有些区的路人弄得太严了。

只要帖子有价值,何必管原帖啥时候写的。
回复

使用道具 举报

发表于 2011-1-2 13:23:48 | 显示全部楼层
我发现自己最近变严了...基本上就按版规行事不...
不过新人还是有放过一些...
回复

使用道具 举报

发表于 2011-1-2 14:26:35 | 显示全部楼层
小德很不错的~~摸摸头~~
回复

使用道具 举报

发表于 2011-1-2 14:28:49 | 显示全部楼层
可是我很多东西都不懂...
有些人问我 我答不上来...
回复

使用道具 举报

发表于 2011-1-2 15:43:12 | 显示全部楼层
不懂就问。
回复

使用道具 举报

发表于 2011-1-2 16:00:12 | 显示全部楼层
的确有在问
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-11-24 04:59 , Processed in 0.053339 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表