|
楼主 |
发表于 2008-1-26 15:42:09
|
显示全部楼层
进阶高级
本章设计到jass语言中更复杂的一些东西,熟练使用好这些东西,你将体会到更多作图的乐趣。从本章开始,我会尽量结合自己在作图的一些经历,配合范例讲解j的实际应用
-----------------------------------------
1. function概述
结构化语言的特点就是,使用判断、循环和独立的过程来完成所有的功能。function是一段用来完成一个独立功能的代码,使用好j,就要学会用好function
1) function的构成
一段function,由声明、函数体两部分构成:
function 名称 takes [nothing | 参数列] returns [nothing | 返回类型] //声明
... // 函数体部分
<return [返回值]>
endfunction //标志一段function的结束
2) function的分类
a) 过程与函数
在passcal中,声明一段函数只用这个关键字,而声明过程则用另一个关键字;在c中,则直接使用变量类型来声明函数,可以把无返回类型的函数(void类型)理解成过程。我在这里沿用passcal的概念,将不返回值的函数定义为过程。
常函数与变函数
常函数返回一个固定的值,而变函数则根据参数的不同和函数体内的运算。常函数是在function的声明前加constant关键字:
constant function
c) API与自定义function
API(Application Programming Interface,应用程序接口)是指包含在common.j中的函数,该部分函数实际上是一些已经由系统封装好的函数,用户只要知道function名、功能、参数,就可以利用这部分function做到自己想要做的事情,通常API 是实现用户无法通过自定义function来实现的功能,在cj中,
API的声明形式如下:
native CreateItem takes integer itemid, real x, real y returns item
自定义function是指用户在使用过程中,自己定义的一些过程或函数,如我们用到一个地图初始化的trigger中注册trigger的部分:
function InitTrig_MapInit takes nothing returns nothing
set gg_trg_MapInit = CreateTrigger( )
call TriggerAddAction( gg_trg_MapInit, function Trig_MapInit_Actions )
endfunction
3) function的参数
在function的声明中,takes与returns之间的部分为参数部分。
nothing关键字表示无参数。传递参数的时候,要写明传递的参数的类型和参数在函数过程中的名称,如传递几个参数,不同参数之间用逗号(,)隔开:
a. function **** takes integer i returns **** //传递一个integer型参数
b. function **** takes real x, real y returns **** //传递两个real型参数
b. function **** takes nothing returns **** //不传递参数
4) function的返回值类型
返回值类型是在声明中returns后面的部分。
如使用nothing关键字,则表示不返回任何数值,该function为一个过程。函数只能有一个返回类型,可使用任何在cj中声明的变量类型:
a. function **** takes **** returns integer //返回integer型
b. function **** takes **** returns nothing //过程
-----------------------------------------
2. function的使用
1) 过程体与函数体
过程体由变量声明、代码两部分组成。变量声明部分是对本地变量的声明,前面已经介绍过,用local关键字来声明
函数体除了过程体以外,还需要有返回函数值的语句,这是函数与过程的区别。
2) function的可见度
只有一个function在前面已经声明过,后面的代码才能使用这个function。一个function对整个map都是可见的。
3) 调用function,传递参数,在function中使用参数,取得函数返回值
我们定义了一个function,那么如何在后面的过程中使用呢?
对于过程和函数,都可以使用下面的方法来调用:
call 名称(<参数列>)
参数列中参数的数量必须与声明中的数量相同,并且类型一一对应,如有一个函数:
function xyz takes integer a, real b, string c returns integer
...
endfunction
我们在调用这个函数的时候,必须如下形式传递:
call xyz(1,0.5,"c")
传递的参数可以是数值(如1 0.5 "a"等)、常量(如bj_PI、UNIT_STATE_LIFE等)、变量。在function使用参数的时候,直接使用声明function时候的变量名称:
function *** takes integer i, integer j returns ***
local integer a = i + 1
set j = j + a
....
endfunction
需要说明的是,参数的传递都是按值传递的,假如有这样2个funciton:
function add1 takes integer i ret
补充资料:
1. 全局变量与局域变量的差别
2. 两个jass的示例
下面结合两个范例来消化前面学过的东西
范例 1
前面已经说过,function是线性运行的,而trigger是并行运行的,那么假如我在做一个既能的时候,想要生成一个范围内的效果。但是如果在程序中用PolledWait执行的时候会发现,实际上的时间没法和真实的技能效果时间对应上,那么怎么解决呢?
一般的方法是另外做一个trigger用来产生效果,在技能触发了t之后,使用来显示效果的t生效,然后再在本段t中进行伤害,到了一定时间之后在将那个效果t禁止。
用j的话,我们可以利用trigger的工作原理,将两段代码合并在一起。
首先,我们需要一个使function立即执行并不等待function结束的功能,下面介绍这个功能的实现:
// 参数用来传递一个function
function RunFunctionAsTrigger takes code cFun returns nothing
//申请一个居于的trigger,因为我们只要求这个trigger运行一次,所以不需要全局变量
local trigger trg = CreateTrigger()
//把参数传递来的function作为新创建的trigger的action
call TriggerAddAction(trg, cFun)
//立即触发这个trigger,实际上就是让function作为另外一个进程运行,不需要等待执行结束
call TriggerExecute(trg)
//由于这个trigger已经在运行中,我们不再需要它了,所以马上毁掉这个trigger,并释放内存
call DestroyTrigger(trg)
set trg = null
endfunction
第二步,我们要想要在一定范围内持续出现一个效果,那么这个效果应该是每一定时间出现的,所以要创建第二个基础函数。另外考虑到,这个trigger持续一段时间后怎么结束呢?所以要让这个function有返回类型:
//传递一个function的参数,一个real型是说明多少秒之后执行,bool型说明是否只执行一次
function RunFunctionAsTriggerWithTimer takes code cFun, real timeout, boolean periodic
returns trigger
//与前面的过程一样,只对变动部分进行讲解
local trigger trg = CreateTrigger()
call TriggerAddAction(trg, cFun)
//给这个trigger注册一个事件,这个函数的意思就是用于多少秒的时候执行,是否只执行一次
call TriggerRegisterTimerEvent(trg,timeout,periodic)
//返回我们做好的这个trigger
return trg
endfunction
准备工作已经做好了,以后实现类似功能的时候,我们都可以调用这两个函数。使用j的好处就是,我们可以把大量重复的工作封装成function,用到这个功能的时候,只要调用这个function就可以了,而不用一遍一遍的复制,做重复的工作。
下面的是在一定范围内不断产生lich的frost nova的效果:
//用来产生效果,围绕一点(udg_fFSLocX,udg_fFSLocY)(两个都是全局变量),产生一个效果
function FSEffectWithTimer takes nothing returns nothing
//随机产生一个x和y,可以看成近似一个圆,因为出现在这个圆之外是个小概率事件
local real x = udg_fFSLocX+GetRandomReal(0,400)*SinBJ(GetRandomReal(-180,180))
local real y = udg_fFSLocY+GetRandomReal(0,400)*SinBJ(GetRandomReal(-180,180))
//产生效果
local effect eff = AddSpecialEffect("Abilities\\\\Spells\\\\Undead\\\\FrostNova\\\\FrostNovaTarget.mdl",x,y)
//等待2秒
call PolledWait(2)
//销毁效果,释放内存
call DestroyEffect(eff)
set eff = null
endfunction
//用于在技能中拿来RunFunctionAsTrigger的
function FrostSpaceEffect takes nothing returns nothing
//把效果函数注册成每0.1秒运行一次,即每0.1秒产生一个效果
local trigger trg = RunFunctionAsTriggerWithTimer(function FSEffectWithTimer, 0.1, true)
//等待5秒
call PolledWait(5)
//摧毁效果trigger,释放内存
call DestroyTrigger(trg)
set trg = null
endfunction
好了,现在你可以做一个技能,然后把上述的jass放到里面,看看效果如何了:)
* 补充:在全局变量的声明中,还有个size选项,那个选项实际上是假的,只是你自己输入一个数字提示自己这个数组应该有多大而以。jass为了防止mapper不熟练使用数组产生的bug,采用了自动增加数组长度的方式。这个好像要分情况吧,我试过用timerdialog的数组,只有[0] 和[1]是有效的其它都没效,这个很明显的size有关 |
|