找回密码
 点一下
查看: 4574|回复: 24

请问...TriggerRemoveCondition是怎么使用的?

[复制链接]
发表于 2008-1-20 23:08:33 | 显示全部楼层 |阅读模式
以下代码是我在everguo教程里看到的,用的是condition,但是使用的时候却发生错误
[codes=jass]function DestroyTriggerAll takes trigger trg returns nothing
         call TriggerRemoveCondition(trg,I2TC(GetStoredInteger(udg_GC,I2S(H2I(trg)),"TriggerCondition")))
         call DestroyTrigger(trg)
         call FlushStoredMission(udg_GC,I2S(H2I(trg)))
endfunction
//========================================================
function RegisterUnitAmortCond takes nothing returns nothing
            call SetUnitInvulnerable(GetTriggerUnit(), true)
            call DestroyTriggerAll(GetTriggeringTrigger())
endfunction

function RegisterUnitAmortEvent takes unit witchUnit returns nothing
         local trigger trg = CreateTrigger()
         call TriggerRegisterUnitStateEvent(trg, witchUnit, UNIT_STATE_LIFE, LESS_THAN_OR_EQUAL, 50)
         call StoreInteger(udg_GC,I2S(H2I(trg)),"TriggerCondition",H2I (TriggerAddCondition(trg,Condition(function RegisterUnitAmortCond))))
         set trg = null
endfunction[/codes]
这是在教程中看到的另一段代码,是用action做的...但却可以运行
[codes=jass]function RegisterUnitAmortAction takes nothing returns nothing
         local trigger trg = GetTriggeringTrigger()
         local triggeraction Act=I2TA(GetStoredInteger(udg_GC,I2S(H2I(trg)),"Triggeraction"))
         call SetUnitInvulnerable(GetTriggerUnit(), true)
         call TriggerRemoveAction(trg,Act)
         call DestroyTrigger(trg)
         call FlushStoredMission(udg_GC,I2S(H2I(trg)))
         set trg = null
         set Act=null
endfunction

function RegisterUnitAmortEvent takes unit witchUnit returns nothing
         local trigger trg = CreateTrigger()
         local triggeraction Act
         call TriggerRegisterUnitStateEvent(trg, witchUnit, UNIT_STATE_LIFE, LESS_THAN_OR_EQUAL, 50)
         set Act=TriggerAddAction(trg,function RegisterUnitAmortAction)
         call StoreInteger(udg_GC,I2S(H2I(trg)),"Triggeraction ",H2I(Act))
         set trg = null
         set Act=null
endfunction[/codes]


经过测试,把第一段代码中的call TriggerRemoveCondition(trg,I2TC(GetStoredInteger(udg_GC,I2S(H2I(trg)),"TriggerCondition"))) 去掉就不会出错...
不知道是我使用有问题,还是代码的问题....想请教下各位大大
发表于 2008-1-21 00:25:11 | 显示全部楼层
这是一个未知BUG,其实在代码里加个没有用的call BJDebugMsg(I2S(0)),就不会弹出游戏,具体为什么我也不知道,详情请见http://www.islga.org/bbs/read.php?tid=9628

这会是一个很有意思的BUG,希望能有人把它研究出来
回复

使用道具 举报

发表于 2008-1-21 11:28:38 | 显示全部楼层
这个bug我也碰到过………………后来很无奈的把triggercondition都改回triggeraction了………………

everguo大人的方法,恩,等下去试试~~
回复

使用道具 举报

发表于 2008-1-23 20:36:14 | 显示全部楼层
function RegisterUnitAmortCond takes nothing returns nothing

返回值类型不对。 应该是boolean。。。
回复

使用道具 举报

发表于 2008-1-23 20:39:22 | 显示全部楼层
引用第3楼feelerly于2008-01-23 20:36发表的  :
function RegisterUnitAmortCond takes nothing returns nothing

返回值类型不对。 应该是boolean。。。

报错的地方不在TriggerAddCondition,只要去掉TriggerRemoveCondition就完全不会出错的………………
回复

使用道具 举报

发表于 2008-1-23 21:52:39 | 显示全部楼层
引用第3楼feelerly于2008-01-23 20:36发表的  :
function RegisterUnitAmortCond takes nothing returns nothing

返回值类型不对。 应该是boolean。。。

改了返回值照样弹出
回复

使用道具 举报

发表于 2008-1-24 11:49:34 | 显示全部楼层
今天做了很多测试,基本上搞懂了出错的原因:在同个触发器中,不能直接用条件动作来删除该条件。 否则会出错(这个有点奇怪,删除触发器没有事,删条件就有事了)

根据我的分析, 应该是条件动作没有返回真假值之前,一直处于运行状态,如果直接在没有返回真假值之前就给触发器移除条件,这就相当于你在吃饼的时候,突然咽住了一样(就是内存冲突)

所以,我们必须在条件返回真假值之后(就是用计时器延时删除)这样就不会出错了。

其时这个BUG有些小白了,犯了一些逻辑上的错误而已。
回复

使用道具 举报

发表于 2008-1-24 12:08:42 | 显示全部楼层
嗯啊,那请ls发一个成功删除没有跳错的演示出来吧~~
回复

使用道具 举报

发表于 2008-1-24 12:48:13 | 显示全部楼层
[jass]
function ConvertHandleInt takes handle h returns integer
    return h
    return 0
endfunction
function ConvertTrigger takes integer i returns trigger
    return i
    return null
endfunction
function ConvertCondition takes integer i returns triggercondition
    return i
    return null
endfunction
function TimerDestroyTriggerAll takes nothing returns nothing
    local integer c = GetStoredInteger(bj_lastCreatedGameCache, "T","C")
    local integer t = GetStoredInteger(bj_lastCreatedGameCache, I2S(ConvertHandleInt(GetExpiredTimer())),"T")
    call TriggerRemoveCondition(ConvertTrigger(t), ConvertCondition(c) )
    call DestroyTrigger( ConvertTrigger(t) )
    call FlushStoredMission(bj_lastCreatedGameCache, I2S(ConvertHandleInt(GetExpiredTimer())))
    call FlushStoredMission(bj_lastCreatedGameCache, "T")
    call DestroyTimer( GetExpiredTimer() )
endfunction
function Trig_T_Conditions takes nothing returns boolean
    local timer t = CreateTimer()
    call FogEnable( false )
    call FogMaskEnable( false )
    call DisplayTextToPlayer( Player(0), 0,0, "123")
    call StoreInteger( bj_lastCreatedGameCache,I2S(ConvertHandleInt(t)),"T",ConvertHandleInt(GetTriggeringTrigger()))
    call TimerStart( t, 0.05, false, function TimerDestroyTriggerAll )
    return true
endfunction

//===========================================================================
function InitTrig_T takes nothing returns nothing
    local integer i = 0
    set bj_lastCreatedGameCache=InitGameCache("test.m3v")
    set gg_trg_T = CreateTrigger(  )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_T, Player(0) )
    set i = ConvertHandleInt(TriggerAddCondition( gg_trg_T, Condition(function Trig_T_Conditions) ))
    call StoreInteger( bj_lastCreatedGameCache, "T","C", i )
endfunction
[/jass]

以上是偶研究的结果,[这个也证明了我的推理。
回复

使用道具 举报

发表于 2008-1-24 13:46:26 | 显示全部楼层
貌似………………是的………………
那么………………能再问下,为什么如果按原先的那种做法,不是每个条件删除都跳错,而是只有在最后一个条件被删除时才跳呢??
回复

使用道具 举报

发表于 2008-1-24 14:07:37 | 显示全部楼层
刚才又试了一下,timer也不需要0.05的,0.00也就没问题了,恩,可能是执行的优先级问题吧
回复

使用道具 举报

发表于 2008-1-24 14:09:12 | 显示全部楼层
这个可能跟JASS的编译及运行规则有关,就如 Return bug 明明返回的值是不配匹的,但还是可以用的。原因就是因为只检查最后一个返回值。而触发器条件也会按照类似的规则来运行,这个目前只是推论,估计还得做一些测试才行。不过除此之外,想不出其他原因了。
回复

使用道具 举报

发表于 2008-1-24 14:17:23 | 显示全部楼层
哦,谢谢了~~
至少找到解决办法就算是进了一步了………………
回复

使用道具 举报

发表于 2008-1-24 14:28:24 | 显示全部楼层
引用第6楼feelerly于2008-01-24 11:49发表的  :
今天做了很多测试,基本上搞懂了出错的原因:在同个触发器中,不能直接用条件动作来删除该条件。 否则会出错(这个有点奇怪,删除触发器没有事,删条件就有事了)

根据我的分析, 应该是条件动作没有返回真假值之前,一直处于运行状态,如果直接在没有返回真假值之前就给触发器移除条件,这就相当于你在吃饼的时候,突然咽住了一样(就是内存冲突)

所以,我们必须在条件返回真假值之后(就是用计时器延时删除)这样就不会出错了。
.......

在你说BUG小白之前,请你能不能回答下   

为何加个没用的call BJDebugMsg(I2S(0)),可以阻止程序崩溃

照你的例子,“如果直接在没有返回真假值之前就给触发器移除条件,这就相当于你在吃饼的时候,突然咽住了一样(就是内存冲突)”,那么这个call BJDebugMsg(I2S(0)),是不是像杯水一样,能让在吃饼被噎住后,让你能顺利吞下这块饼
回复

使用道具 举报

发表于 2008-1-24 14:50:40 | 显示全部楼层
everguo大人,刚才试了下,加了call BJDebugMsg(I2S(0)),在最后一个农民hp<=50的时候还是跳错了额………………
可能是我加的不对,附上地图

rpbug.w3x (19 KB, 下载次数: 20)
回复

使用道具 举报

发表于 2008-1-24 15:49:12 | 显示全部楼层
测试了下  的确是这样

触发器条件在销毁前  必须返回值(或者说必须执行完条件里的动作)

为何销毁触发器不会出错呢  因为触发器即便被销毁  也会执行一次  同样的道理  在触发器动作上也适用

还有一点  提到线程  call 函数的执行是窜行的  触发器、Timer和ExecuteFunc等执行是并行的  因此  call 函数中执行的函数   也被看做是条件中的一部分   因此这函数中销毁条件   实际是在条件中销毁条件    条件在没有返回值前就被销毁

但使用Timer(其实也可用ExecuteFunc)后    线程关系是并行的  因此这样删除条件  Timer或ExecuteFunc执行的函数   不隶属于条件   它是在条件的外部销毁条件  所以不会出错

PS:feelerly你是对的,我之前的语气有点冲,可能在听到你说这BUG小白有点不高兴;当然,也希望老狼能振作起来,只要不涉及触发器条件的销毁,把动作写到函数里,仍旧是种很好的写法。
回复

使用道具 举报

发表于 2008-1-24 16:06:05 | 显示全部楼层
呵呵~莫有关系的了~~这种问题我也是第一次遇到,很多时候也只能做一些推测的说。

不过ExecuteFunc,删除条件仍会出错的。估计是ExecuteFunc仍会保持那个进程中的数据吧。

所以最好的办法也只剩下 Timer 了。(因为计时器是独立的,不传递数据的。)
回复

使用道具 举报

发表于 2008-1-24 16:12:36 | 显示全部楼层
但是为何在zhuzeitou的演示中,程序不是立即崩溃,而是执行到最后一个农民启动触发才崩溃呢
回复

使用道具 举报

发表于 2008-1-24 16:14:59 | 显示全部楼层
引用第11楼feelerly于2008-01-24 14:09发表的  :
这个可能跟JASS的编译及运行规则有关,就如 Return bug 明明返回的值是不配匹的,但还是可以用的。原因就是因为只检查最后一个返回值。而触发器条件也会按照类似的规则来运行,这个目前只是推论,估计还得做一些测试才行。不过除此之外,想不出其他原因了。

估计有点像return bug的问题 —— JASS的编译问题吧。目前偶也只是推测,这个需人做一些测试才行。
回复

使用道具 举报

发表于 2008-1-24 16:22:08 | 显示全部楼层
引用第17楼938于2008-01-24 16:12发表的  :
但是为何在zhuzeitou的演示中,程序不是立即崩溃,而是执行到最后一个农民启动触发才崩溃呢

这个问题也有一次类似的,就是jass培训班的那个3C选英雄,我一开始用的是condition,结果也是在选完最后一个英雄是跳错,这个时候我特意去看了acer01同学的作业,测试下来也有同样的问题
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-22 04:11 , Processed in 0.274630 second(s), 21 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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