|
发表于 2006-4-3 17:03:14
|
显示全部楼层
[原创]学JASS,从最简单的T开始 作者:fangdaping
一直以来都是J盲,由于对某些东西感兴趣,不得不学JASS,看了些教程,自己也琢磨了一下,多少有点体会。
先讲两个简单的问题:
什么是JASS?
不必说了,想学JASS的人一般心里都有底,而且几乎所有的教程都有介绍,我就免了=。=
学JASS有什么先决条件?
以我个人的体会:1,有一定的计算机语言基础(主要是逻辑和思路);2,有一定的英文基础,方便阅读和记忆;3,用惯英文WE最好,因为英文WE的T看起来比较像JASS的库函数。
如果不具备上面条件,显然学起来要困难,但只要努力,没有什么做不到。
关于JASS教程,有很多前辈写了,如C-A的“JASS速成教程”,eGust的JASS教程和GREEDWIND的“JASS完全手册”,另外小白等人好像也有写。相信不少朋友都看过,不过因为几乎是纯理论所以相信不少朋友看得很懵,虽然GREEDWIND喜欢举一些比较飘的例子(面包、爱情、女人)但是因为我们在触发器里看不到这些东西,所以很难理解我自己也是稀里糊涂,我一直认为结合实例研究是比较好的学习方法。
但是上哪找合适的JASS演示来研究呢?一般用JASS写的都不是几个函数就了之的,大段的代码令人眼花,看到就怕,我和一些朋友聊天,他们有些人告诉我一个简单的T转化成J都有那么多东西,真是不想学,确实J比T看上ヒ?榉车亩啵?卸嗦榉衬兀空乙桓黾虻サ?转成J看看先!
什么T最简单?当然是什么都没有的T最简单了(废话)~,但是-----他果真“什么都没有”吗?我们命名一个名叫“meiyou\"的T(事件,条件,动作全无)转成J,我们看到下面一段代码(以下你最好需先掌握一个函数的声明和调用格式即“function。。。takes。。。returns 。。。。”和“call。。。。”,这些上面提到的教程都有,我不在重复):
function Trig_meiyou_Actions takes nothing returns nothing
endfunction
//===========================================================================
function InitTrig_meiyou takes nothing returns nothing
set gg_trg_meiyou = CreateTrigger( )
call TriggerAddAction( gg_trg_meiyou, function Trig_meiyou_Actions )
endfunction
这说明该T并非“什么都没有”,下面我就来简单介绍一下J和T中的事件、条件和动作是如何对应的。
就以上面一段J为例(因为它最简单),我们一般从那条分割线下方看起:
function InitTrig_meiyou takes nothing returns nothing //这是一个触发器初始化的函数,它是每个触发器必备的,而且我寻找触发器的时候一般也以此为起点,它的名字是“InitTrig_”+“触发器名(此处为meiyou)”,后面肯定是“takes nothing returns nothing”。
set gg_trg_meiyou = CreateTrigger( ) //表示创建触发器,这是一个变量的声明和赋值,其格式也是固定的,唯一不同的是变量名(注意触发器类型的变量在调用时前面要加上gg_trg_,至于后面,则是触发器的名称(这里是meiyou),后面= CreateTrigger( )是固定的。
注意,不管你的触发器有多复杂,以上两个句子肯定是要写。
call TriggerAddAction( gg_trg_meiyou, function Trig_meiyou_Actions ) //这个call TriggerAddAction表示的是给触发器添加动作,他的参数有2个:一个是你要添加动作的触发器变量(此处即为gg_trg_meiyou),另一个是“动作函数”,其名称一般是“Trig_”+“触发器名(meiyou)”+“_Actions”,这么说有点抽象,说通俗点就是---你想添加什么动作---所有的这些动作将被写成一个函数(此处为function Trig_meiyou_Actions),细心的朋友能发现这个“动作函数”就出现在分割线的上方,我用蓝色钩出。
function Trig_meiyou_Actions takes nothing returns nothing //触发器动作函数,它也必须是takes nothing returns nothing,但是,由于我们这里什么动作都没有,所以他直接就endfunction(结束函数)了。
知道了动作是怎么被执行的,那么事件和条件呢?没关系,我们来看一个完整的T:
下面有人叫到“哎,这个T很眼熟啊,这不是沧海大人的刷兵演示吗?”没错,就是要找大家熟悉的例子来讲解,因为这个T的流程你再清楚不过了,为了讲解方便,我特地加了一个条件(原T是没有条件的),那么我们把它转成J来看看:
function Trig_GO_Conditions takes nothing returns boolean
if ( not ( GetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD) <= 5000 ) ) then
return false
endif
return true
endfunction
function Trig_GO_Func004A takes nothing returns nothing
call IssuePointOrderLocBJ( GetEnumUnit(), \"attack\", GetRectCenter(gg_rct_B) )
endfunction
function Trig_GO_Actions takes nothing returns nothing
set udg_Lv = ( udg_Lv + 1 )
call CreateNUnitsAtLoc( 5, udg_arm[udg_Lv], Player(11), GetRectCenter(gg_rct_A), bj_UNIT_FACING )
call ForGroupBJ( GetUnitsInRectOfPlayer(gg_rct_A, Player(11)), function Trig_GO_Func004A )
endfunction
//===========================================================================
function InitTrig_GO takes nothing returns nothing
set gg_trg_GO = CreateTrigger( )
call DisableTrigger( gg_trg_GO )
call TriggerRegisterPlayerStateEvent( gg_trg_GO, Player(11), PLAYER_STATE_RESOURCE_FOOD_USED, LESS_THAN, 1.00 )
call TriggerAddCondition( gg_trg_GO, Condition( function Trig_GO_Conditions ) )
call TriggerAddAction( gg_trg_GO, function Trig_GO_Actions )
endfunction
比刚才那段长多了,不要急,慢慢来分析,首先依然从分割线下方开始,一边分析一边对照第一个例子。
function InitTrig_GO takes nothing returns nothing //初始化“GO”这个触发器
set gg_trg_GO = CreateTrigger( ) //创建触发器
上面两步必不可少。
call DisableTrigger( gg_trg_GO ) //因为这个触发器被设置成初始不打开,这里我们记住了一个库函数DisableTrigger( )
call TriggerRegisterPlayerStateEvent( gg_trg_GO, Player(11),PLAYER_STATE_RESOURCE_FOOD_USED, LESS_THAN, 1.00 ) //这里便是注册触发器事件的语句了,函数名一般是“TriggerRegister”+。。。。+“Event”+。。。,它的参数由前面事件的种类而定,但是有一个参数总是在的,那就是---你为哪个触发器注册事件,你必须把这个触发器名字告诉电脑。具体就这里来说,这里TriggerRegisterPlayerStateEvent表示的是“玩家属性(PlayerState)”事件,他的参数:gg_trg_GO是你告诉电脑的触发器名,Player(11)表示是玩家12的事件(因为是从0算起的),PLAYER_STATE_RESOURCE_FOOD_USED表示“玩家使用的食物”,LESS_THAN是“小于”,1.00 是说它小于1,前面两个大写的代码都是游戏中早就定义的常量,表示一个固定的含义,无法更改(这些代码如果你英文稍微好点,猜也猜的出意思)----于是这里整个的事件就是:玩家12所使用的食物量少于1.00。
call TriggerAddCondition( gg_trg_GO, Condition( function Trig_GO_Conditions ) ) //这里便是为触发器添加条件,函数名是TriggerAddCondition,参数有两个,一个你仍然要告诉电脑你为哪个触发器(这里是gg_trg_GO)添加条件,另外一个则是一个“条件函数(这里的function Trig_GO_Conditions)”,与第一个例子所讲的“动作函数”一样,你可以发现它也出现在分割线的上方(紫色标出),我们稍后讨论。
call TriggerAddAction( gg_trg_GO, function Trig_GO_Actions ) //这个便是给触发器添加动作了,上一个例子我们已经见到了。
一般来说,上面这一段我们可以看做是一个“准备阶段”
下面看分割线以上。
function Trig_GO_Conditions takes nothing returns boolean
if ( not ( GetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD) <= 5000 ) ) then
return false
endif
return true
endfunction
这是我们所说的“条件函数”,注意它肯定是takes nothing returns boolean(因为有“是”与“非”两种选择,所以返回布尔变量),下面我一句一句分析:
if ( not ( GetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD) <= 5000 ) )
GetPlayerState()表示“取得玩家属性”,GetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD)则表示“玩家1所有的黄金”, <= 5000表示“小于等于5000”,整个if语句的意思是“如果玩家1的金钱不小于等于5000”。
then return false //表示返回值为“非”,既然是“非”那么系统就不会执行下面的动作了,注意我前面强调了这个“不”字,因为前面有一个not存在,这是WE在把T转成J时的习惯写法写法,我们正常的逻辑是“XX条件成立,返回‘是’”,而WE喜欢写作“XX条件不成立,返回‘非’,否则返回‘是’”,习惯了就好。
介绍完条件函数,我们看动作函数。
function Trig_GO_Func004A takes nothing returns nothing //恩?这个动作函数的名字好像和分割线下面的不一样啊,没关系,先跳过看下面一个函数。
function Trig_GO_Actions takes nothing returns nothing
set udg_Lv = ( udg_Lv + 1 )
call CreateNUnitsAtLoc( 5, udg_arm[udg_Lv], Player(11), GetRectCenter(gg_rct_A), bj_UNIT_FACING )
call ForGroupBJ( GetUnitsInRectOfPlayer(gg_rct_A, Player(11)), function Trig_GO_Func004A )
endfunction
恩,就是它了,那来分析一下。
set udg_Lv = ( udg_Lv + 1 ) //令LV=LV+1
call CreateNUnitsAtLoc( 5, udg_arm[udg_Lv], Player(11), GetRectCenter(gg_rct_A), bj_UNIT_FACING ) //这里CreateNUnitsAtLoc表示“创建多少个XX单位在X点”,5表示“创建5个”,udg_arm[udg_Lv]是你事先定义好的单位类型(这个定义在另外一个T里),Player(11)表示“为了玩家12”,GetRectCenter(gg_rct_A)表示“在地区A的中心”,bj_UNIT_FACING是游戏中的一个常量,也就是我们习惯说的“面向默认角度”,事实上这个角度是270度。整个意思就是在地区A的中心为玩家12创建5个单位(单位类型为udg_arm[udg_Lv])。
call ForGroupBJ( GetUnitsInRectOfPlayer(gg_rct_A, Player(11)), function Trig_GO_Func004A ) //ForGroupBJ是一个单位组函数,它一般也有2个参数,一个是“选取哪些单位(这里是GetUnitsInRectOfPlayer(gg_rct_A, Player(11)),意思是选取地区A中属于玩家12的所有单位),另一个是“你要这些单位干什么(这里是又一个动作函数function Trig_GO_Func004A---即是刚才被我们跳过的神秘函数)”。
现在我们可以看那个被跳过的神秘函数了,原来它是那些被“选中的单位”将要执行的动作函数。
function Trig_GO_Func004A takes nothing returns nothing
call IssuePointOrderLocBJ( GetEnumUnit(), \"attack\", GetRectCenter(gg_rct_B) )
endfunction
该函数只有一条语句call IssuePointOrderLocBJ( GetEnumUnit(), \"attack\", GetRectCenter(gg_rct_B) ),IssuePointOrderLocBJ表示“给单位下达命令到某点”,GetEnumUnit()表示“选取的单位”,\"attack\"是一个字符串,表示“攻击--移动到”,GetRectCenter(gg_rct_B)表示“区域B的中心”,于是整个动作是“命令选取的单位攻击--移动到区域B的中心”。
那么这个T就这么结束了,我们顺便接触了不少库函数和游戏常量(虽然这只是九牛一毛)。
可以说,只要你顺藤摸瓜,一步一步找下去,就能摸清楚一个J的执行过程。
PS:我这里已经说得相当详细。。。目的是为了帮助那些因为看到一大串代码而退缩放弃的朋友重新拾回信心,其实这帖内容非常简单,稍微有点水平的就不用看了,以后有空我会拿一些难一点的出来分析----当然就不会讲这么细了。
知道了J的大致流程我们只是说能看懂别人的J,并不代表自己能写,接下来应该是多找演示看了,一方面吸取别人的思路方法,一方面积累库函数和游戏常量------等有一定的积累量了,就可以自己开始写了。
末了,推荐些东西,一是GREEDWIND的“JASS完全手册”,里面的教程不必说,我最喜欢的是里面的资料很全;二是eGust的“JASSSHOP”,在这里面看JASS比在WE里看舒服,而且方便。
最后祝大家成功!
[ 本帖最后由 freeman_666666 于 2006-4-3 17:12 编辑 ] |
|