找回密码
 点一下
查看: 2037|回复: 13

在图片对话框项中播放多帧动画的一些研究

[复制链接]
发表于 2016-8-26 21:47:05 | 显示全部楼层 |阅读模式
本帖最后由 yxxiaobin 于 2016-9-1 21:18 编辑

官方的命令按钮带有冷却、自动施法等动画内容,而提供给我们的触发器按钮却不包含这些元素。而且,即使你用带有动画内容的命令按钮做模板来创建按钮,然后衔接其中的元素,仍旧难以控制它们。所以如果想要在自己的图里方便使用动画,就要研究官方按钮动画是如何实现的。
查看官方命令按钮可以看到,按钮动画其实并不是真正的动画文件,而是使用一种特殊的图片,图片上包含若干张小图,形成一个帧序列,依次显示它们,就能产生动画效果。系统允许我们比猫画虎的定义一个这样的图片控件,而且目前触发器提供我们一些控制动画的方式,尽管有些不足,但是目前动画效果已经能很好的实现了。下边我将这段时间对图片控件序列动画的研究结果共享出来。
首先是UI的定义,必须在UI中定义一个序列动画图片出来,完全依赖触发器创建是不行的。序列动画图片的UI定义大致如下:
  1. <Frame type="Image" name="CooldownFinishedImage">
  2. <Texture val="@UI/ButtonCoolDownBurst"/>
  3. <TextureCoords top="0.000000" left="0.000000" bottom="1.000000" right="0.125000"/>
  4. <Animating val="true"/>
  5. <ManagedAnim val="true"/>
  6. <AnimColumns val="8"/>
  7. <AnimCount val="8"/>
  8. <AnimDuration val="250"/>
  9. <LoopingAnim val="false"/>
  10. <RenderPriority val="518"/>
  11. <BlendMode val="Add"/>
  12. </Frame>
复制代码
逐一解释一下:
Texture:图片使用的贴图资源,需要指向我们要显示的动画序列。
TextureCoords:贴图坐标,根据本站dqndqn1的解释:指定第一小格的坐标(所有小格的大小),数值是占总长宽的百分比,这里面所有数据跟图片的Top和Left对齐,比如bottom="1.0"就是小格底边距离图片上边有100%的图片长度,Left="0"就是小格左边距离图片左边有0%的图片宽度。
Animating:指这个图片控件是否是动画格式的。只有动画格式,才能逐一播放帧。如果要做动画,这个值必须为true。
ManagedAnim:托管动画。目前发现,把这个值设为真,当控件被创建时,即自动播放动画,但目前版本下触发器的设置动画时间动作bug了,所以我们无法控制动画播放的时间,不过仍然能通过触发器更改从化持续时间。如果使用触发器强行指定动画帧,会导致自动播放失效,且目前版本下无法恢复。
AnimColumns:动画列。指示用的贴图资源一共有几列图片单元。
AnimCount:帧总数。一共有多少帧。这里并没有指定动画有几行,然后利用行列求总数,而是直接指定了总数。可能是考虑到某些时候帧数并不能恰好充满行列。
AnimDuration:动画持续时间,即动画需要多久播放完成一遍,单位是毫秒,比如定义2000,则代表2秒。如果是冷却动画,则这个数值应当等于冷却时间。但是考虑到不同情况下冷却时间并不固定,所以只有自动施法等恒速动画需要在UI里设置这个值。
LoopingAnim:循环播放动画。当动画播放完成时,自动播放下一遍,前提是动画在自动播放的话。将托管动画和循环播放动画全部设为真,则动画会循环自动播放。

基本上和动画播放有关的就这些了,如果有疏漏,请大家补充。

然后看触发器动作部分,可能和图片动画有关的有下列几条:
设置对话框控件动画持续时间:设置动画持续时间,能覆盖UI中AnimDuration字段指定的时间,但是这里单位是秒,而不是毫秒,一定不要弄错。
设置对话框控件动画时间:有两条这种动作,其中一条适用于图片。可以设置动画播放到哪里,即提供进度定位。但是需要注意的是:UI中必须指定动画托管为真,而循环播放动画为假,这一动作才起效。而且当前版本有bug,只有第一次使用时有效,以后再次调用将失效,所以总体上说,这动作目前不可用。
设置对话框控件动画索引:可以指定显示哪一帧,帧的编号从1开始。本来只在需要精确控制动画播放时才有用,但是由于设置动画时间动作bug掉了,所以可控的动画一般是依赖这一动作实现的。可以定义一个循环,根据计算结果依次展示各帧,就能形成动画了。需要特殊说明的是,本动作有个小bug,最后一帧无法正常显示,所以你需要多定义一帧,比如冷却动画实际有128帧,但是定义时你要把AnimCount的值设置为129,这时使用设置动画索引动作时,第128帧才能正确显示出来。

目前自动施法动画因为不需要严格从头开始播放,所以只要按照上边我给的示例代码那么写,就会反复自动播放了。不过其他动画则不行,因为目前设置动画时间的动作失效,且没找到哪条动作会开始一个自动播放。如果从控件创建时就自动播放,很显然当我们要显示动画时,动画不可能就刚好播放到第一帧,而用于调整动画进度的动作失效,导致我们无法中断一个循环,从头开始播放一个动画。当然,设置动画索引是有效的,可以把动画设定到第一帧上。但是一旦使用这一动作,自动播放就停止了......然后又回到最初的问题:没有找到那个动作能开始一个自动播放。目前针对这一情况,我设计的解决方案是使用带有等待的循环,在循环中计算出当前应当播放哪一帧,然后使用设置动画索引动作显示该帧。只要设置合理,倒是也能做出动画效果,但是很显然,这比起自动播放来要费事一些,而且因为很难和游戏周期恰好合拍,所以动画播放出来似乎并不是很流畅(主要是冷却完成时的闪光动画)。
发表于 2016-8-29 03:12:35 | 显示全部楼层
其实你的所有问题的答案都是同一个。

“图片序列动画”与“控件动画事件”并不是同一个东西。


后者你可以搜索UI编辑器里的StateGroup来查看例子。

点评

我猜也是两个东西,不过以前有人提到过可能与此有关,我就顺便写上了。 其实目前真正的问题在于:针对图片控件的“设置对话框控件动画时间”动作并不能起效。如果能让这一动作起效,图片序列动画就能完美实现了。  详情 回复 发表于 2016-8-29 09:47
回复

使用道具 举报

 楼主| 发表于 2016-8-29 09:47:12 | 显示全部楼层
本帖最后由 yxxiaobin 于 2016-8-29 09:49 编辑
麦德三世 发表于 2016-8-29 03:12
其实你的所有问题的答案都是同一个。

“图片序列动画”与“控件动画事件”并不是同一个东西。


我猜也是两个东西,不过以前有人提到过可能与此有关,我就顺便写上了。
其实目前真正的问题在于:针对图片控件的“设置对话框控件动画时间”动作并不能起效。如果能让这一动作起效,图片序列动画就能完美实现了。
附上测试图。
  1. <Frame type="Image" name="CooldownImage2">
  2. <Texture val="@UI/ButtonCooldown"/>
  3. <TextureCoords top="0" left="0" bottom="0.125" right="0.0625"/>
  4. <Animating val="true"/>
  5. <ManagedAnim val="true"/>
  6. <AnimColumns val="16"/>
  7. <AnimCount val="128"/>
  8. </Frame>
复制代码


1.png

1.SC2Map (17.7 KB, 下载次数: 12)

正常情况下,冷却时间应该在1秒时被重置为0.25秒,但实际上并没有。


点评

稍微做了些测试,发现这整个系列函数,动画时间,持续时间啥的都是操纵这两个系列的接口函数, 其中X替换为数据类型,有bool, int, fixed, text, color, string, control, unit, unitgroup,或许还有更多我就没多  详情 回复 发表于 2016-8-31 22:08
回复

使用道具 举报

发表于 2016-8-31 22:08:47 | 显示全部楼层
本帖最后由 dqndqn1 于 2016-8-31 22:11 编辑
yxxiaobin 发表于 2016-8-29 09:47
我猜也是两个东西,不过以前有人提到过可能与此有关,我就顺便写上了。
其实目前真正的问题在于:针对 ...

稍微做了些测试,发现这整个系列函数,动画时间,持续时间啥的都是操纵这两个系列的接口函数,
  1. DialogControlSetPropertyAs##X (int lp_dialogItem, int c_triggerControlProperty, playergroup lp_players, X var);
  2. X DialogControlGetPropertyAs##X (int lp_dialogItem, int c_triggerControlProperty, int lp_player);
复制代码


其中X替换为数据类型,有bool, int, fixed, text, color, string, control, unit, unitgroup,或许还有更多我就没多找了,
  1. DialogControlSetPropertyAsFixed (int lp_dialogItem, int c_triggerControlProperty, playergroup lp_players, fixed var);
  2. int DialogControlGetPropertyAsInt (int lp_dialogItem, int c_triggerControlProperty, int lp_player);
复制代码



参数中第一个是对话框项的编号,直接用对话框项变量传递就行,
第二个应该是一个枚举,其中值0~77都有,这个的意义就是操纵的是哪条属性,比如动画持续时间是61,动画时间是62,动画帧是68(其中59,69好像没定义,都是bool,操作图片没反应)
第三个是玩家组或玩家编号,这个就不说了
第四个就是要设置的变量值了,注意类型应该保持一致,不过我没全测过

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

然后简单的测试了一下,跟你的结果一致,就是动画帧一Set就不动了,在ManagedAnim="true"下动画时间不起作用。这里发现了个问题在刚开始没给动画时间赋值的时候,我Get动画时间的值是会报错的,也就是说这个值只存在于触发器下,并没有写入到属性里,Set动画时间应该是操作另外的属性来完成的,至于Set动画帧就停下来了我估计是这样的:
整个Manage在初始化的时候注册整个有ManagedAnim="true"标旗的图片,然后也是周期设置图片的位置,播放出动画,这时候Set动画时间,其中操作的属性估计跟Manage重叠了,所以我们的操作被Manage复写掉了,然后Set动画帧
这个动作应该是跟Manage操作的方式不一样,他要设置必须要将目标图片从Manage中卸载掉,才能正确的设置属性,所以就停下来了

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


如果这过程真的跟我想的一样的话,那动画只有自己写一个Manage去管理了,或者说找到重新加入Manage队列的接口函数



点评

经过测试找到了设置动画时间的正确用法。 该动作必须在动画托管为真,且循环播放动画为假时才有用。一般情况下可以用于冷却完成动画。如果冷却动画不需要精确控制,也可以使用这一技术,但是如果想要精确控制,还是  详情 回复 发表于 2016-9-1 20:45
回复

使用道具 举报

发表于 2016-9-1 00:39:47 | 显示全部楼层
  1. <TextureCoords top="0.000000" left="0.000000" bottom="1.000000" right="0.125000"/>
复制代码

顺便一提,这个是指定第一小格的坐标(所有小格的大小),数值是占总长宽的百分比,这里面所有数据跟图片的Top和Left对齐,比如bottom="1.0"就是小格底边距离图片上边有100%的图片长度,Left="0"就是小格左边距离图片左边有0%的图片宽度。

点评

好详细的测试,拜服。 关于get错误的解释:在创建对话框项时,他的属性虽然被模板决定,但是并没有把这些值传递到触发层面,所以get会得到一个空值,早期版本还会直接报错。一般需要手动set覆盖一下才能正确使用get  详情 回复 发表于 2016-9-1 13:06
回复

使用道具 举报

 楼主| 发表于 2016-9-1 13:06:42 | 显示全部楼层
dqndqn1 发表于 2016-9-1 00:39
顺便一提,这个是指定第一小格的坐标(所有小格的大小),数值是占总长宽的百分比,这里面所有数据跟图片 ...

好详细的测试,拜服。
关于get错误的解释:在创建对话框项时,他的属性虽然被模板决定,但是并没有把这些值传递到触发层面,所以get会得到一个空值,早期版本还会直接报错。一般需要手动set覆盖一下才能正确使用get语句,其中最常见的就是可见性了,如果使用模板有时候还涉及到尺寸。
另外感谢对TextureCoords的解释,我会把它更新上去。
回复

使用道具 举报

发表于 2016-9-1 14:09:38 | 显示全部楼层
这是因为UI控件是在脚本以外执行的,脚本操作的时候需要Hook现有(触发创建就是直接生成)UI时会生成一个脚本可以操作的对象,但是似乎并没有获取UI层的数据。只有当你对其进行赋值时,它会将值写入脚本的对象,再写入UI,所以结果就是这样了。
这也是有一定原因的。因为UI本身是异步的,除非在运行地图时就开始同步全部数据,否则生成脚本操作对象时获得的数据是对不同玩家不同的,大约是这个原因导致暴雪这样进行处理
回复

使用道具 举报

 楼主| 发表于 2016-9-1 20:45:48 | 显示全部楼层
本帖最后由 yxxiaobin 于 2016-9-1 21:19 编辑
dqndqn1 发表于 2016-8-31 22:08
稍微做了些测试,发现这整个系列函数,动画时间,持续时间啥的都是操纵这两个系列的接口函数,

其中X ...


经过测试找到了设置动画时间的正确用法。
该动作必须在动画托管为真,且循环播放动画为假时才有用。一般情况下可以用于冷却完成动画。如果冷却动画不需要精确控制,也可以使用这一技术,但是如果想要精确控制,还是需要使用设置动画帧动作。
-----------------------------------------------
还是有bug,只在第一次使用时有效,再次使用就不行了.....
回复

使用道具 举报

发表于 2016-9-2 10:55:48 | 显示全部楼层
通篇看了这么多,其实序列帧和特效整合到一张图上的单张序列图来实现特效,完全就是图片替换和单张序列锚点偏移就可以解决了,做好序列坐标偏移算法直接用,何必这么麻烦呢

点评

貌似没有比自动帧序列更简单的实现方案了,毕竟其他的东西都不能自动完成,需要完全的代码控制才行。  发表于 2016-9-2 20:12
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-25 20:56 , Processed in 0.150108 second(s), 27 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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