|
恩,偶尔瞎想一下还是有用的……
上面那句是废话…… -_-|||
好吧,我再多说句,一下这些内容不是给ReturnBug+GameCache很精通的诸位高手看的
它主要说的是在T范围下的延时传递,虽然是把简单弄复杂了些
但是对于初学者,还是这个比一堆J代码容易懂些
我写它的含义是使T能在更广阔的范围内使用
而不是什么都非J不可
要知道,不是人人都懂J的
不需要局域化的触发之间的参数传递本身是并不难的,直接调用相应的全局变量就可以实现,甚至即使是局域化了的触发之间的参数传递,也可以直接使用全局变量,只要两个触发之间没有延时,直接调用,这个传递的过程一般也不会产生变量冲突。比如使用触发器 – 运行 NewTrigger 001 <预设> (无视条件)来执行下一个触发,使用全局变量传递参数就不会有问题。
但是我们经常要在不是立即执行的情况下来传递参数,在这种情况下,如果使用全局变量传递参数明显会有可能产生变量冲突。但是局域变量或者事件响应又是无法直接传递的,那么,这个问题要怎么解决呢?
我们先考虑一下触发之间的延时运行是怎么实现的,时间又是怎么被延长的。恩,仔细的想一下,你会发现延时运行的时间延长,不外乎两种方法:计时延时、事件延时。
计时延时,顾名思义,就是通过计时手段来控制时间,这种延时方法一般都是在知道要延长多少时间的情况下使用。具体的方法有:
[trigger]
动作
等待 2.00 秒(游戏时间)
触发器 – 运行 trigger_XXX (无视条件)
[/trigger]
[trigger]
NewTrigger 001
动作
计时器 – 启动 timer,应用计时方式: 一次性,计时周期为 30.00 秒
事件
时间 – timer 归零
[/trigger]
以上的两种是最常见的两种方法,而且在不考虑延时精确的情况下可以相互替代。不过使用计时器的方法更好些,不仅延时可以精确到0.01秒,还不会出现什么BUG。这也是我们经常使用的方法。
事件延时,就是一直延时到事件发生,这种延时的延时时间是不确定的,所以一般不是用计时器来延时的,或者可以这样说,事件延时就是两个触发,只是一个调用了另一个的结果而已。
根据延时方法的不同,参数的延时传递的方法也不同。相比于计时延时,事件延时并没有一个通用的方法来避免延时参数传递的变量冲突,我们只能根据具体的事件来想办法。所以这个只能凭借个人经验对应实际情况来解决,除了那种可以通过间隔固定时间判断条件成立来代替事件的触发,其他的并没有通用方法。
关于计时延时的参数传递,我还是先说一下在J范围内是如何避免这个问题的。
这个方法是ReturnBug+GameCache。其中Return Bug是一种转换——将一个handle类型的变量变成整数型的变量,说白了就是将变量转换成一个类似地址指针的东西,它的实质我们不需要了解,只要知道它的功能是将我们要转换的内容转换成一串互不相同的整数就行。GameCache,就是游戏缓存,只要我们可以理解GameCache是一个可以存储和读取变量的东西就行。其他的只要会用T存储和读取变量就行(这里就不再细说了)。
ReturnBug+GameCache的其他内容我就不过多说了,GA上随便搜索就可以找到。我要说的是它是怎么来解决参数传递的变量冲突的。
恩,ReturnBug+GameCache在参数传递上实际上应该称作ReturnBug+GameCache+Timer。其中的timer是指计时器。ReturnBug+GameCache的原理比较容理解:就是将我们要传递的内容存储在游戏缓存中,存储的名字或者类别是和一个局域化了的计时器相关的(就是用Return Bug转换出来整数作为名字),然后开启计时器,设置延时时间,并添加计时器到期事件到延时执行的触发。当计时器到期事件响应后,把到期的计时器转换为保存在游戏缓存的参数的名称或类别。最后从缓存中读取这个参数,这样局域话的延时参数传递就完成了。由于每个计时器通过Return Bug转换出来的值都不相同,并且这个值是唯一的,所以这样就可以避免了参数冲突。
如果你仔细思考一下,你就会发现,参数延时传递避免变量冲突的方法的核心就是找到一个可以计时的东西,在它与参数之间建立一个可以相互转换的关系,再通过这个东西的某个时间变化的事件来运行被延时的触发,同时用事件响应来确定每次执行被延时触发对应的这个东西,最后转换出传递的参数。(写起来好绕口)
我最初的选择是用单位来延时与绑定变量:用生命周期来代替计时器延时,用单位的自定义值来传递变量。这种方法是可以实现的,唯一的问题就是很没有效率,占用很多资源,如果同时执行的次数很多,就会卡。具体的例子可以在点击这里看到,我就不做过多解释了。
我本以为这样就是最终的方法了,然而某一天一个突然出现的念头让我想到了一个更好的方法,那就是:UnionBug+GameCache。GameCache还是指游戏缓存,而UnionBug的含义 请看这里。
UnionBug+GameCache的思路与ReturnBug+GameCache是一样的,唯一的区别是在计时器转换成整数的方法上。ReturnBug是使用了这样一个函数H2I:
[jass]
function H2I takes handle h returns integer
return h
return 0
endfunction
[/jass]
而UnionBug是利用同名变量设置时强制转换的BUG实现的,不过转换出的整数都是一样的。
下面就是一个简单的例子:
[trigger]
事件
地图初始化
条件
动作
游戏缓存 - 创建游戏缓存,使用文件名: wh.w3v
Set w3v = (最后创建的游戏缓存)
[/trigger]
[trigger]
NewTrigger 001
事件
玩家 - 玩家1(红色) 按下Esc键(跳过电影)
条件
动作
自定义代码: local integer udg_timer_I=0
自定义代码: local timer udg_timer_T = CreateTimer()
触发器 - 为 NewTrigger 002 <预设> 添加事件: (时间 - timer_T 归零)
游戏缓存 - 记录 ((当前触发) 的触发动作运行次数) ,使用名称: (转换 timer_I 为字符串) 类别名: Category 缓存: w3v
计时器 - 启动 timer_T,应用计时方式: 一次性,计时周期为 1.00 秒
[/trigger]
[trigger]
NewTrigger 002
事件
条件
动作
自定义代码: local integer udg_timer_I=0
自定义代码: local timer udg_timer_T
Set timer_T = (到期的计时器)
游戏 - 对 (所有玩家) 发送文本信息: (转换 (从游戏缓存读取整数,名称: (转换 timer_I 为字符串) 类别: Category 缓存: w3v) 为字符串)
自定义代码: call DestroyTimer( udg_timer_T )
[/trigger]
自定义代码: local timer udg_timer_T = CreateTimer()创建了一个计时器,同时由于UnionBug,使全局变量timer_T的值强制赋给timer_I这样就成功的获得了Return Bug的效果。
这种方法使用自定义语句来声明局域变量和销毁计时器,已经不是纯T了,不过相比于使用H2I好一点,而且只要复制两个声明自定义的动作,以及在确定不使用计时器时使用call DestroyTimer( udg_timer_T )来销毁计时器就可以使用,水平不是很高的WEER使用起来也方便一些。
这种方法还是有一个不重要的缺陷:就是无法再使用同名局域变量,否则也会强制赋值(使用带udg_或者普通的局域变量没有关系,只要没有同名全局变量就行)。
恩,最后是那个近战抵抗护盾的修改版的触发:
[trigger]
MapsInitialzation
事件
地图初始化
条件
动作
游戏缓存 - 创建游戏缓存,使用文件名: w3v.w3v
Set w3v = (最后创建的游戏缓存)
[/trigger]
[trigger]
startreg
事件
时间 - 当游戏逝去 0.00 秒
条件
动作
循环动作[I]从 1 到 12, do (玩家 - 禁用 魔法书 对 (玩家 I))
单位组 - 选取 ((可用地图区域) 内的所有单位) 内所有单位 (触发器 - 为 attacked <预设> 添加事件: (单位 - (选取单位) 接受伤害))
[/trigger]
[trigger]
reg
事件
单位 - 任意单位进入 (可用地图区域)
条件
((进入的单位) 的类型) 不等于 计时马甲
动作
触发器 - 为 attacked <预设> 添加事件: (单位 - (进入的单位) 接受伤害)
[/trigger]
[trigger]
skillonandoff
事件
单位 - 任意单位 发布无目标指令
条件
Or - 任意条件成立
条件
(转换 (发布的命令ID) 为命令字符串) 等于 manashieldon
(转换 (发布的命令ID) 为命令字符串) 等于 manashieldoff
动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 运作)
If - 条件
(转换 (发布的命令ID) 为命令字符串) 等于 manashieldon
Then - 动作
单位 - 添加 魔法书 给 (发布命令的单位)
Else - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 运作)
If - 条件
(转换 (发布的命令ID) 为命令字符串) 等于 manashieldoff
Then - 动作
单位 - 删除 魔法书 从 (发布命令的单位)
单位 - 删除 近战抵抗护盾 从 (发布命令的单位)
Else - 动作
[/trigger]
[trigger]
attacked
事件
条件
动作
自定义代码: local integer udg_Timer_I=0
自定义代码: local timer udg_Timer_T = CreateTimer()
单位 - 设置 (触发单位) 的生命值为 ((生命值 对于 (触发单位)) + 1.00)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 运作)
If - 条件
(单位所受伤害) 等于 1.00
(随机实数,最小值: 0.00 最大值: 100.00) 小于或等于 (20.00 x (转换 (近战抵抗护盾 的等级对 (伤害来源)) 为实数))
Then - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 运作)
If - 条件
((伤害来源) 拥有 近战抵抗护盾 ) 等于 TRUE
Then - 动作
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 运作)
If - 条件
(魔法值 对于 (伤害来源)) 大于或等于 Needmana
Then - 动作
Set UnitA[(((当前触发) 的触发动作运行次数) mod 8000)] = (伤害来源)
Set UnitB[(((当前触发) 的触发动作运行次数) mod 8000)] = (触发单位)
Set Point_A = ((伤害来源) 的位置)
Set Point_B = ((触发单位) 的位置)
Set Point_C = (从 Point_A 开始,距离 50.00 ,方向为 (Point_A 到 Point_B 的角度) 度的位移处)
单位 - 设置 (伤害来源) 的魔法值为 ((魔法值 对于 (伤害来源)) - Needmana)
如果 ((魔法值 对于 (伤害来源)) 小于 Needmana) 成立,则运行 (单位 - 对 (伤害来源) 发布 中立 娜迦海巫 - 关闭魔法盾 命令) 否则运行 (不做任何动作)
游戏缓存 - 记录 (((当前触发) 的触发动作运行次数) mod 8000) ,使用名称: Integer 类别名: (转换 Timer_I 为字符串) 缓存: w3v
游戏缓存 - 记录 (Movelength / Movespeed) ,使用名称: Real 类别名: (转换 Timer_I 为字符串) 缓存: w3v
触发器 - 为 timer <预设> 添加事件: (时间 - Timer_T 归零)
计时器 - 启动 Timer_T,应用计时方式: 一次性,计时周期为 Movetime 秒
单位 - 创建 1 个 特效马甲 给 ((伤害来源) 的所有者) 在 Point_C ,面向角度为 (Point_A 到 Point_B 的角度) 度
单位 - 设置 0.30 秒 普通 类型的生命周期对 (最后创建的单位)
触发器 - 为 dead <预设> 添加事件: (单位 - (最后创建的单位) 死亡)
点 - 清除 Point_A
点 - 清除 Point_B
点 - 清除 Point_C
Else - 动作
单位 - 对 (伤害来源) 发布 中立 娜迦海巫 - 关闭魔法盾 命令
Else - 动作
单位 - 删除 魔法书 从 (伤害来源)
单位 - 删除 近战抵抗护盾 从 (伤害来源)
Else - 动作
自定义代码: call DestroyTimer( udg_timer_T )
[/trigger]
[trigger]
timer
事件
条件
动作
自定义代码: local integer udg_Timer_I=0
自定义代码: local timer udg_Timer_T
Set Timer_T = (到期的计时器)
Set I = (从游戏缓存读取整数,名称: Integer 类别: (转换 Timer_I 为字符串) 缓存: w3v)
Set R = (从游戏缓存读取实数,名称: Real 类别: (转换 Timer_I 为字符串) 缓存: w3v)
Set PointA = (UnitA[I] 的位置)
Set PointB = (UnitB[I] 的位置)
Set PointC = (从 PointB 开始,距离 Movespeed ,方向为 (PointA 到 PointB 的角度) 度的位移处)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 运作)
If - 条件
(PointA 和 PointC 之间的距离) 小于或等于 Movelength
(PointC 处的 可通行地面 通行状态为关闭) 不等于 TRUE
R 大于或等于 1.00
Then - 动作
单位 - 设置 UnitB[I] 的X坐标为 (PointC 的X轴坐标)
单位 - 设置 UnitB[I] 的Y坐标为 (PointC 的Y轴坐标)
如果(所有的条件成立) 则运行 (Then - 动作) 否则运行 (Else - 运作)
If - 条件
((PointA 和 PointC 之间的距离) + Movespeed) 小于或等于 Movelength
Then - 动作
游戏缓存 - 记录 (R - 1.00) ,使用名称: Real 类别名: (转换 Timer_I 为字符串) 缓存: w3v
计时器 - 启动 Timer_T,应用计时方式: 一次性,计时周期为 Movetime 秒
Else - 动作
自定义代码: call DestroyTimer( udg_timer_T )
Else - 动作
自定义代码: call DestroyTimer( udg_timer_T )
点 - 清除 PointA
点 - 清除 PointB
点 - 清除 PointC
[/trigger]
[trigger]
dead
事件
条件
动作
单位 - 删除 (死亡单位)
[/trigger]
实验了一下,虽然还是有点卡(因为创建特效马甲,关闭了就不卡了),但是比用用生命周期的方法好多了。
地图中按ESC使全部圣骑士开启护盾。
又想到某个更为简单的方法
就是直接使用timer转的整数模8192的余作为数组序号
恩,如果这个参数的传递延时不是很长的话(不会使地址>8192而覆盖了没有使用的变量)
还有,关于缓存传递单位,其实也可以不用数组序号,而是直接传递单位转换的数字 |
评分
-
查看全部评分
|