|
楼主 |
发表于 2008-10-28 22:58:11
|
显示全部楼层
[月协出品] YD的JASS教程
[简介]月协的JASS教程,一共三卷,内容丰富,语言通俗易懂,举例生动形象妙趣横生,更介绍了一些非常实用的小技巧;虽然YD,却深受某些朋友喜爱;本打算把这些教程净化后发布,但一来太花时间,二来会破坏教程原有的味道,故作保留,请大家以正确的眼光对待。
[序]这些JASS教程,均出自月协会长之手,他以天马行空的手法给我们展现了一个奇妙荒诞的JASS世界,让我们在大笑过后不但消除了对JASS的恐惧更增进了对JASS的了解。在第一卷讲变量时,他以三名妓女来分别比喻全局变量、局部变量和全局变量数组,并在篇末讲解了一种通过“阉割全局变量”,让技能可以多人使用的方法;在第二卷讲函数时,以嫖客和妓女为例讲解函数的调用,情节丝丝入扣,顺带介绍了一种快速查看地图代码的小技巧;在第三卷讲GameCache时,以木子美的性爱日记为参照讲解GameCache的使用,更把GameCache跟Return Bug和Timer的关系比作淫乱的3P...
一、变量
1.什么是变量
变量是存放的是实质的东西,并且因存放的东西不同而分类不同:有单位、区域、触发器等变量——这样说吧,就像容器,放水的叫杯,盛饭的叫碗,装屎的叫马桶。因分类不同,所以你不能让一个变量储存与它类型不同的东西,譬如你不能用单位变量来保存地图上一个区域,就像你不能用马桶给客人盛饭。
2.不同变量类型的转换
虽说变量不能储存与它类型不同的东西,但变量的类型,其实是可以改变的。我们在T里,看到“将一个整数转换成实数”,“将一个整数转换成字符窜”等等;WE里提供了三种变量类型之间的自由转换——整数,实数,字符窜;就像我们可以用杯子装饭,拿碗装水一样。
不知不觉便说到我们的周星星同学了,因为有人看到他居然拿马桶吃饭;这是怎么回事?原来有个Return Bug,利用系统漏洞可以实现任意两个变量类型之间的转换。由于周星星是个特工,他的皮鞋,其实是吹风机,他的电话,还是吹风机,也就是说,由于职业需要,他把他的东西做了改装,以麻痹敌人。所以,他拿的马桶也不是真的马桶,那其实是个饭盒,外观像马桶而已。所以当周星星拿着马桶去厕所,别人以为他是去便便,其实他是去吃饭。
关于Return Bug,将在后面着重单独列出来讲。
3.全局变量与局部变量
变量是容器,这里我们拿杯子来说明全局变量与局部变量的区别。全局变量就像一个玻璃杯,不可能两个人同时使用,使用完下次可继续使用;局部变量则像一叠一次性纸杯,同时可以满足很多任何水的需要,并且使用完纸杯就丢掉,即便你有Sars也不怕传染给别人。
一般而言,由于程序在执行时,速度很快,因此多个T使用同一个全局变量,出错的概率很小;但,一旦T里有等待,情况就不妙了。
就像用杯子喝水,如果你是一口气把水喝完,然后把杯子放回原处给下一个人用,没什么问题;但如果你喝一小口,歇半天,再喝下一口,就出问题了——如果这时,另外有人也要用这杯子,那么,你跟他将轮流喝杯子里的水——很有断臂山的感觉。
好了,我们把目光回到JASS上。
1>全局变量
全局变量我们并不陌生,顾名思意,它是在不同的函数体里都能使用的变量。
那么,哪些变量是全局变量呢。
首先我们在T里自定义的变量全是全局变量;将T转为J后,你会发现,所有自定义变量前都有udg_的前缀。比如,我们定义一个类型为整数的变量i,那么,当保存地图时,我们可以看到下面这条J:
jass: Copy code
globals
// User-defined
integer udg_i= 0
endglobals
可见,在J里,全局变量是在globals下定义的。
以bi_为前缀的变量也是全局变量,比如bj_lastCreatedUnit,bj_forLoopAIndex,等,或许这些变量你看了有些陌生,但是之前在T里我们曾大量使用过。
在介绍bj_类全局变量前,我们先看两个例子:
我们常说,不能在循环里加等待,为何?因为bj_forLoopAIndex便是循环里使用的循环整数A,它是一个全局变量;如果在循环里加等待,那么当别的T也用循环整数A来执行循环时,前面的提过断臂山就将上演。
还有一个经典的错误,我们在创建一个单位后,等待XX秒,然后命令上次创建的单位去XX,便有可能会出错,因为此时最后创建的单位可能不是原来的单位了。或许你已经猜到了,我们在用T时,系统每生成一个单位,便用bj_lastCreatedUni来保存它,因此使用等待之后,那它可能保存别的单位去了。
其实,bj_类全局变量,不是别的,正是WE自带的全局变量;如果说udg_类变量是二奶,那人家bj_类变量就是原配。
2>局部变量
局部变量是在一个函数体里定义的变量,并且只能在该函数体内使用。它定义的方式如下:
local <类型> <变量名>
比如,我们定义一个单位变量:
local unit FRJJ
于是,我们就定义了个名为“芙蓉姐姐”的单位变量。
“定义它做什?”
“待会儿我要用她教训看帖不回帖的人。”
“YD男,你这样讲解太费事了,把局部变量比作老婆,把全局变量比作军妓,不就讲明白了么!”
“非也,老婆都还有红杏出墙的可能,但局部变量它忠贞不二绝不会勾一搭二勾三搭四。”
要注意下,部分类型的局部变量在使用后必须清零,所以在用FRJJ教训完看贴不回帖的人后,要记得
set FRJJ = null
除了unit类变量,类似需要清空的还有rect, location, timer, trigger, group, triggercondition, triggeraction,我只记得这几个,漏了的话请大人补充。
3>全局变量+数组
丽春院的生意火了,这可把已经升级到老鸨的韦春花乐得合不拢嘴;但让她发愁的是,最近人手严重不够用。举个例子,她去给田大爷唱十八摸,都唱到第十七摸了,结果西门大官人又点她去唱;给西门庆唱了第一摸后,在田伯光面前把第十八摸唱成了第二摸,这可把她郁闷到了。
这该死的全局变量!
这时,一个小鬼头跑进来,两边脸都有三条纹,跟小花猫似的;他问:
“店里招人吗,不用给我工钱,给碗拉面就是了。”
“我们不招伙计。”
“我可以去接客。”
“哼,来这的人都来找姑娘的,没人会找正太……”
韦春花话音未落,眼前的小正太不见了,出现一个裸体的美女,两边脸都也有三条纹。
“你看,这样行吗?”
哇噻,这小鬼居然会使传说中的色诱术,相信大家都猜到他是谁了吧!
这时西门庆跟田伯光打起架了,都想要这小美女陪,但又不肯玩3P,这可急煞了韦春花。此时,只见小美女双手结印,大喝一声“影分身之术”;瞬间三个美女出现在众人面前。
三个美女,一个陪西门庆,一个陪田伯光,另一个接过拉面埋头大吃。
韦春花纳闷,难道这小子像孙悟空一样,拔毛一吹能变出小猴子;她好奇地到两位客人的房前偷听,只闻得那一声声“呀咩嗲”连绵不绝,没有任何可疑之处。
事后,当西门庆跟田伯光满足地走出来,韦春花进屋一看,哪有小美女的影子……
局部变量就是好啊!不愧是东嬴来的,真厉害。韦春花感叹道。
这时,又进来一个女人,十分妖艳。
“你是谁?”
“难道你看不出,我是个女人吗?”
“你来这做什么?”
“看你缺人手,帮你接客咯!”
“不用了,我有人选了。”这小鬼只要一碗拉面就能打发,而且会这么厉害的法术,韦春花当然不会再招人。
“这小Y头片子有我漂亮么?”
“人家会法术。”
“不就是分身术么,我也会!”说完,一阵烟雾过后,几十个美女出现在韦春花面前。
这时,门口的客人再人忍不住,一窝蜂冲进来,抢了美女就去开房。
“好,你被录用了,你叫什么名字。”
“我叫春三十娘。”
春三十娘的分身比那小鬼头的更好,完事后会从房里走出来;不像那小鬼头的分身,太邪乎了。
托两个伙计的福,这几天丽春院生意一直很好。不过,被春三十娘的分身服侍过的客人,有些染上了花柳;而小鬼头的分身,即便是服侍了有花柳的客人,也没事,因为服侍完后分身就不见了,连根毛都没有。渐渐的,客人不敢点春三十娘服务了。
这时,有人指出,春三十娘的分身术是骗人的把戏,这人不是别人,正是我们智慧的化身——阿凡提。
原来阿凡提每次被春三十娘的分身服侍,都会在她们身上做记号;终于有天,他发现服侍自己的分身上有以前做过的记号。
铁证如山,春三十娘只好承认,她有二十九个孪生姐妹——她们分别是春大娘,春二娘,……,春二十九娘。
那么,故事讲完了~
如果韦春花是全局变量,旋涡鸣人是局部变量,那春三十娘跟她的姐妹们就是全局变量加数组——她们长得一模一样,能同时应付多人需求。
全局变量加数组还能克服全局变量的一些弊端,比如,我们要在循环里加等待,那我们就不要使用循环整数A,而是定义一个整数变量数组Loop[],可以把循环数设为Loop[触发单位的自定义值],或Loop[触发玩家的索引],这样一样出错的概率就大大降低。
因此,使用不了局部变量,用全局变量加数组也是个不错的选择~~
需要指出的是,关于数组的尺寸,一般类型变量的数组,尺寸设置为0就可以了,使用时数组会自动增加其长度;而单位组跟玩家组类型的数组,则必须设置好尺寸,比如PiaokeZhong[]的尺寸设置为3,那PiaokeZhong[4]就是无效的;PiaokeZhong[3]也无效,因为数组的有效索引是从0开始的,所以真正有效的三个单位组是PiaokeZhong[0]、PiaokeZhong[1]、PiaokeZhong[2]。
4.王道
即便采用全局变量加数组,也不能完美地模拟局部变量的功能,正如前面所说,春三十娘的分身还是会传播花柳;可是,我们无法在T里使用局部变量,那么,怎么完美地解决了。
当你被问到谁是你心目中武功最高的人,你可能会想到他(她)——东方不败。为什么他(她)最厉害呢,因为他(她)既不是男人也不是女人,但同时又具备了两者的特性,阴阳调和,是天地间最可怕的生物。所以,人妖是王道啊,比如我国现在采取的一国两制。
那么,如何将局部变量写进T里呢,呵呵,我们有Custom Script(自定义代码),也就是传说中的《葵花宝典》。
举例如下:
Trigger Tree Present: Zoxc @ wc3campaigns | Migration: Greedwind | 展开 | 收缩 | 复制
piaoji
事件
单位 - 单位进入 丽春院
环境
((触发单位) 是一个嫖客) 等于 True (真)
动作
自定义:local unit piaoke = GetTriggerUnit()
自定义:local real x = GetUnitX(piaoke)
自定义:local real y = GetUnitY(piaoke)
自定义:local unit WeiChunhua = CreateUnit(Player(0),'JV00',x,y,0)
游戏 - 对 (所有玩家) 显示文本: 楼上楼下的~
游戏 - 对 (所有玩家) 显示文本: 姑娘们出来~
游戏 - 对 (所有玩家) 显示文本: 接客了!
自定义:call IssueTargetOrderBJ( piaoke, "XX", WeiChunhua )
等待 1800.00 游戏秒
自定义:set piaoke = null
自定义:call RemoveUnit(WeiChunhua)
自定义:set WeiChunhua = null
如何,我们用个局部变量piaoke来保存触发单位,然后生成的单位WeiChunhua也用局部变量保存,如此一来,即便丽春院生意再红火,也不会出现人手不够的情形,也不会有人染上花柳。
这里,需要注意下,含有local的自定义代码必须放在其它代码前面,否则会出错。
那么,如何把一个含有全局变量的T,变成上面的“东方不败”呢,呵呵,很简单。
我们先用T把这个触发写好:
Trigger Tree Present: Zoxc @ wc3campaigns | Migration: Greedwind | 展开 | 收缩 | 复制
piaoji
事件
单位 - 单位进入 丽春院
环境
((触发单位) 是一个嫖客) 等于 True (真)
动作
设置 piaoke = (触发单位)
设置 point = (单位 piaoke 的位置)
单位 - 创造 1 个妓女为了玩家 1(红色) 在 point 面对 0.00 度
设置 WeiChunhua = (最后创建的单位)
游戏 - 对 (所有玩家) 显示文本: 楼上楼下的
游戏 - 对 (所有玩家) 显示文本: 姑娘们出来
游戏 - 对 (所有玩家) 显示文本: 接客了!
单位 - 命令 piaoke XX WeiChunhua
等待 1800.00 游戏秒
单位 - 把 WeiChunhua 从游戏中不留痕迹的删除
点 - 删除 point
好了,我们开始人类改造手术吧(奸笑~)
首先,我们把这个T转成J,我们可以看到,在动作函数里
jass: Copy code
function Trig_piaoj_Actions takes nothing returns nothing
set udg_piaoke = GetTriggerUnit()
set udg_point = GetUnitLoc(udg_piaoke)
call CreateNUnitsAtLoc( 1, 'JV00', Player(0), udg_point, 0.00 )
set udg_WeiChunhua = GetLastCreatedUnit()
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_1330" )
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_1331" )
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_1332" )
call IssueTargetOrderBJ(udg_piaoke, "XX", udg_WeiChunhua )
call PolledWait( 1800.00 )
call RemoveUnit( udg_WeiChunhua )
call RemoveLocation( udg_point )
endfunction
现在,我们可以戴上手套,拿出剪刀了(继续奸笑)。
我们的目的,是用局部变量替代全局变量;找了下,这段代码里有三个全局变量,udg_piaoke,udg_point,udg_WeiChunhua;为什么我们能很快找出全局变量呢,因为他们多长了个东西——“udg_”,好了,是时候阉割全局变量了让他们变人妖了~
剪掉udg_后,代码变成
jass: Copy code
function Trig_piaoj_Actions takes nothing returns nothing
set piaoke = GetTriggerUnit()
set point = GetUnitLoc(piaoke)
call CreateNUnitsAtLoc( 1, 'JV00', Player(0), point, 0.00 )
set WeiChunhua = GetLastCreatedUnit()
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_1330" )
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_1331" )
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_1332" )
call IssueTargetOrderBJ(piaoke, "XX", WeiChunhua )
call PolledWait( 1800.00 )
call RemoveUnit(WeiChunhua )
call RemoveLocation(point )
endfunction
那么,手术结束了吗?当然没,因为局部变量是要先定义的,而且在使用完后,单位啊,点啊之类的变量要清空。
jass: Copy code
function Trig_piaoj_Actions takes nothing returns nothing
local unit piaoke
local unit WeiChunhua
local location point
set piaoke = GetTriggerUnit()
set point = GetUnitLoc(piaoke)
call CreateNUnitsAtLoc( 1, "JV00", Player(0), point, 0.00 )
set WeiChunhua = GetLastCreatedUnit()
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_1330" )
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_1331" )
call DisplayTextToForce( GetPlayersAll(), "TRIGSTR_1332" )
call IssueTargetOrderBJ(piaoke, "XX", WeiChunhua )
call PolledWait( 1800.00 )
call RemoveUnit(WeiChunhua )
call RemoveLocation(point )
set piaoke = null
set WeiChunhua = null
set point = null
endfunction
手术成功,我们先把这段代码保存下来。
最后,我们把这些代码,一行行用自定义代码加到T里,就成了这样子~
Trigger Tree Present: Zoxc @ wc3campaigns | Migration: Greedwind | 展开 | 收缩 | 复制
piaoji
事件
单位 - 单位进入丽春院
环境
((触发单位) 是一个嫖客) 等于 True (真)
动作
自定义:local unit piaoke
自定义:local unit WeiChunhua
自定义:local location point
自定义:set piaoke = GetTriggerUnit()
自定义:set point = GetUnitLoc(piaoke)
自定义:call CreateNUnitsAtLoc( 1, 'hfoo', Player(0), point, 0.00 )
自定义:set WeiChunhua = GetLastCreatedUnit()
游戏 - 对 (所有玩家) 显示文本: 楼上楼下的
游戏 - 对 (所有玩家) 显示文本: 姑娘们出来
游戏 - 对 (所有玩家) 显示文本: 接客了!
自定义:call IssueTargetOrderBJ(piaoke, "XX", WeiChunhua )
等待 1800.00 游戏秒
自定义:call RemoveUnit(WeiChunhua)
自定义:call RemovLocation(point)
自定义:set piaoke = null
自定义:set WeiChunhua = null
自定义:set point = null
于是一个伟大的人妖诞生咯~
可以看出,对于含有全局变量的一行T,我们实行阉割,然后装进自定义代码中,但对于其他的T,比如上面的“游戏 - 对 (所有玩家) 显示文本: 接客了!”、“等待 1800.00 游戏秒”,则可以原封不动保存下来。
我一直认为做图,没必要学习JASS,T就已经绰绰有余;只需要了解点排泄方面的知识,以及会用两句Custom Script,就足够了。按刚才阉割全局变量的方法,我们可以轻松把一个技能变成可以多人同时使用。
综述,使用Custom Script是解决全局变量与局部变量矛盾最好的方法。
我是看这个教程把全局变量 变成局部变量的~~~~~ |
|