![]() |
|
| 您所在位置:游戏首页 >> 单机游戏 >> 魔兽 >>简单讲解一下全局变量与局域变量 | ||||||||||
| 简单讲解一下全局变量与局域变量 | ||||||||||
| 转自:新浪 时间:2004-9-29 20:55:40 点击: | ||||||||||
学过编程的人就不用看了(除非是只学过那种老式的用行号的basic的) 我先来举个例子吧,假如有个t,触发的事件是一个单位死亡(any unit dies),在这个map中有一个string型的全局变量s,t的事件如下(用j来写了,语句前是注释): function ****** takes nothing returns nothing //申请一个force型局域变量,并设置成死掉的单位的玩家 local force foc = GetOwningPlayer(GetTriggerUnit()) //设置s为死掉的单位的名字——位置A set udg_s = GetUnitName(GetTriggerUnit()) //等待30秒的游戏时间(Wait-Game Time) call PolledWait(30) //在屏幕上向foc指向的玩家输出死掉的单位的名字——位置B call DisplayTextToForce(foc,"A "+udg_s+" has been slain.") //释放内存 call DestroyForce(foc) set foc = null endfunction 下面来假设一个情节,首先是玩家1(player 1)的一个步兵(footman)被杀了,过了10秒player 2的一个食尸鬼(Ghoul)被杀了,结果将是: 在footman死后30s,player 1收到一条信息:A Ghoul has been slain. 在Ghoul死后30s,player 2收到一条信息:A Ghoul has been slain. 我来说明一下这个t的执行过程,当footman被杀的时候,t被触发了(t1),过了10s,这个t再次被触发(t2): 1.t1:set udg_s = "Footman",给局域变量foc分配了一块内存空间,并且set foc = player1 2.t1:开始wait 3.t2:在t1 wait了10s的时候被触发,set udg_s = "Ghoul",给局域变量foc分配一块内存空间,并且set foc = player2 4.t2:开始wait 5.t1:又wait了20s,这时t2已经wait了10s 6.t1:向foc(player1)输出udg_s的内容"Ghoul" 7.t2:又wait了20s后,向foc(player2)输出udg_s的内容"Ghoul" 看完这个过程后就大概明白了局域变量与全局变量的差别了吧? 在trigger editor中,全局变量是在菜单中编辑的(或者是“x”的图标)做的,在地图编译后,是在.j文件的最开始声明: globals unit udg_**** = null ...... endglobals 而局域变量,是指在每个t的最开始的位置声明: function ***** takes ***** returns ***** local unit *** = ***** ..... endfunction 全局变量对所有的t过程都可见,所有的t访问一个全局变量的时候,实际上访问的都是同一个内存地址。局域变量在t的开始时,通过声明语句划分内存空间,一个t每次触发的时候都会为局域变量划分内存空间,局域变量仅对本次的执行过程可见;也就是说,同一个t同时执行了几个进程时,相同名称的局域变量有不同的内存地址,每个进程只能访问该进程申请的内存地址,无法访问其他进程的内存地址;在每个进程结束之后,局域变量的内存空间会被释放,再也无法得到这个变量的值 从编程的角度来说,局域变量是在过程结束的时候,除了使用了指针并为指针指向的地址划分了新的内存空间,所有的局域变量都是自动释放内存空间的,但war3的似乎没有那么高级,所有的指针变量都不但需要最后Destroy,而且还要set =null(最后这个让我费解了好久,后来人家说blz自己的人都那么做,你还是照着来吧) 再说一些其他的差别。全局变量的访问速度要低于局域变量,不过对于现在的cpu来说速度差别可以忽略。明白了全局变量和局域变量的差别后,就要了解两个变量的使用原则。具体说的话,全部使用局域变量,只有在整个map的过程都需要保留这个变量的值,或者是向其他的t传递某个变量或者数值的时候,才需要全局变量(这个也是因为trigger提供的接口不够丰富,不然的话传递变量也不需要用全局变量)。 另外还有一个原则上的使用方法问题,从执行的速度上讲: 局域变量的访问速度 > 全局变量的访问速度 > 函数的访问速度 (靠左的速度更快) 所以如果某个常函数需要经常使用的话(如GetPlayersAll,向所有玩家的屏幕上发送信息是map中经常会用到的),可以使用一个全局变量,不仅速度要比GetPlayersAll快,而且也不需要每次都在使用DisplayTextToForce的t当中: local force foc=GetPlayersAll() .... call DisplayTextToForce(foc,****) call DestroyForce(foc) set foc=null 这么麻烦了,而且这个里面2次访问了函数,效率也要低了许多 另外一个是局域变量的使用原则。首先要说一些大家都不大关心的的东西,补充一些知识。可能绝大多数人都不看blz.j的吧,t使用的函数绝大部分是在blz.j里的,而blz.j里的函数都不是真正的API(应用程序接口),只有common.j里面的才是真正的API,blz.j里面的东西是对com.j进行了封装,而在blz.j里面,大量使用了bj_前缀的全局变量。下面说一个t里经常会用到的函数: function CreateNUnitsAtLoc takes integer count, integer unitId, player whichPlayer, location loc, real face returns group call GroupClear(bj_lastCreatedGroup) loop set count = count - 1 exitwhen count < 0 call CreateUnitAtLocSaveLast(whichPlayer, unitId, loc, face) call GroupAddUnit(bj_lastCreatedGroup, bj_lastCreatedUnit) endloop return bj_lastCreatedGroup endfunction 这个是创建单位(unit)的t实际上所使用的函数,在这个函数中还使用了另外一个blz.j中的函数: function CreateUnitAtLocSaveLast takes player id, integer unitid, location loc, real face returns unit if (unitid == 'ugol') then set bj_lastCreatedUnit = CreateBlightedGoldmine(id, GetLocationX(loc), GetLocationY(loc), face) else set bj_lastCreatedUnit = CreateUnitAtLoc(id, unitid, loc, face) endif return bj_lastCreatedUnit endfunction 整个函数过程中使用了2个全局变量(bj_lastCreatedUnit, bj_lastCreatedGroup),一个循环(loop),一个判断(if),还掉用了n次函数,而事实上我们常常只需要创建一个unit而已。而且使用了这个函数后,还要考虑内存释放的问题——事实上我是第一次看bj中CreateNUnitsAtLoc的函数,不认为这个函数会存在group的内存泄漏的问题,现在正在和人讨论,但是loc的泄漏是肯定的,又多执行了许多语句。 这么多的过程,实际上只要一条语句就能完成,比如我们经常做的,在施法者的位置创建一个“辅助单位”(caster),用j只要这样: local unit u = GetTriggerUnit() //等会儿再解释为什么要这句 local unit uCaster = CreateUnit( GetOwningPlayer( u ), '****', GetUnitX( u ), GetUnitY( u ), 0 ) 而如果用t的话,翻译成j,需要这样几句: local location loc = GetUnitLoc(GetTriggerUnit()) //这句需要手动添 call CreateNUnitsAtLoc( 1, '****', GetOwningPlayer(GetTriggerUnit), loc, bj_UNIT_FACING ) //下面这句到底需不需要晚些时候告诉大家答案,不过估计是需要,等会儿帖篇esper大大的文章 call Destroy(GetLastCreatedGroup()) call RemoveLocation(loc) set loc = null 而且在每次访问caster的时候,t还要使用GetLastCreatedUnit(),效率低了,工作量大了 首先就是要明确一个原则,希望各位逐渐由t转到j,提高自己map的执行效率。接下来局域变量的原则是需要应用在j中的。根据soarchin的观点,哪怕使用了一次的函数也可使用局域变量(咔咔,他自己说过的,表怪我)。俺觉得除非要释放那处内存,要不然没必要为只使用一次的函数也创立一个局域变量。我的习惯是,如果是嵌套的的函数调用,大于一次就为嵌套内的函数创建变量,比如GetOwningPlayer(GetTriggerUnit()),我会为GetTriggerUnit申请一个局域变量;如果一个函数使用了大于2次,我也会为那个函数申请变量。其实这些是习惯问题,申请变量一方面是代码好读了,另外一方面也提高了效率,都是个人习惯的问题。 其他的像wait之后如果也要使用GetTriggerUnit的话就一定要用局域变量的常识我就不用介绍了吧? 再补充一点关于循环的问题 For each (Integer A) from 1 to 10使用的实际上是 set bj_forLoopAIndex = 1 set bj_forLoopAIndexEnd = 10 loop exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd .... set bj_forLoopAIndex = bj_forLoopAIndex + 1 endloop 使用的3个变量都是全局变量,这个是有很大危险的(估计绝大多数人都知道了),所以一旦有for循环,一定要使用局域变量 |
||||||||||
|
上一篇攻略:[技术] 关于追枪的心得
下一篇攻略:[技术] DiGiTracker的cs瞄准技巧
|
||||||||||
|
||||||||||