本帖最后由 vegetto 于 2023-1-6 17:04 编辑
前言:在骑砍里大家所接触到的动画大多是骨骼动画,并且是代码程序可控的;还有少量顶点动画,大多数人处理的场合就是大地图的图标以及部分盾牌弓箭类的武器;以及shader等手段产生的类似UV材质变化的动画效果。实际上动画对于游戏是一个比较广义的概念,比如粒子的放大缩小、贴图的rgb变化都可以看作动画,并且部分系统能够用代码进行模拟也可以用模型手段做出。所以我将对大家不经常或缺乏必要技术研究支持的顶点动画和2D序列图动画系统作出独家系统研究体系的分享和讲解。
本贴主要讲下顶点动画。主要是场景物的顶点动画,因为其他武器大地图图标的常规ms不可控并且不是技术盲区可搜索到,所以这些我不讲。
一、顶点动画模型的制作
1.骑砍适用的顶点动画即md3格式的动画模型的来历:
最初来自一款射击游戏鼻祖雷神之锤的续作quake3,基于制作反恐精英cs的半条命1代,steamG胖发家的游戏就是由这个quake1和2代引擎结合编出来的,quake系列123,分别采用的模型格式mdl、md2、md3进化,也就是md3是最古老的真正的3d动画格式,是游戏史上顶点动画向骨骼动画的最后的过渡技术(因为md3其实也算骨骼动画,quake3的人物基本分成upper上半身,lower下半身和head头部,三个部分,每个部分都是纯md3顶点动画,但是有一个cfg文件强行以骨骼模拟的方式在upper与head,lower与upper之间分别构造了一根骨骼,也就是两个单根骨骼动画串了3个顶点动画,所以说这个是骨骼动画过渡的雏形)。
2.md3动画技术在骑砍深度运用的模型动画技术瓶颈:
一般对于有一点模型动画软件使用基础的人来说,顶点动画的制作他们会采用模型动画软件对动画模型逐帧导出obj再导入openbrf在满足各帧模型顶点面数坐标一样时全选右键点击“merge frames as in a vertex ani”合成顶点动画模型,这个是一个繁琐的方法,试问,如果帧数成百上千,你该怎么办,如果模型具有多个分割部分对应多个材质贴图,那你还要每个mesh部分分别合成帧,你的工作量又是成倍,甚至你导出后并不能保证各帧模型顶点面数坐标一样。
3.模型动画技术瓶颈在骑砍如何突破:
所以我手上有一个这种动画高效处理的软件,可以对主流绑定动画的模型格式dae,fbx等等进行一键整体转化md3,哪怕一万帧也是几秒转化的事情,这个软件看大家对此技术学习的需求积不积极再分享。
所以我的制作步骤是,先准备好绑定全体动画的动画模型,最佳模型格式是fbx(最好设置成2014二进制格式,ASCII版本整体转换后容易塌陷)或mdl(这个常见半条命反恐精英这种游戏,因为mdl是md3的儿子,转换会比较完美),如果是max请导出fbx,dae等容易被其他动画格式导出塌陷。然后用我的软件资源直接转换md3格式.
其他建议:如果源动画比较多,最好在max里先等比压缩一下关键帧数量再导出fbx等常规动画模型再转md3. 给个参考数据,单个顶点动画导入brf后的brf文件大小一般是模型面数(单位:万)x关键帧数/5~7 =。。。(单位MB),也就是打比方我的嘉然模拟器一个嘉然顶点动画模型就是接近20万面的模型x26帧数,结果到达80多兆,所以单体玩家使用的顶点动画模型你可以偶尔有个达到100兆的,但是其他ai单位最好限制在20兆以下。至于brf最大能容纳多大一个顶点动画模型,我最大塞过500兆的,但是塞之前的原始md3模型没这么大,因为塞进去后brf大小会是模型大小扩大后的3~6倍,所以一般往brf塞80兆以上的md3原始文件就容易导致brf奔溃跳出了。至于对性能的影响,这个不能抛开数量谈性能,就是哪怕你一个动画模型200兆,只要你只一个场景加载一两个,不会影响流畅,如果电脑比较好,理想情况是运行还流畅着然后很快到了内存溢出的上限c++run error,所以就看吧,你一个场景加载的这种模型总大小有没有超出1个gb,太多容易跳出。
然后是关于碰撞体设置的问题,场景物的顶点动画不会改变碰撞体,也就是场景物定义的是什么碰撞体模型,无论怎么播放动画都不会改变,所以这个碰撞体怎么设置要具体对象具体分析,比如和战团差不多的人如果采用跟随agent换皮控制的方式,可以不设实际的场景物碰撞体为空,如果是一些机械类,可以根据本身的形态简化处理,降低负担,比如坦克,你可以两个柱体重合加个杆子,避免直接按原始高面数生成碰撞体,因为场景物控制运动带来的负担受模型面数的影响,碰撞体的面数影响是远大于显示的模型外形本身的。
4.一些顶点动画模型参考实例:
我的魔兽争霸modhttps://bbs.mountblade.com.cn/thread-2094063-1-1.html和七龙珠modhttps://bbs.mountblade.com.cn/thread-2093251-1-1.html拥有骑砍界绝大部分的高帧顶点动画模型数量,包含各种生物机械装置战车飞行器以及含有顶点动画的特效模型。你在其他mod基本很少能看到这类模型,有也不超过30帧并且动作种类单一。可以参考看看,但是不要随意提取用到其他mod里.然后下面我具体代码示例的魔兽英雄模型是到第一个链接里找所有human_,orc_,nightelf_,undead_,monster_这些前缀的brf,这些一个brf装一个英雄或普通单位动画模型。然后动画特效一般是eft后缀的brf里。
二、相关op(制作mod的骑砍版本最好要高于1.161,也就是你一般骑砍版本高于1.161就会得到很多新的神奇实用操作,基本满足目前特殊题材mod制作的高度和大部分mod的运行,后续版本更新的东西只是为了dlc的小补充,所以如果不用最新版本制作至少也要保证版本大于1.161)
讲op前先介绍相关参数在brf里的体现:打开有顶点动画模型的brf,选中顶点动画模型看右侧面板的数据,和动画帧数有关的有两个格子的数据排列,右处为帧时刻,是下列op的value或frame要填的数据,也就是动画模型的某帧状态的控制参数,而左侧数据代表的关键帧序号,没有任何op需要这个数据,因为关键帧序号就是一个连续从0开始用于关键帧排序的序号,相连关键帧之间可以填间隔不同的帧时间,比如0号关键帧是0时刻,1号关键帧是5时刻,2号关键帧是15时刻,那么动画第1帧代表的模型形态变到第2帧所用的时间是第0帧变第1帧的2倍时间,但一般为了控制方便,宜设置间隔连续均匀。
可能大家没处理过,不了解,一般你导入做好的顶点动画模型后各帧时刻参数会均为0或者散乱不成等差数列,所以以前我这个帖子说了下如何快速让顶点动画的各帧序的帧时刻从0开始成差值为10的等差数列https://bbs.mountblade.com.cn/thread-2050522-1-1.html,假如你学会了顶点动画的制作,这个小细节不掌握也会使你在代码控制前的模型处理环节就卡住思路。
此外注意没有顶点动画的场景物也可以控制帧状态,所以这种特殊的情况可以用来还没有制作动画时随便用一个没有动画的模型先留空写好代码,以及利用顶点动画控制op是可以操作模型在一个帧时刻区间变换时限定总完成时间的特性,构造一个看不见的无动画模型将控制顶点动画来当作一个计时器来使用。但是注意控制顶点动画的场景物可以没有顶点动画但是需要有具体模型,也就是要有点线面,如果你的模型是none空的,顶点动画op强制执行到某帧时刻后你获取的当前帧时刻始终为0。
prop_instance_deform_to_time = 2610 # (prop_instance_deform_to_time, <prop_instance_no>, <value>),
# value参数代表帧时刻,也就是prop_instance_no场景物id的场景物一次性设置到value这个帧时刻
prop_instance_deform_in_range = 2611 # (prop_instance_deform_in_range, <prop_instance_no>, <start_frame>, <end_frame>, <duration-in-1/1000-seconds>),
# 强制场景物id<prop_instance_no>的场景物自起点帧时刻<start_frame>向终点帧时刻<end_frame>匀速变化,在<duration-in-1/1000-seconds>(单位千分之一秒)时间内完成一次动画,然后模型便停留在终点帧时刻<end_frame>的形态上。此外注意这里面控制动画变化区间的时候是可以取值到<end_frame>,不要去类比is between、try for range这些取不到终值的op,因为这个是行为操作而不是判断类操作。
prop_instance_deform_in_cycle_loop = 2612 # (prop_instance_deform_in_cycle_loop, <prop_instance_no>, <start_frame>, <end_frame>, <duration-in-1/1000-seconds>),
# 强制场景物id<prop_instance_no>的场景物自起点帧时刻<start_frame>向终点帧时刻<end_frame>匀速变化,在<duration-in-1/1000-seconds>(单位千分之一秒)时间内完成一次动画,然后重新到<start_frame>时刻反复循环动画。也就是与上面的op区别是一个不循环动画一个循环动画,这个你们要结合骨骼动画的机理联系想想。
prop_instance_get_current_deform_progress = 2615 # (prop_instance_get_current_deform_progress, <destination>, <prop_instance_no>),
# 获取<prop_instance_no>场景物正在用2611或2612操作播放顶点动画时,已经播放的百分比0-100取值<destination>,实际上,这个用的不多,下面的op具有等效替代作用。
prop_instance_get_current_deform_frame = 2616 # (prop_instance_get_current_deform_frame, <destination>, <prop_instance_no>),
#获取<prop_instance_no>场景物操作播放顶点动画时,当前时点播放到的帧时刻<destination>。
该系列op功能的总体分析(为了写方便,下面以op的序号简称):
1.实际上操作号2611,2612和2616已经可以满足顶点动画控制的需求,操作号2610和2615用的场合不多并且可以被其他3个op等效操作。
2.<duration-in-1/1000-seconds>的填写与<end_frame>-<start_frame>的差值的关系有一点关系但不多,具体填多少还要看你关键帧动画变化的幅度结合实际行为,比如说同样是两个顶点动画人物的走路动画,一个步伐夸张一个步伐缓慢甚至有切变多动作,或者一个模型走路动画每10帧数动作变化幅度较明显,但另一个模型的走路动画每10帧甚至不仔细看都没怎么动作幅度,所以这两个模型一个特定动画区间的长度相等时,满足我们观感适宜的<duration-in-1/1000-seconds>值很多时候不一定相等。这个要在brf里手动播放帧数记录各行为关键帧起始终止帧时刻时看感觉心中有个估值设置好后到游戏调整。然后如果涉及到动作有被加减速动画速度的条件,比如施法加速技能,那这些<duration-in-1/1000-seconds>值还要进一步变量化控制。
3.2611和2612代表了顶点动画的不循环和循环,这个要类比骨骼动画smd特别是其标签作用,骨骼动画按照一些标签应付不同场合的需求,需要动作可以循环执行或仅执行一次,然后我们再类比下,骨骼动画强制切换动作是怎么做的,其实采用的是具有高优先级标签的动作去覆盖当前正在执行的动作,优先级高,则直接打断,优先级次一点,可能等当前动作做完续上或不打断。
所以对于同一个物体的顶点动画中两个不同区间的帧动画进行切换时,操作号2611或2612需要和2616来组合使用,比如某物体假设是一个怪兽,顶点动画总共0-400的帧时间,通过我自己的人为设定,停止发呆动作的帧时刻区间是0-100,走路是101-200(看到没有,因为动画控制可以取终值,所以这个相邻两个区间前一个终值100不可以等于后一个起始值101),攻击是201-300,死亡是301-400。所以这个也表明了大部分情况,你需要把一个顶点动画所有行为压到一个顶点动画模型里,然后记个笔记人为分分类,哪个区间是作什么行为作用的动画来使用。
这时候你们要联系实际生活和玩过的游戏来想怎么把这不同行为的动画区间控制好,首先动画是抽象行为的具体表象,所以先让总体行为指导动画的触发,比如我看到你腿在动的动画,那当前你就是在走路。则通过行为判断的条件,比如走路(先不区分前后左右跑步还是慢跑,假设上面的怪兽只有一种前进动作,其他靠转弯),那么,(key_is_down, key_W)即按着w键便是一种判断当前是否要执行走路动画的条件。然后就是停止待命动画,一般在动画领域这个动作叫idle动作,是很多动作首先要做的动画,因为你无论是走路还是攻击释放技能,最终执行完这些行为后,都要恢复idle站着等待执行其他行为或就像一些任务型人物就呆在一个地方不动,这也说明了idle是优先级最低的动作,也是几乎所有动作的中转动作行为,所以我们进行顶点动画多区间行为化的模型进行多种动画行为控制时,要先分析不同动画区间代表的不同行为优先级的排序。类似动作A在执行时动作B不执行,动作A执行完毕时如果不继续触发动作A的条件则自动切换到动作C,等等。
所以代码控制顶点动画的基本思路就是:
满足动画A(帧时刻范围在(b,c))的条件触发时,op操作号2616得到当前帧数a
如果a在(b,c)值域内,也就是你目前就是在执行A动作动画过程中,出现行为条件的改变,则判断你实际需要触发的事件本应该执行什么动作来决定如何执行2611或2612 op操作号,具体循环与否看你的事件触发条件是否是持续的还是一次性事件,比如走路和待机就是持续性事件采用2612循环动作,而非持续施法的技能和攻击行为以及死亡便是非循环单次事件要用2611,其他特殊情况特殊分析。
然后如果突然又出现了动画B(帧时刻范围在(d,e))的条件触发时,直接按照相同的套路强制执行2611或2612 操作号,打断当前执行的其他动作,或者等目前执行的单次行为动作事件执行完毕即播放到目前行为动画的尾帧时刻再执行新的动画播放。
综述就是:同一个顶点动画模型的不同帧时刻区间定义的不同动作的切换,就是靠op操作号2616得到当前帧数作为判断条件是否处于某个行为事件,再根据你实际需要触发的其他行为条件需要强制执行2611或2612 操作号去转接播放其他帧时刻区间的顶点动画,然后比较优先级,是直接打断当前动画执行还是等原来的执行完。
三、接下来我把我魔兽争霸的顶点动画人物控制代码写下,作为案例注释助大家理解下。
首先做顶点动画模型,此处制作过程省略,然后新建一个excel表做笔记
表格设置的一些解释:看我如下表格,我将我的魔兽人物目前简单定义了几个行为动作与动画的对应,停止待命idle,跑步run,前两个的特殊special状态(比如人族步兵举盾还是不举盾),atk1-double即三种攻击动作(因为玩过网易游戏的会了解,像这种moba人物不像格斗动作游戏一样,很多会采用有限普通攻击动作,具有代表性的是三段击,也就是三个动作循环,攻击力一个比一个高),skill1-4是四个技能动作,因为我大部分英雄是qwer的技能设置,laugh是嘲讽动作娱乐性作用,die是死亡动作,后面带Summoning是含有技能召唤物的比如血法师的凤凰,一般英雄没有,就会像我开头备注的文字if none anim ,control frame 89999-99999,and force it to idle一样,无效动作帧数设置89999-99999方便集中判断无效动作以idle动作代替。
然后为什么要做这样的表格呢,因为起初我做龙珠mod的时候,我采用的是每个人物都写一遍结构很相似的触发器,只不过执行动画帧区间时填的帧时刻参数不一样而已。对于很多会动的生物来说其实大家行为都差不多,人蛇昆虫鸟,都会有idle(待命)-walk/run(走/跑)-attack(攻击)-underattack(被打)-die(死)这些共同的基础动作,然后其他特有动作另写,一般优先级高于基础动作,除了死亡,死亡是优先级最高的动作,因为死了啥事都做不了。比如你释放技能时,根据你玩游戏的经验看,很多技能动作会强制打断待命走路攻击有时不执行结束技能动作还不能进行其他动作(这个一般指的即时释放的技能,持续释放的技能略有差别)
所以说对于不同的顶点动画生物控制,他们各种行为对应的动画帧区间的起点终点值抽象成一个参数、控制量、变量即可保证大部分生物都能通用一套触发器控制,然后初始化比如spawn刷出时进行赋值,把类似动画序列表的数据一次性赋值给这个场景物的sceneprop slot来储存。然后控制动画时读取这些动画帧时刻参数即可。
表格 (scene_prop_set_slot, reg0, 101, 60), 这个数据的生成我采用了“=CONCATENATE(D66,F66)”这个excel函数,目的是为了把D66格子的(scene_prop_set_slot, reg0, 101和F66格子的, 60),这两个格子的数据合并,为什么要这么写呢,是因为我要让101这个数据可以被excel向下拉的时候自动填充并+1,因为我这么多动作需要使用大量的slot存值,如果一个个手写,手都要断了,所以合理利用excel自动填充的特性来处理这种需要大量初始赋值参数的场合便极为方便高效。
魔兽人物仅仅设定了十几个通用动作的参数,龙珠是它的好几倍动作数量,比较复杂,所以下面仅仅以我魔兽争霸mod的动作设定来作为参考例:
表格如下:
---------------------------------------------------------------------------------------------------------------
if none anim ,control frame 89999-99999,and force it to idle | | | | | | | | | | but if atk only one anim,other atk frame set the same | | | | | | | | | | | | | grovekeeper-树林守护者war3 | | grovekeeper-树林守护者dota老鹿 | | none-原始模板备份 | | | 以下写了英文的是动作行为名称,每个动作存动画区间的起始和尾帧时刻参数,如idle待机动作的101slot代表起始帧时刻,102代表尾帧时刻 | 动作分布 | | 1 | | 2 | | 3 | 1 | 2 | | | | | | | | | | | | | | | | | | | | | idle | (scene_prop_set_slot, reg0, 101
| | , 60), | | , 60), | | , 0), | (scene_prop_set_slot, reg0, 101
, 60), | (scene_prop_set_slot, reg0, 101
, 60), | | (scene_prop_set_slot, reg0, 102
| | , 390), | | , 390), | | , 0), | (scene_prop_set_slot, reg0, 102
, 390), | (scene_prop_set_slot, reg0, 102
, 390), | idle—special | (scene_prop_set_slot, reg0, 103
| | , 89999), | | , 89999), | | , 89999), | (scene_prop_set_slot, reg0, 103
, 89999), | (scene_prop_set_slot, reg0, 103
, 89999), | | (scene_prop_set_slot, reg0, 104
| | , 99999), | | , 99999), | | , 99999), | (scene_prop_set_slot, reg0, 104
, 99999), | (scene_prop_set_slot, reg0, 104
, 99999), | run | (scene_prop_set_slot, reg0, 105
| | , 660), | | , 660), | | , 0), | (scene_prop_set_slot, reg0, 105
, 660), | (scene_prop_set_slot, reg0, 105
, 660), | | (scene_prop_set_slot, reg0, 106
| | , 760), | | , 760), | | , 0), | (scene_prop_set_slot, reg0, 106
, 760), | (scene_prop_set_slot, reg0, 106
, 760), | run—special | (scene_prop_set_slot, reg0, 107
| | , 89999), | | , 89999), | | , 89999), | (scene_prop_set_slot, reg0, 107
, 89999), | (scene_prop_set_slot, reg0, 107
, 89999), | | (scene_prop_set_slot, reg0, 108
| | , 99999), | | , 99999), | | , 99999), | (scene_prop_set_slot, reg0, 108
, 99999), | (scene_prop_set_slot, reg0, 108
, 99999), | atk1 | (scene_prop_set_slot, reg0, 109
| | , 1340), | | , 1340), | | , 0), | (scene_prop_set_slot, reg0, 109
, 1340), | (scene_prop_set_slot, reg0, 109
, 1340), | | (scene_prop_set_slot, reg0, 110
| | , 1590), | | , 1590), | | , 0), | (scene_prop_set_slot, reg0, 110
, 1590), | (scene_prop_set_slot, reg0, 110
, 1590), | atk2 | (scene_prop_set_slot, reg0, 111
| | , 1340), | | , 1340), | | , 0), | (scene_prop_set_slot, reg0, 111
, 1340), | (scene_prop_set_slot, reg0, 111
, 1340), | | (scene_prop_set_slot, reg0, 112
| | , 1590), | | , 1590), | | , 0), | (scene_prop_set_slot, reg0, 112
, 1590), | (scene_prop_set_slot, reg0, 112
, 1590), | atk double | (scene_prop_set_slot, reg0, 113
| | , 1340), | | , 1340), | | , 0), | (scene_prop_set_slot, reg0, 113
, 1340), | (scene_prop_set_slot, reg0, 113
, 1340), | | (scene_prop_set_slot, reg0, 114
| | , 1590), | | , 1590), | | , 0), | (scene_prop_set_slot, reg0, 114
, 1590), | (scene_prop_set_slot, reg0, 114
, 1590), | skill1 | (scene_prop_set_slot, reg0, 115
| | , 400), | | , 400), | | , 0), | (scene_prop_set_slot, reg0, 115
, 400), | (scene_prop_set_slot, reg0, 115
, 400), | | (scene_prop_set_slot, reg0, 116
| | , 650), | | , 650), | | , 0), | (scene_prop_set_slot, reg0, 116
, 650), | (scene_prop_set_slot, reg0, 116
, 650), | skill2 | (scene_prop_set_slot, reg0, 117
| | , 2730), | | , 2730), | | , 0), | (scene_prop_set_slot, reg0, 117
, 2730), | (scene_prop_set_slot, reg0, 117
, 2730), | | (scene_prop_set_slot, reg0, 118
| | , 2990), | | , 2990), | | , 0), | (scene_prop_set_slot, reg0, 118
, 2990), | (scene_prop_set_slot, reg0, 118
, 2990), | skill3 | (scene_prop_set_slot, reg0, 119
| | , 2400), | | , 2400), | | , 0), | (scene_prop_set_slot, reg0, 119
, 2400), | (scene_prop_set_slot, reg0, 119
, 2400), | | (scene_prop_set_slot, reg0, 120
| | , 2720), | | , 2720), | | , 0), | (scene_prop_set_slot, reg0, 120
, 2720), | (scene_prop_set_slot, reg0, 120
, 2720), | skill4 | (scene_prop_set_slot, reg0, 121
| | , 2400), | | , 2400), | | , 0), | (scene_prop_set_slot, reg0, 121
, 2400), | (scene_prop_set_slot, reg0, 121
, 2400), | | (scene_prop_set_slot, reg0, 122
| | , 2720), | | , 2720), | | , 0), | (scene_prop_set_slot, reg0, 122
, 2720), | (scene_prop_set_slot, reg0, 122
, 2720), | laugh | (scene_prop_set_slot, reg0, 123
| | , 2400), | | , 2400), | | , 0), | (scene_prop_set_slot, reg0, 123
, 2400), | (scene_prop_set_slot, reg0, 123
, 2400), | | (scene_prop_set_slot, reg0, 124
| | , 2720), | | , 2720), | | , 0), | (scene_prop_set_slot, reg0, 124
, 2720), | (scene_prop_set_slot, reg0, 124
, 2720), | die | (scene_prop_set_slot, reg0, 125
| | , 770), | | , 770), | | , 0), | (scene_prop_set_slot, reg0, 125
, 770), | (scene_prop_set_slot, reg0, 125
, 770), | | (scene_prop_set_slot, reg0, 126
| | , 1330), | | , 1330), | | , 0), | (scene_prop_set_slot, reg0, 126
, 1330), | (scene_prop_set_slot, reg0, 126
, 1330), | Summoning-idle | (scene_prop_set_slot, reg0, 127
| | , 89999), | | , 89999), | | , 89999), | (scene_prop_set_slot, reg0, 127
, 89999), | (scene_prop_set_slot, reg0, 127
, 89999), | | (scene_prop_set_slot, reg0, 128
| | , 99999), | | , 99999), | | , 99999), | (scene_prop_set_slot, reg0, 128
, 99999), | (scene_prop_set_slot, reg0, 128
, 99999), | Summoning-run | (scene_prop_set_slot, reg0, 129
| | , 89999), | | , 89999), | | , 89999), | (scene_prop_set_slot, reg0, 129
, 89999), | (scene_prop_set_slot, reg0, 129
, 89999), | | (scene_prop_set_slot, reg0, 130
| | , 99999), | | , 99999), | | , 99999), | (scene_prop_set_slot, reg0, 130
, 99999), | (scene_prop_set_slot, reg0, 130
, 99999), | Summoning-atk | (scene_prop_set_slot, reg0, 131
| | , 89999), | | , 89999), | | , 89999), | (scene_prop_set_slot, reg0, 131
, 89999), | (scene_prop_set_slot, reg0, 131
, 89999), | | (scene_prop_set_slot, reg0, 132
| | , 99999), | | , 99999), | | , 99999), | (scene_prop_set_slot, reg0, 132
, 99999), | (scene_prop_set_slot, reg0, 132
, 99999), | Summoning-idle | (scene_prop_set_slot, reg0, 133
| | , 89999), | | , 89999), | | , 89999), | (scene_prop_set_slot, reg0, 133
, 89999), | (scene_prop_set_slot, reg0, 133
, 89999), | | (scene_prop_set_slot, reg0, 134
| | , 99999), | | , 99999), | | , 99999), | (scene_prop_set_slot, reg0, 134
, 99999), | (scene_prop_set_slot, reg0, 134
, 99999), | | (scene_prop_set_slot, reg0, 135
| | , 5000), | | , 5000), | | , 5000), | (scene_prop_set_slot, reg0, 135
, 5000), | (scene_prop_set_slot, reg0, 135
, 5000), | | (scene_prop_set_slot, reg0, 136
| | , 3600), | | , 3600), | | , 2400), | (scene_prop_set_slot, reg0, 136
, 3600), | (scene_prop_set_slot, reg0, 136
, 3600), | | (scene_prop_set_slot, reg0, 137
| | , 3600), | | , 3600), | | , 2400), | (scene_prop_set_slot, reg0, 137
, 3600), | (scene_prop_set_slot, reg0, 137
, 3600), | | (scene_prop_set_slot, reg0, 138
| | , 1200), | | , 1200), | | , 1200), | (scene_prop_set_slot, reg0, 138
, 1200), | (scene_prop_set_slot, reg0, 138
, 1200), | | (scene_prop_set_slot, reg0, 139
| | , 1200), | | , 1200), | | , 600), | (scene_prop_set_slot, reg0, 139
, 1200), | (scene_prop_set_slot, reg0, 139
, 1200), | | (scene_prop_set_slot, reg0, 140
| | , 1200), | | , 1200), | | , 800), | (scene_prop_set_slot, reg0, 140
, 1200), | (scene_prop_set_slot, reg0, 140
, 1200), | | (scene_prop_set_slot, reg0, 141
| | , 1200), | | , 1200), | | , 800), | (scene_prop_set_slot, reg0, 141
, 1200), | (scene_prop_set_slot, reg0, 141
, 1200), | | (scene_prop_set_slot, reg0, 142
| | , 2000), | | , 2000), | | , 5000), | (scene_prop_set_slot, reg0, 142
, 2000), | (scene_prop_set_slot, reg0, 142
, 2000), | | (scene_prop_set_slot, reg0, 143
| | , 2000), | | , 2000), | | , 2000), | (scene_prop_set_slot, reg0, 143
, 2000), | (scene_prop_set_slot, reg0, 143
, 2000), | | (scene_prop_set_slot, reg0, 144
| | , 300), | | , 300), | | , 50), | (scene_prop_set_slot, reg0, 144
, 300), | (scene_prop_set_slot, reg0, 144
, 300), | | (scene_prop_set_slot, reg0, 145
| | , 50), | | , 50), | | , 50), | (scene_prop_set_slot, reg0, 145
, 50), | (scene_prop_set_slot, reg0, 145
, 50), | | (scene_prop_set_slot, reg0, 146
| | , 300), | | , 300), | | , 50), | (scene_prop_set_slot, reg0, 146
, 300), | (scene_prop_set_slot, reg0, 146
, 300), | | (scene_prop_set_slot, reg0, 147
| | , 300), | | , 300), | | , 250), | (scene_prop_set_slot, reg0, 147
, 300), | (scene_prop_set_slot, reg0, 147
, 300), |
关于135以后slot含义表格漏了,另外附下:
idle动画基础速度 | | (scene_prop_set_slot, reg0, 135
| run动画基础速度 | | (scene_prop_set_slot, reg0, 136
| atk动画基础速度 | | (scene_prop_set_slot, reg0, 137
| sk1动画基础速度 | | (scene_prop_set_slot, reg0, 138
| sk2动画基础速度 | | (scene_prop_set_slot, reg0, 139
| sk3动画基础速度 | | (scene_prop_set_slot, reg0, 140
| sk4动画基础速度 | | (scene_prop_set_slot, reg0, 141
| laugh动画基础速度 | | (scene_prop_set_slot, reg0, 142
| die动画基础速度 | | (scene_prop_set_slot, reg0, 143
| 效果持续时间1 | | (scene_prop_set_slot, reg0, 144
| 效果持续时间2 | | (scene_prop_set_slot, reg0, 145
| 效果持续时间3 | | (scene_prop_set_slot, reg0, 146
| 效果持续时间4 | | (scene_prop_set_slot, reg0, 147
| ---------------------------------------------------------------------------------------------------------------
上面这些表格的内容在刷出顶点动画人物后把类似(scene_prop_set_slot, reg0, 101, 60),结构的所有竖行都复制过去,进行初始化存数据,然后以下涉及镜头控制、stoprun变量控制的dynamic强制停止位移,aaa变量控制的rts等等参数的变化和控制代码写在其他触发器, 因为有很多配套代码要阉割出来比较麻烦,所以有些东西就下面的主体动画控制触发器里注释简单提及一下,不写出来了,主要提供最主要的动画控制代码的一个触发器(脚本)给大家看个整体思路:
以下添加到module_mission_templates.PY需要的场景里,比如lead charge 野战,或者直接全部脚本化后每个场景触发器都引用一遍:
条件推荐0.00000,0.00000,0.00000
(set_fixed_point_multiplier, 1000),
(store_add, ":var_0", "$heroswitch", 647),
(troop_get_slot, ":var_1", "trp_player", ":var_0"), #以上表示:var_0这个是由$heroswitch决定的我不同的可选魔兽英雄的操作序号,形成了slot序号,由trp_player troop slot 此序号提前在其他触发器存储了英雄的顶点动画场景物的spr id,设为:var_1。
(scene_prop_get_num_instances, ":var_2", ":var_1"),
(eq, ":var_2", 1), #英雄顶点动画模型数量为1时开始执行,在其他触发器里面集中执行了战斗场景应该刷出玩家选择的什么英雄对应的场景物模型
(get_player_agent_no, ":var_3"),
(agent_get_troop_id, ":var_4", ":var_3"),
(agent_get_position, pos15, ":var_3"),
(agent_get_team, ":var_5", ":var_3"),
(store_agent_hit_points, ":var_6", ":var_3", 0),
(scene_prop_get_instance, ":var_7", ":var_1", 0), #代表了玩家换皮顶点动画场景物的魔兽英雄模型,单体实例id设为:var_7
(scene_prop_get_instance, ":var_8", "spr_plpoint", 0), #含有跳动动画的光标模型,表示rts模式的人物选中状态,玩家和ai都有这个东西,在我其他触发器初始化时刷出的,本贴触发器省略不写
(prop_instance_get_position, pos2, ":var_7"), #代码块1-用于获取玩家当前位置到RTS控制需要去的目的地(scripted_destination)的位置水平投影的间距,用于下面判断RTS模式($aaa为1或2时)是采用走路还是待命顶点动画动作的判定
(prop_instance_get_position, pos5, ":var_7"),
(agent_get_scripted_destination, pos6, ":var_3"), #你们可能奇怪为什么玩家也可以用这个op,虽然玩家的移动行为一般情况是靠wasd,但是你set_scripted_destination到一个pos然后用get_scripted_destination是可以获取到这个pos的 #,或者换个说法,假如你按作弊ctrl+f5系统托管玩家控制,玩家就可以响应set_scripted_destination到脚本目的地,所以玩家有scripted_destination的作用,但是一般情况会被wasd等基础系统机制覆盖效果。
(position_set_z, pos5, 0), #为了只获取水平投影的间距,z坐标统一设0
(position_set_z, pos6, 0),
(get_distance_between_positions, ":var_9", pos5, pos6), #代码块1-结束
(agent_get_position, pos1, ":var_3"),
(2616, ":var_10", ":var_7"), #获取英雄顶点动画模型当前运行到的帧时刻,因为我txt做mod,习惯用数字表示这一系列的操作号。
(agent_get_attack_action, ":var_11", ":var_3"),
(agent_get_simple_behavior, ":var_12", ":var_3"),
(store_random_in_range, ":var_13", 0, 1000), #这个随机数很下面的try for agents里的代码会用到,是顶点动画三种不同攻击动作的概率
(try_begin),
(agent_slot_eq, ":var_3", 333, 0), #玩家agent slot333号代表了这个英雄有没有额外的运动控制,如果没有,即slot为0时,常规情况英雄顶点动画模型和头顶表示人物选中的光标模型将始终设置于玩家agent的位置上,因为其他触发器设定了玩家agent影身,所以用顶点动画场景物的形象和动作代表了玩家控制的新形象和动作行为
(prop_instance_set_position, ":var_7", pos15),
(prop_instance_set_position, ":var_8", pos15),
(try_end),
(agent_get_slot, ":var_14", ":var_3", 500), #代码块2-slot503-506代表了技能的持续时间进程控制,slot501代表了移动动画播放速度的变速控制影响量(比如受技能改变加速)在其他触发器默认初始化设为4,slot502代表了攻击动画播放速度的变速控制影响量(比如受技能改变加速)在其他触发器默认初始化设为4,slot500已经废弃,原本是控制攻击力变化的,后来换了算法
(agent_get_slot, ":var_15", ":var_3", 501),
(agent_get_slot, ":var_16", ":var_3", 502),
(agent_get_slot, ":var_17", ":var_3", 503),
(agent_get_slot, ":var_18", ":var_3", 504),
(agent_get_slot, ":var_19", ":var_3", 505),
(agent_get_slot, ":var_20", ":var_3", 506), #代码块2-结束
(scene_prop_get_slot, ":var_21", ":var_7", 101), #代码块3-看我上面附的大表格,是用来获取英雄顶点动画模型包含的各个行为动作的动画起点和终点帧时刻数以及动作持续时间和技能持续时间已经在其他触发器初始化存好到各个prop slot的参数。
(scene_prop_get_slot, ":var_22", ":var_7", 102),
(scene_prop_get_slot, ":var_23", ":var_7", 103),
(scene_prop_get_slot, ":var_24", ":var_7", 104),
(scene_prop_get_slot, ":var_25", ":var_7", 105),
(scene_prop_get_slot, ":var_26", ":var_7", 106),
(scene_prop_get_slot, ":var_27", ":var_7", 107),
(scene_prop_get_slot, ":var_28", ":var_7", 108),
(scene_prop_get_slot, ":var_29", ":var_7", 109),
(scene_prop_get_slot, ":var_30", ":var_7", 110),
(scene_prop_get_slot, ":var_31", ":var_7", 111),
(scene_prop_get_slot, ":var_32", ":var_7", 112),
(scene_prop_get_slot, ":var_33", ":var_7", 113),
(scene_prop_get_slot, ":var_34", ":var_7", 114),
(scene_prop_get_slot, ":var_35", ":var_7", 115),
(scene_prop_get_slot, ":var_36", ":var_7", 116),
(scene_prop_get_slot, ":var_37", ":var_7", 117),
(scene_prop_get_slot, ":var_38", ":var_7", 118),
(scene_prop_get_slot, ":var_39", ":var_7", 119),
(scene_prop_get_slot, ":var_40", ":var_7", 120),
(scene_prop_get_slot, ":var_41", ":var_7", 121),
(scene_prop_get_slot, ":var_42", ":var_7", 122),
(scene_prop_get_slot, ":var_43", ":var_7", 123),
(scene_prop_get_slot, ":var_44", ":var_7", 124),
(scene_prop_get_slot, ":var_45", ":var_7", 125),
(scene_prop_get_slot, ":var_46", ":var_7", 126),
(scene_prop_get_slot, ":var_47", ":var_7", 127),
(scene_prop_get_slot, ":var_48", ":var_7", 128),
(scene_prop_get_slot, ":var_49", ":var_7", 129),
(scene_prop_get_slot, ":var_50", ":var_7", 130),
(scene_prop_get_slot, ":var_51", ":var_7", 131),
(scene_prop_get_slot, ":var_52", ":var_7", 132),
(scene_prop_get_slot, ":var_53", ":var_7", 133),
(scene_prop_get_slot, ":var_54", ":var_7", 134),
(scene_prop_get_slot, ":var_55", ":var_7", 135),
(scene_prop_get_slot, ":var_56", ":var_7", 136),
(scene_prop_get_slot, ":var_57", ":var_7", 137),
(scene_prop_get_slot, ":var_58", ":var_7", 138),
(scene_prop_get_slot, ":var_59", ":var_7", 139),
(scene_prop_get_slot, ":var_60", ":var_7", 140),
(scene_prop_get_slot, ":var_61", ":var_7", 141),
(scene_prop_get_slot, ":var_62", ":var_7", 142),
(scene_prop_get_slot, ":var_63", ":var_7", 143),
(scene_prop_get_slot, ":var_64", ":var_7", 144),
(scene_prop_get_slot, ":var_65", ":var_7", 145),
(scene_prop_get_slot, ":var_66", ":var_7", 146),
(scene_prop_get_slot, ":var_67", ":var_7", 147), #代码块3-结束
(troop_get_slot, ":var_68", "trp_player", 729),
(troop_get_slot, ":var_69", "trp_player", 730),
(troop_get_slot, ":var_70", "trp_player", 731),
(troop_get_slot, ":var_71", "trp_player", 732), #以上trp slot729-732分别代表了不同伤害的定义值,写在其他触发器,了解含义即可,比如729代表普通攻击伤害,后面三个是有关技能的伤害
(try_begin), #代码块4-以下有4个相似的代码块,用来处理503-506agent slot代表的qwer四个英雄技能持续时间进程控制,比如503agentslot值由0变1则开始触发效果,在0到prop144号slot取值之间的区间进行持续+1变化,到峰值归0终止效果。
(eq, ":var_17", 0),
(eq, "$ccd1", 2),
(agent_slot_eq, ":var_3", 307, 0),
(agent_set_slot, ":var_3", 503, 1),
(else_try),
(is_between, ":var_17", 1, ":var_64"),
(val_add, ":var_17", 1),
(try_begin),
(eq, ":var_17", 3),
(str_store_troop_name, s15, ":var_4"),
(str_store_item_name, s16, "itm_wardenskilll"),
(display_message, "str_showskill"),
(try_end),
(agent_set_slot, ":var_3", 503, ":var_17"),
(else_try),
(eq, ":var_17", ":var_64"),
(agent_set_slot, ":var_3", 503, 0),
(str_store_troop_name, s15, ":var_4"),
(str_store_item_name, s16, "itm_wardenskilll"),
(display_message, "str_diskill"),
(try_end),
(try_begin),
(eq, ":var_18", 0),
(eq, "$ccd2", 2),
(agent_slot_eq, ":var_3", 307, 0),
(agent_set_slot, ":var_3", 504, 1),
(else_try),
(is_between, ":var_18", 1, ":var_65"),
(val_add, ":var_18", 1),
(try_begin),
(eq, ":var_18", 3),
(str_store_troop_name, s15, ":var_4"),
(str_store_item_name, s16, "itm_wardenskill2"),
(display_message, "str_showskill"),
(try_end),
(agent_set_slot, ":var_3", 504, ":var_18"),
(else_try),
(eq, ":var_18", ":var_65"),
(agent_set_slot, ":var_3", 504, 0),
(str_store_troop_name, s15, ":var_4"),
(str_store_item_name, s16, "itm_wardenskill2"),
(display_message, "str_diskill"),
(try_end),
(try_begin),
(eq, ":var_19", 0),
(eq, "$ccd3", 2),
(agent_slot_eq, ":var_3", 307, 0),
(agent_set_slot, ":var_3", 505, 1),
(else_try),
(is_between, ":var_19", 1, ":var_66"),
(val_add, ":var_19", 1),
(try_begin),
(eq, ":var_19", 3),
(str_store_troop_name, s15, ":var_4"),
(str_store_item_name, s16, "itm_wardenskill3"),
(display_message, "str_showskill"),
(try_end),
(agent_set_slot, ":var_3", 505, ":var_19"),
(else_try),
(eq, ":var_19", ":var_66"),
(agent_set_slot, ":var_3", 505, 0),
(str_store_troop_name, s15, ":var_4"),
(str_store_item_name, s16, "itm_wardenskill3"),
(display_message, "str_diskill"),
(try_end),
(try_begin),
(eq, ":var_20", 0),
(eq, "$ccd4", 2),
(agent_slot_eq, ":var_3", 307, 0),
(agent_set_slot, ":var_3", 506, 1),
(else_try),
(is_between, ":var_20", 1, ":var_67"),
(val_add, ":var_20", 1),
(try_begin),
(eq, ":var_20", 3),
(str_store_troop_name, s15, ":var_4"),
(str_store_item_name, s16, "itm_wardenskill4"),
(display_message, "str_showskill"),
(try_end),
(agent_set_slot, ":var_3", 506, ":var_20"),
(else_try),
(eq, ":var_20", ":var_67"),
(str_store_troop_name, s15, ":var_4"),
(str_store_item_name, s16, "itm_wardenskill4"),
(display_message, "str_diskill"),
(agent_set_slot, ":var_3", 506, 0),
(try_end), #代码块5-结束
(store_div, ":var_72", 400, ":var_14"), #原先代表攻击力调整,现废除无用
(store_div, ":var_73", ":var_56", ":var_15"), #调整移动动画速度的基础变化,:var_56是propslot136号的基础赋值,":var_15"是agentslot501号的赋值作为速度调节器类似modified类op的效果
(store_div, ":var_74", ":var_57", ":var_16"), #调整攻击动画速度的基础变化,:var_57是propslot137号的基础赋值,":var_16"是agentslot502号的赋值作为速度调节器类似modified类op的效果
(try_begin), #代码块6-控制玩家不进行除待机走路以外的动作时,控制待机走路这两个动作触发的条件和优先级关系
(neg|gt, ":var_10", ":var_30"), # 判断当前是否处于攻击1号动作动画区间内作为条件反向筛选
(ge, ":var_10", ":var_29"),
(else_try),
(neg|gt, ":var_10", ":var_32"), # 判断当前是否处于攻击2号动作动画区间内作为条件反向筛选
(ge, ":var_10", ":var_31"),
(else_try),
(neg|gt, ":var_10", ":var_34"), # 判断当前是否处于攻击3号动作动画区间内作为条件反向筛选
(ge, ":var_10", ":var_33"),
(else_try),
(neg|gt, ":var_10", ":var_36"), # 判断当前是否处于1技能动作动画区间内作为条件反向筛选
(ge, ":var_10", ":var_35"),
(else_try),
(neg|gt, ":var_10", ":var_38"), # 判断当前是否处于2技能动作动画区间内作为条件反向筛选
(ge, ":var_10", ":var_37"),
(else_try),
(neg|gt, ":var_10", ":var_40"), # 判断当前是否处于3技能动作动画区间内作为条件反向筛选
(ge, ":var_10", ":var_39"),
(else_try),
(neg|gt, ":var_10", ":var_42"), # 判断当前是否处于4技能动作动画区间内作为条件反向筛选
(ge, ":var_10", ":var_41"),
(else_try),
(neg|gt, ":var_10", ":var_44"), # 判断当前是否处于嘲讽动作动画区间内作为条件反向筛选
(ge, ":var_10", ":var_43"),
(else_try),
(neg|gt, ":var_10", ":var_46"), #判断当前是否处于死亡动作动画区间内作为条件反向筛选
(ge, ":var_10", ":var_45"),
(else_try), #对如上非待机走路行为动作的条件判断转折后,剩下的条件便是为待机走路这两个动作行为的条件,以此接下来开始对待机走路这两个动作进行更细的区别控制
(try_begin),
(neg|eq, "$aaa", 0), #$aaa是我用来控制RTS鼠标框选点击地面移动机制的判断条件,不为0则是RTS模式,了解即可,本贴暂时不提供魔兽RTS操作代码。
(try_begin),
(ge, ":var_9", 100), #:var_9是我开头写的玩家当前位置与脚本强制命令走动到目的地目标的位置的水平投影间距,因为rts控制移动就不是靠wasd按键条件,所以要判断此刻和下一刻玩家的位移变化值来判断玩家是否想要移动还是静止待命。
(try_begin),
(neg|gt, ":var_10", ":var_26"),
(ge, ":var_10", ":var_25"),
(else_try),
(2612, ":var_7", ":var_25", ":var_26", ":var_73"), #以上表示:var_10就是op2616操作号获取的英雄顶点动画场景物的当前动画帧数,如果当前帧数不在(:var_25,:var_26)这个走动动画的帧时刻区间,则直接op2612操作号强制场景物运行(:var_25,:var_26)区间的循环顶点动画。
(try_end),
(else_try),
(neg|ge, ":var_9", 100),
(try_begin),
(neg|gt, ":var_10", ":var_22"),
(ge, ":var_10", ":var_21"),
(else_try),
(2612, ":var_7", ":var_21", ":var_22", ":var_55"), #以上表示:var_10就是op2616操作号获取的英雄顶点动画场景物的当前动画帧数,如果当前帧数不在(:var_21,:var_22)这个待机动画的帧时刻区间,则直接op2612操作号强制场景物运行(:var_21,:var_22)区间的循环顶点动画。
(try_end),
(try_end),
(else_try),
(eq, "$aaa", 0), #$aaa是我用来控制RTS鼠标框选点击地面移动机制的判断条件,为0则是正常的第三/一人称视角模式
(try_begin),
(this_or_next|key_is_down, key_w), #第三/一人称视角模式,如果图方便借用原本的位移机制换皮,则wasd按键控制便是触发走路动画的条件,但是我根据我的需求,moba英雄没有后退行为,所以屏蔽了s按键,并在下方的$stoprun变量判断此情况玩家不会因为按了s二移动
(this_or_next|key_is_down, key_a),
(key_is_down, key_d),
(neg|key_is_down, key_s),
(try_begin),
(neg|gt, ":var_10", ":var_26"),
(ge, ":var_10", ":var_25"),
(else_try),
(2612, ":var_7", ":var_25", ":var_26", ":var_73"),
(try_end),
(else_try),
(try_begin),
(neg|gt, ":var_10", ":var_22"),
(ge, ":var_10", ":var_21"),
(else_try),
(2612, ":var_7", ":var_21", ":var_22", ":var_55"),
(try_end), #以上和$aaa不等于0时类似,$aaa为0时,按wasd按键条件区分什么时候用走路动画,什么时候用待机动画
(try_end),
(try_end),
(try_end),
(try_begin), #以下到并列的try end 是对技能和嘲讽动作行为控制
(neg|gt, ":var_10", ":var_46"),
(ge, ":var_10", ":var_45"), #以上两行是为了判断死亡动作的情况,进而写下面非死亡动作条件的技能动作事件,为什么不判断上面走路和待机的动作条件,是因为我认定技能动作优先级要比走路待机以及下面的攻击事件要高。
(else_try),
(try_begin),
(key_clicked, key_left_alt), #对嘲讽动作事件的控制,按key_left_alt即左边的alt键将按下面执行动画
(try_begin),
(neg|gt, ":var_10", ":var_44"),
(ge, ":var_10", ":var_43"),
(else_try),
(2611, ":var_7", ":var_43", ":var_44", ":var_62"),
(try_end), #以上表示当前是否当前帧时刻:var_10处于(:var_43,:var_44)这个嘲讽动画的帧时刻区间,不在就执行一遍(:var_43,:var_44)区间的顶点动画(不循环用2611,因为对于这个动作以及下面的技能动作,按键一次只触发一次)
(else_try),
(eq, ":var_10", ":var_44"), #所以为什么我上面要用2611,嘲讽动作判断动作执行完成一次终止回归到待机动作,因为如果是采用2612循环,在到动画时刻:var_44时会很快循环重置到起始帧时刻:var_43,导致(eq, ":var_10", ":var_44"), 常常来不及检测到这个终值。
(2612, ":var_7", ":var_21", ":var_22", ":var_55"), #和上一行条件组合判断执行表示当前是否当前帧时刻:var_10处于:var_44这个嘲讽动画的帧时刻的终点时刻,就执行(:var_21,:var_22)这个待机动画的帧时刻区间进行循环动画,
(try_end),
(try_begin), #代码块7-ccd1是一技能触发的条件,类比上面嘲讽动作触发的定义,因为一些其他触发条件导致ccd1为1开始执行一次一技能动作动画,执行完后回归待机动作动画,ccd1是一个变化的量,本代码不涉及到,在我其他触发器后会根据技能的cd长短从1循环到一定值后归0
(eq, "$ccd1", 1),
(stop_all_sounds, 1),
(play_sound_at_position, "snd_juggw", pos15),
(try_begin),
(neg|gt, ":var_10", ":var_36"),
(ge, ":var_10", ":var_35"),
(else_try),
(2611, ":var_7", ":var_35", ":var_36", ":var_58"),
(try_end),
(else_try),
(eq, ":var_10", ":var_36"),
(2612, ":var_7", ":var_21", ":var_22", ":var_55"),
(try_end), #代码块7-结束
(try_begin),
(eq, "$ccd2", 1),
(stop_all_sounds, 1),
(play_sound_at_position, "snd_juggw", pos15),
(try_begin),
(neg|gt, ":var_10", ":var_38"),
(ge, ":var_10", ":var_37"),
(else_try),
(2611, ":var_7", ":var_37", ":var_38", ":var_59"),
(try_end),
(else_try),
(eq, ":var_10", ":var_38"),
(2612, ":var_7", ":var_21", ":var_22", ":var_55"),
(try_end), #以上表示二技能的动作动画控制,参考我上面的嘲讽动作和一技能动作代码注释的解释理解,其中$ccd2用于控制二技能的触发和cd,其值的变化写在其他触发器上
(try_begin),
(eq, "$ccd3", 1),
(stop_all_sounds, 1),
(play_sound_at_position, "snd_juggw", pos15),
(try_begin),
(neg|gt, ":var_10", ":var_40"),
(ge, ":var_10", ":var_39"),
(else_try),
(2611, ":var_7", ":var_39", ":var_40", ":var_60"),
(try_end),
(else_try),
(eq, ":var_10", ":var_40"),
(2612, ":var_7", ":var_21", ":var_22", ":var_55"),
(try_end), #以上表示三技能的动作动画控制,参考我上面的嘲讽动作和一技能动作代码注释的解释理解,其中$ccd3用于控制三技能的触发和cd,其值的变化写在其他触发器上
(try_begin),
(eq, "$ccd4", 1),
(stop_all_sounds, 1),
(play_sound_at_position, "snd_juggw", pos15),
(try_begin),
(neg|gt, ":var_10", ":var_42"),
(ge, ":var_10", ":var_41"),
(else_try),
(2611, ":var_7", ":var_41", ":var_42", ":var_61"),
(try_end),
(else_try),
(eq, ":var_10", ":var_42"),
(2612, ":var_7", ":var_21", ":var_22", ":var_55"),
(try_end), #以上表示四技能的动作动画控制,参考我上面的嘲讽动作和一技能动作代码注释的解释理解,其中$ccd4用于控制四技能的触发和cd,其值的变化写在其他触发器上
(try_end),
(try_for_agents, ":var_75"), #以下到同级的try end 为对攻击动画和新攻击判断事件的控制
(agent_is_alive, ":var_75"),
(agent_is_human, ":var_75"),
(agent_get_team, ":var_76", ":var_75"),
(neg|eq, ":var_75", ":var_3"),
(neg|eq, ":var_76", ":var_5"),
(neg|eq, ":var_76", 5),
(neg|eq, ":var_76", 6), #以上表示攻击的对象不是玩家自己和自己阵营的人,且不是team编号5、6的人(因为team5,6我有其他中立的作用)
(agent_get_position, pos10, ":var_75"),
(copy_position, pos11, pos2),
(position_move_y, pos11, -10),
(copy_position, pos12, pos2),
(position_move_y, pos12, 10),
(get_distance_between_positions, ":var_77", pos11, pos10),
(get_distance_between_positions, ":var_78", pos12, pos10), #以上表示获取英雄场景物的坐标pos2(开头定义的比较远往上翻翻可以看到)前面10cm的位置和后面10cm的位置分别与循环的潜在攻击对象:var_75agent位置的距离
(try_begin),
(neg|eq, "$aaa", 0),
(neg|ge, ":var_77", ":var_78"), #如果是RTS模式,":var_78"大于":var_77",说明玩家自身前面的坐标位置到攻击对象的位置的距离要大于自身后面的坐标位置到攻击对象的位置的距离,这说明这个条件筛选的是敌人是否处于玩家身后的位置,因为这个是反向筛选条件,我们需要判断攻击的对象应该是玩家面前的人,所以先判断身后的目标else排除一下,其实也可以用in sight 和behind之类的操作op,但是这样判断在执行频率比较高但对判断事物是面向范围但不需要判断是否正对的时候会更省系统负担
(else_try),
(neg|eq, "$aaa", 0),
(ge, ":var_77", ":var_78"),
(neg|is_between, ":var_78", 50, 180), #结合上一个else条件判断,这个是为了筛掉RTS模式下虽然在自身面前但是距离过近和过远的敌人,即在面前距离(50cm,180cm)范围的敌人,进而避免隔空打人或穿模模型重合打人的情况
(else_try),
(eq, "$aaa", 0),
(neg|key_is_down, key_left_mouse_button), #判断非RTS模式玩家没有按鼠标左键,else反向筛掉这个条件就是我希望非RTS模式按鼠标左键时可以触发顶点动画的攻击动画
(else_try),
(neg|eq, "$aaa", 0),
(neg|key_is_down, key_left_control), #判断RTS模式玩家没有按左ctrl键,else反向筛掉这个条件就是我希望RTS模式按左ctrl键时可以触发顶点动画的攻击动画
(else_try),
(try_begin),
(neg|gt, ":var_10", ":var_30"),
(ge, ":var_10", ":var_29"),
(else_try),
(neg|gt, ":var_10", ":var_32"),
(ge, ":var_10", ":var_31"),
(else_try),
(neg|gt, ":var_10", ":var_34"),
(ge, ":var_10", ":var_33"),
(else_try),
(neg|gt, ":var_10", ":var_36"),
(ge, ":var_10", ":var_35"),
(else_try),
(neg|gt, ":var_10", ":var_38"),
(ge, ":var_10", ":var_37"),
(else_try),
(neg|gt, ":var_10", ":var_40"),
(ge, ":var_10", ":var_39"),
(else_try),
(neg|gt, ":var_10", ":var_42"),
(ge, ":var_10", ":var_41"),
(else_try),
(neg|gt, ":var_10", ":var_44"),
(ge, ":var_10", ":var_43"),
(else_try),
(neg|gt, ":var_10", ":var_46"),
(ge, ":var_10", ":var_45"),
(else_try), #上面一堆else看我判断待机走路的代码注释,为了判断当前没有处于死亡攻击技能嘲讽这些动作行为,也就是动作优先级死亡>技能&嘲讽>攻击>待机&走路
(troop_slot_eq, "trp_player", 705, 1), #这个705号trp slot是为了判断我当前有没有使用附身小兵并重新采用战团骨骼动画的判定,主体代码不在本触发器,了解意思即可
(else_try),
(try_begin),
(is_between, ":var_13", 0, 400),
(2611, ":var_7", ":var_29", ":var_30", ":var_74"),
(else_try),
(is_between, ":var_13", 400, 800),
(2611, ":var_7", ":var_31", ":var_32", ":var_74"),
(else_try),
(is_between, ":var_13", 800, 1000),
(2611, ":var_7", ":var_33", ":var_34", ":var_74"),
(try_end), #以上表示一定概率条件下,即把":var_13"随机数在0-1000的取值按4:4:2划分概率区间,分别用来触发三种不同的攻击动作,因为我上面的else屏蔽了攻击动画的条件,所以这个触发攻击动作后一定会等待攻击动作执行完毕一次后才能触发下一次攻击动作,不会因为狂点鼠标而鬼畜从动画中间打断攻击重置。
(try_end),
(try_end),
(this_or_next|eq, ":var_10", ":var_29"),
(this_or_next|eq, ":var_10", ":var_31"),
(eq, ":var_10", ":var_33"),
(ge, ":var_77", ":var_78"),
(is_between, ":var_78", 50, 180), #以上是判断攻击动画执行后是否有有效攻击单位执行攻击有效伤害的条件,也就是在攻击动画帧时刻分别处于3种攻击动画任意一种的起始帧时刻时且面前范围距离自身范围(50cm,180cm)时触发
(try_begin),
(item_slot_eq, "itm_monkeykingbar", 308, 0), #没有装备金箍棒被动时,itemslot308用来判断是否装备此物品并可执行被动技能
(prop_instance_get_position, pos40, ":var_7"),
(position_move_z, pos40, 150),
(position_move_y, pos40, 20),
(position_move_x, pos40, -40),
(add_missile, ":var_3", 40, 64000, 0, 0, "itm_melee", 0),
(position_move_x, pos40, 40),
(add_missile, ":var_3", 40, 64000, 0, 0, "itm_melee", 0),
(position_move_x, pos40, 40),
(add_missile, ":var_3", 40, 64000, 0, 0, "itm_melee", 0), #向面前发射三处无形模型的箭矢,重力比较大,会近处掉落,加上上面判断必须面向有人且(50cm,180cm)距离范围才会触发,所以会近似打击面前的单位,类似近战攻击效果。注意这个一看就知道是平射,如果高低坡的敌人容易打不到,因为我的魔兽争霸mod就是moba题材的机制,所以本来就是这个设定,高坡攻击miss,并且由于箭矢个头小就近射也容易miss,所以加了一些装备来弥补这个自身原始攻击方式的不足,比如金箍棒可以无视一定高坡集中攻击,鹰脚弓可以让近战英雄在第一人称时发射与自己视角协调的箭矢剑气
(else_try),
(agent_deliver_damage_to_agent, ":var_3", ":var_75", ":var_68"), #如果装备了金箍棒物品的被动,则可以对面前一定范围的人造成群体分裂伤害
(try_end),
(try_end),
(try_begin), #代码块8-判断是否装备了鹰脚弓被动,作用是近战英雄攻击时可以发出远程剑气,可选内容,了解即可
(troop_slot_eq, "trp_player", 705, 0),
(item_slot_eq, "itm_eaglehorn", 308, 1), #slot308表示是否有这个装备的被动功能,鹰脚弓eaglehorn,由于暂时缺少蝴蝶模型,所以这个来自dota的装备先扮演蝴蝶的作用然后又自行加了这个特殊被动
(this_or_next|eq, ":var_10", ":var_29"),
(this_or_next|eq, ":var_10", ":var_31"),
(eq, ":var_10", ":var_33"),
(prop_instance_get_position, pos40, ":var_7"),
(position_move_z, pos40, 150),
(position_move_y, pos40, 20),
(copy_position, pos41, pos40),
(try_begin),
(eq, "$aaa", 0),
(eq, "$cam1", 1), #cam1变量是判断是否除以新镜头控制代码的第一三人称镜头控制,为1是第一人称,因为我r键作为四技能使用了,并且顶点动画人物怪物体型和战团人物差别比较大,所以另外重写了第一三人称镜头切换控制
(agent_get_look_position, pos42, ":var_3"),
(position_copy_rotation, pos41, pos42), #以上表示第1人称镜头下下面用于发射箭矢的pos41角度要与玩家视角复制一致,也就是装备eaglehorn可以使得玩家选择近战英雄控制的时候,第一人称发射任意视角方向的远程剑气
(try_end),
(add_missile, ":var_3", 41, 64000, 0, 0, "itm_swift", 0),
(try_end), #代码块8-结束
(try_begin), #代码块9-判断玩家控制的顶点动画英雄是否是远程还是近战英雄,如果是远程英雄,则按左ctrl键可以不受面前近距离是否有敌人的条件释放箭矢missle,代码结构比较像我上面的循环近战攻击代码,可选内容,了解即可。
(agent_slot_eq, ":var_3", 331, 1), #slot331号的agentslot为1代表这个英雄是远程英雄,这个会在其他触发器设定取值
(key_is_down, key_left_control),
(try_begin),
(neg|gt, ":var_10", ":var_30"),
(ge, ":var_10", ":var_29"),
(else_try),
(neg|gt, ":var_10", ":var_32"),
(ge, ":var_10", ":var_31"),
(else_try),
(neg|gt, ":var_10", ":var_34"),
(ge, ":var_10", ":var_33"),
(else_try),
(neg|gt, ":var_10", ":var_36"),
(ge, ":var_10", ":var_35"),
(else_try),
(neg|gt, ":var_10", ":var_38"),
(ge, ":var_10", ":var_37"),
(else_try),
(neg|gt, ":var_10", ":var_40"),
(ge, ":var_10", ":var_39"),
(else_try),
(neg|gt, ":var_10", ":var_42"),
(ge, ":var_10", ":var_41"),
(else_try),
(neg|gt, ":var_10", ":var_44"),
(ge, ":var_10", ":var_43"),
(else_try),
(neg|gt, ":var_10", ":var_46"),
(ge, ":var_10", ":var_45"),
(else_try),
(troop_slot_eq, "trp_player", 705, 1),
(else_try),
(try_begin),
(is_between, ":var_13", 0, 400),
(2611, ":var_7", ":var_29", ":var_30", ":var_74"),
(else_try),
(is_between, ":var_13", 400, 800),
(2611, ":var_7", ":var_31", ":var_32", ":var_74"),
(else_try),
(is_between, ":var_13", 800, 1000),
(2611, ":var_7", ":var_33", ":var_34", ":var_74"),
(try_end),
(try_end),
(this_or_next|eq, ":var_10", ":var_29"),
(this_or_next|eq, ":var_10", ":var_31"),
(eq, ":var_10", ":var_33"),
(prop_instance_get_position, pos40, ":var_7"),
(position_move_z, pos40, 150),
(position_move_y, pos40, 20),
(copy_position, pos41, pos40),
(try_begin),
(eq, "$aaa", 0),
(eq, "$cam1", 1),
(agent_get_look_position, pos42, ":var_3"),
(position_copy_rotation, pos41, pos42),
(try_end),
(agent_get_slot, ":var_79", ":var_3", 332),
(add_missile, ":var_3", 41, 64000, 0, 0, ":var_79", 0),
(try_end), #代码块9-结束
(try_begin), #代码块10-集中判断一些一次性执行的动画动作终止的条件,一般就是像上面嘲讽动作一样,动画播放到尾帧时刻回归执行idle的待机动作
(eq, ":var_10", ":var_33"),
(stop_all_sounds, 1),
(play_sound_at_position, "snd_juggatkdouble", pos15), # 以上表示如果开始播放第三个动作的起始帧,就会发出暴击的音效
(else_try),
(this_or_next|eq, ":var_10", ":var_46"),
(this_or_next|eq, ":var_10", ":var_30"),
(this_or_next|eq, ":var_10", ":var_32"),
(eq, ":var_10", ":var_34"),
(2612, ":var_7", ":var_21", ":var_22", ":var_55"),
(eq, ":var_10", ":var_46"),
(stop_all_sounds, 1),
(play_sound_at_position, "snd_reborn", pos15), # 以上表示如果播放到3种攻击动作或死亡动画的尾帧时刻,则回归执行idle的待机动作,特别的,如果执行到死亡的尾帧时刻,播放重生音效。死亡动作的设定在ti kill这个 trigger的触发器里另外写,不在本触发器里。
(else_try),
(eq, ":var_10", ":var_45"),
(stop_all_sounds, 1),
(play_sound_at_position, "snd_dotadeath", pos15), # 以上表示如果播放到死亡动画的起始帧时刻,播放死亡音效
(try_end), #代码块10-结束
(try_begin),
(neg|gt, ":var_10", ":var_26"),
(ge, ":var_10", ":var_25"),
(assign, "$stoprun", 0),
(else_try),
(assign, "$stoprun", 1),
(try_end), #以上是判断顶点动画处于跑步行为的帧时刻区间时$stoprun设0,其他情况设1,对$stoprun的判断写在了其他触发器里,作用是和其他变量一起组合判断玩家是否要用agent set no dynamic这个op来强制玩家不可以随便移动, 一般$stoprun为1的情况是不可以移动的,比如我释放技能和攻击时会强制玩家no dynamic进而取消了系统控制的位移行为。
(try_begin), #RTS-2镜头状态和第1/3人称时的镜头控制在其他触发器里,RTS-1镜头状态即$aaa为1时因为一些不同英雄的镜头需求写在了这里
(eq, "$aaa", 1),
(agent_get_look_position, pos4, ":var_3"),
(position_copy_rotation, pos2, pos4),
(position_move_y, pos2, "$rog"),
(position_move_z, pos2, 90),
(mission_cam_set_mode, 1),
(mission_cam_set_position, pos2),
(try_end),
(try_begin), # 到上面为止示例基本结束了,以下的代码是对一些特殊补丁添加的新英雄的判断,不多解释,目的为了开局执行一下idle待机动作,因为部分采用引用本脚本动作控制的英雄,需要重新覆盖一个新的propslot动作序列参数,导致重新赋值时动画开在一个循环类的高优先级动作上比如技能动作,所以要开局卡一定cd后给予一个判断重置动作到idle的量
(troop_slot_ge, "trp_player", 736, 1),
(agent_get_slot, ":var_80", ":var_3", 335),
(try_begin),
(is_between, ":var_80", 1, 30),
(val_add, ":var_80", 1),
(agent_set_slot, ":var_3", 335, ":var_80"),
(eq, ":var_80", 20),
(2612, ":var_7", ":var_21", ":var_22", ":var_55"),
(try_end),
(try_begin),
(agent_slot_eq, ":var_3", 335, 0),
(agent_set_slot, ":var_3", 335, 1),
(else_try),
(agent_slot_eq, ":var_3", 335, 30),
(troop_slot_ge, "trp_player", 679, 2),
(agent_set_slot, ":var_3", 335, 0),
(try_end),
(try_end),
|