找回密码
 点一下
查看: 7098|回复: 18

【中级教程】出兵+正确使用漂浮文字+避免内存泄漏+局部变量在GUI T中的使用方法

[复制链接]
发表于 2006-4-19 05:01:15 | 显示全部楼层 |阅读模式
原帖由 kejian 于 2006-4-18 22:36 发表
http://www.ourga.com/forum/viewt ... &extra=page%3D1
各位:
     我是一名刚开始学做图的菜鸟,这两天刚做出一张防守地图,我用T刷出来的怪希望它移动攻击一个区域,但是它移动傻傻的,走两步停三下,还会出现拥挤的现象。请问一下各位大虾们该怎么解决这个问题?如果能像人类保卫战那样的就好了!!!


初步判断,是怪物堆积引起的。
一次产生60个怪,容易引起堆积而失去原来的控制。

用类似我的T重新修改,一次不要产生太多怪。贵精不在多。
可以在LOOP后面加WAIT 1 秒。

另外,
1)你的漂浮文字中有WAIT 10 秒后才销毁漂浮文字。这需要用局部变量处理。
2)对于Center of 地区 000 <情报>等重复调用的点,可以先用全局变量先储存,以免每次都产生临时点而有没法销毁,导致越玩越卡。
3)对于产生的3×2路兵(敌我双方),可以用单位组数组储存,单位死亡后从单位组中移除。


以下是例子
--术语:GUI T/GUI TRIGGER - 即是触发器编辑器中产生的直观触发器。
--关于局部变量和全局变量,请参看JASS或其他语言的有关教程,如:《WE & Jass Online 大全》http://www.ourga.com/forum/viewt ... &extra=page%3D1
在下面的例子中,使用了以下预先定义的全局变量(在Ctrl + B中增加)
  • regioncenter-----点-----------数组 数组大小任意 用于储存经常调用的点,避免产生不可销毁的临时点
  • myUnitGroup---单位组-----数组 数组大小任意 对所出的兵归类,避免在很大的区域使用Pick & Do
  • armType----------单位类型--数组 数组大小任意 出兵类型
  • FloatTextTmp---漂浮文字--只是为了方便在“Set FloatTextTmp = (Last created floating text)”中引用才定义的。注意只是为了在GUI TRIGGER中方便引用。


初始化经常使用的点,避免调用(Center of xxxx)的时候不断产生临时点
(这些点通常会在不同的TRIGGER中经常调用,应该预先作一次储存,供以后的TRIGGER调用。注意数组序号的归类,比如regioncenter[1] 至regioncenter[8]是地图下方的点,regioncenter[10]至regioncenter[16]是地图上方的点。序号归类是为了方便调用,序号太混乱了会弄晕你的。 )
[trigger]Location Init
    事件
        Map initialization
    环境
    动作
        -------- 初始化经常使用的点,避免调用(Center of xxxx)的时候不断产生临时点 --------
        Set regioncenter[1] = (Center of armBron <情报>)
        Set regioncenter[2] = (Center of 1 <情报>)
        Set regioncenter[10] = (Center of Wang2 <情报>)[/trigger]

出兵举例:
[trigger]bron
    事件
        时间 - Every 120.00 seconds of game time
    环境
    动作
        For each (Integer A) from 1 to 30, do (Actions)
            Loop - 动作
                Wait 0.50 seconds
                单位 - Create 1 armType[Lv] for 玩家 12 (棕色) at regioncenter[1] facing 默认的建筑朝向 degrees
                单位组 - Add (Last created unit) to myUnitGroup[1]
                单位 - Order (Last created unit) to 攻击-移动到 regioncenter[2]
        -------- 如果出现兵徘徊的情况,加下面的 --------
        单位组 - Pick every unit in myUnitGroup[1] and do (Actions)
            Loop - 动作
                单位 - Order (Picked unit) to 攻击-移动到 regioncenter[2]
        Set Lv = (Lv + 1)[/trigger]

当单位死亡的时候,从单位组(myUnitGroup[1])里清除单位
[trigger]Units1Died
    事件
        单位 - A unit 死亡
    环境
        ((Triggering unit) is in myUnitGroup[1]) 等于 TRUE
    动作
        -------- 当单位死亡的时候,从单位组(myUnitGroup[1])里清除单位 --------
        -------- 避免在很大的区域使用Pick Unit Do Something --------
        单位组 - Remove (Triggering unit) from myUnitGroup[1][/trigger]

正确使用漂浮文字(版本1.18以前,需要考虑有可能同时创建漂浮文字的情况和避免内存泄漏,关于更深入的讨论,请看楼下):
(因为使用漂浮文字都需要使用wait,假设在这等待的时间内又创建一个漂浮文字,应该怎么样清除第一次创建的漂浮文字呢?显然用“漂浮文字 - Destroy (Last created floating text)”是不能正确清除第一次创建的漂浮文字的。因为等待N秒后,这个最后创建的漂浮文字(Last created floating text)已不是第一次创建的漂浮文字了,而是指最近创建的!这里,必须要使用局部变量才可实现清除并发创建的漂浮文字。)
[trigger]WangJinWei
    事件
        单位 - 伪军指挥部 0061 <情报> 死亡
    环境
    动作
        -------- FloatTextTmp在变量表中已经定义(只是为了方便在“Set FloatTextTmp = (Last created floating text)”中引用才定义的,在这例子中实际上并未使用全局变量FloatTextTmp) --------
        -------- 下面的局部变量声明必须在TRIGGER的头部 --------
        Custom script:   local texttag udg_FloatTextTmp
        单位 - Unhide 汪精卫 0047 <情报>
        单位 - Move 汪精卫 0047 <情报> instantly to regioncenter[10]
        镜头 -  wangjinwei <情报> for 玩家 1 (红色) over 0.00 seconds
        动画 - Play 汪精卫 0047 <情报>s stand animation
        漂浮文字 - Create floating text that reads 杀死汉奸汪精... at regioncenter[10] with Z offset 10.00, using font size 30.00, color (0.00%, 0.00%, 0.00%), and 0.00% transparency
        -------- 实际上,在“Set FloatTextTmp = (Last created floating text)”中使用的已经是声明过的局部变量udg_FloatTextTmp --------
        Set FloatTextTmp = (Last created floating text)
        Wait 5.00 seconds
        单位 - Order 汪精卫 0047 <情报> to 攻击-移动到 regioncenter[10]
        -------- 先销毁(但依然没清空udg_FloatTextTmp所占用的内存) --------
        漂浮文字 - Destroy FloatTextTmp
        -------- 下句是彻底清理内存,防止内存泄漏 --------
        Custom script:   set udg_FloatTextTmp = null[/trigger]



为了更好的说明上面漂浮文字的使用,我把上面的GUI TIRGGER转变为JASS代码。请注意以下的红字udg_FloatTextTmp

在可执行的第一句    local texttag udg_FloatTextTmp 中,已经声明本函数内使用局部变量udg_FloatTextTmp(这局部变量只局限于此TRIGGER内专用,其他TRIGGER不可访问和改变。就是说,在文字显示期间-call TriggerSleepAction( 5.00 ),即使其他TRIGGER有同名的局部或全局变量udg_FloatTextTmp在此等待期间发生改变或者再次触发本TRIGGER,也不会影响此TRIGGER实例中的udg_FloatTextTmp所指的漂浮文字。这TRIGGER里的局部变量udg_FloatTextTmp为此TRIGGER实例专用。注:每运行一次TRIGGER我们称之为一个TRIGGER实例,不同时间先后运行的同一个TRIGGER程序也会产生完全不同的TRIGGER实例。局部变量的意义在于:一个人不可能再次趟过同一条河)。
如果没有此句声明(local texttag udg_FloatTextTmp),将会使用全局变量udg_FloatTextTmp(即是其他有可能并发的TRIGGER可以访问并改变此变量)。

注意,所有的变量声明都应该在函数头部!并注意区分大小写!

function Trig_WangJinWei_Actions takes nothing returns nothing
    // FloatTextTmp在变量表中已经定义(只是为了方便在“Set FloatTextTmp = (Last created floating text)”中引用才定义的,在这例子中实际上并未使用全局变量FloatTextTmp)
    // 下面的局部变量声明必须在TRIGGER的头部
    local texttag udg_FloatTextTmp
    call ShowUnitShow( gg_unit_N002_0047 )
    call SetUnitPositionLoc( gg_unit_N002_0047, udg_regioncenter[10] )
    call CameraSetupApplyForPlayer( true, gg_cam_wangjinwei, Player(0), 0 )
    call SetUnitAnimation( gg_unit_N002_0047, "stand" )
    call CreateTextTagLocBJ( "TRIGSTR_140", udg_regioncenter[10], 10.00, 30.00, 0.00, 0.00, 0.00, 0 )
    // 实际上,在“Set FloatTextTmp = (Last created floating text)”中使用的已经是声明过的局部变量udg_FloatTextTmp
    set udg_FloatTextTmp = GetLastCreatedTextTag()
    call TriggerSleepAction( 5.00 )
    call IssuePointOrderLocBJ( gg_unit_N002_0047, "attack", udg_regioncenter[10] )
    // 先销毁(但依然没清空udg_FloatTextTmp所占用的内存)
    call DestroyTextTagBJ( udg_FloatTextTmp )
    // 下句是彻底清理内存,防止内存泄漏
    set udg_FloatTextTmp = null
endfunction

为什么要用udg_?因为在WE触发器编辑器的变量表中定义的变量会最终转化为udg_开头的实际JASS变量名。
比如:变量表中的A, 会转换为JASS代码的udg_A
---------变量表中的a, 会转换为JASS代码的udg_a
---------变量表中的FloatTextTmp, 会转换为JASS代码的udg_FloatTextTmp
在此例先在变量表中定义FloatTextTmp,是引用的技巧,方便直接在WE触发器编辑中直接引用。实际上是为了方便此两句的引用:
        
         Set FloatTextTmp = (Last created floating text)
                  ......
                  漂浮文字 - Destroy FloatTextTmp
它转化成JASS代码便是:

         set udg_FloatTextTmp = GetLastCreatedTextTag()
                  ......
                  call DestroyTextTagBJ( udg_FloatTextTmp )
发表于 2006-4-19 10:13:00 | 显示全部楼层
very good
正在为漂浮文字头痛……
及时雨啊
回复

使用道具 举报

发表于 2006-4-19 11:03:41 | 显示全部楼层
顺便问下 是不是声明和莫个全局变量同名的局部变量 >= 2 的时候会出现bug
回复

使用道具 举报

发表于 2006-4-19 11:54:09 | 显示全部楼层
漂浮文字不需要清理的,生命周期结束就被清除
同时存在最大数量为100个,超过时直接替换最后一个

udg_xx的局部变量估计是为了方便用T的人,如果是这样的话,我们根本不用考虑这东西.
回复

使用道具 举报

 楼主| 发表于 2006-4-20 09:30:23 | 显示全部楼层
楼上说的非常正确,

一楼的漂浮文字的例子是WAR3 1.18以前用来举例如何在GUI TRIGGER中使用局部变量的经典例子。但自WAR3 1.18后,漂浮文字不需要清理的,可以设置漂浮文字的生命周期,生命周期结束就被清除。

我会举个更合适的例子。
回复

使用道具 举报

发表于 2006-4-20 11:57:53 | 显示全部楼层
原帖由 illlusion 于 2006-4-19 11:03 发表
顺便问下 是不是声明和莫个全局变量同名的局部变量 >= 2 的时候会出现bug

是的。会有BUG。
所以。还是不要使用这种方法了。
最好的办法就是直接用JASS写。
回复

使用道具 举报

发表于 2006-4-20 16:48:29 | 显示全部楼层
原帖由 amp34 于 2006-4-20 11:57 发表

是的。会有BUG。
所以。还是不要使用这种方法了。
最好的办法就是直接用JASS写。




这种bug是在什么地方发现的?不会是自己吧?能不能告诉我啊?

PS:论坛貌似很不稳定啊。。。
回复

使用道具 举报

发表于 2006-4-20 16:53:33 | 显示全部楼层
这种BUG在哪发现的?
不记得了。
可以自己测试的。。。。
回复

使用道具 举报

发表于 2006-4-20 20:09:00 | 显示全部楼层
原帖由 wataloo 于 2006-4-20 16:48 发表
这种bug是在什么地方发现的?不会是自己吧?能不能告诉我啊?

PS:论坛貌似很不稳定啊。。。



是我不小心发现的
http://bbs.uuu9.com/viewthread.php?tid=228807
【重要】Jass中的已知bug(翻译完成)

但我还发现一个Bug:
当函数中有多个局部变量与全局变量同名时,那些局部变量都引用同一个地址。
当你修改其中一个变量时,其他变量的值也会发生变化(因为引用同一个地址)。
如果那些变量类型不同的话,该Bug极易造成游戏崩溃。



前两天又被人发现过:
http://bbs.uuu9.com/thread-266148-1-3.html
好恐怖的BUG!!!!
回复

使用道具 举报

发表于 2006-4-20 20:20:41 | 显示全部楼层
嗯嗯。对。我看到的就素楼上发表的那个。
后来自己测试过。的确如此。。。
回复

使用道具 举报

发表于 2006-4-20 20:23:47 | 显示全部楼层
其实那也是WE不公开支持局部变量的原因。

以前我在暴雪官论上看到过此问题的声明。
回复

使用道具 举报

 楼主| 发表于 2006-4-21 04:46:01 | 显示全部楼层
那就是说,我的举例是徒劳的了。

老了老了
回复

使用道具 举报

 楼主| 发表于 2006-4-21 05:32:17 | 显示全部楼层
忽然有个想法,有没有可能在DDWE中实现:
1)在TRIGGER中可以声明局部变量(可能需要udg_前缀,可以在DDWE中隐去前缀udg_)
2)收集己经设计好的TRIGGER中声明的局部变量名字(udg_前缀)
3)把这些局部变量的名字去掉udg_,按变量类型分类。然后让编辑者可以在DDWE中选择所需类型的局部变量来方便地直接引用。
4)如果可能,声明局部变量的同时生成防止MEMORY LEAK的GUI代码。

目的:
1)不需要先声明同名的全局变量才可在GUI TRIGGER中引用。
2)可以方便在TIRGGER中方便地使用GUI模式的局部变量。毕竟,局部变量的声明不是普通新手能理解的。


方案设想(GUI,以中文说明):
1)声明局部变量 - 类型:点(location) 变量名称: tmpLoc 初始值: 无
---------------提示:以下插入TRIGGER ------------

(让普通的GUI TRIGGER都可以方便引用tmpLoc)

---------------以下是清除部分 -----------
2)清除1 - 类型:类型:点(location) 变量名称: tmpLoc
3)清除2 - 置空

1)对应JASS CODE:   local location udg_tmpLoc
2)对应JASS CODE:   RemoveLocation(udg_tmpLoc)
3)对应JASS CODE:   set udg_tmpLoc = null
回复

使用道具 举报

 楼主| 发表于 2006-4-21 05:40:41 | 显示全部楼层
如果上面的功能能实现,是WE的一大进步。

我是不知道你们怎么作DDWE的。在我看来,都可能实现。
回复

使用道具 举报

发表于 2006-4-21 09:20:00 | 显示全部楼层
到目前为止DDWE还只有我一人在做……

说到这个局部变量,其实我早就想弄出这么个功能来了,可是事实上可以新增的触发,其对应JASS仅限于函数(如RemoveLocation())。

像local、if、return这种关键字是不能用作新触发的。虽然WE本身有Skip remain action(即return) 和If...then...else结构,但是这2个似乎是在WE.exe中写死的代码。我一个编程盲人,对于反向工程自然是半点不懂,如果有达人能在WE里面插入几个新的关键字就好了……
回复

使用道具 举报

发表于 2006-4-21 10:25:14 | 显示全部楼层
好东西就是要顶……学习ing……
回复

使用道具 举报

发表于 2006-4-22 12:48:13 | 显示全部楼层
真是直得收藏 :victory:
回复

使用道具 举报

发表于 2006-12-16 20:35:10 | 显示全部楼层
好极了!
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-21 22:09 , Processed in 0.056150 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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