找回密码
 点一下
查看: 6963|回复: 2

JASS入门教程

  [复制链接]
发表于 2008-10-27 21:33:52 | 显示全部楼层 |阅读模式
JASS简介

JASS是什么?
JASS(正确地说是JASS 2)是魔兽3的程序语言, 用于控制游戏和地图的进行,也是魔兽游戏和地图的基础。 地图编辑器中摆放的单位(Unit),区域(Region) ,触发(Trigger)……等,最终都会被翻译成JASS语言存在地图文件里,在游戏时被使用。
为什么要学习JASS语言?
少量功能只用GUI Trigger不能完成, 必须用JASS来实现,例如:
内存泄漏问题(Leak,指创建的临时游戏对象于使用过后没有被删除,增加计算机负担及游戏lag度的情形)。只有使用JASS提供的相关Destroy、Remove函数可以解决。
对指定玩家播放音效
在实现一些功能时使用JASS可以比触发(Trigger)写得更简洁、高效、快速,例如:
JASS可以使用区域变量,让多个触发彼此不互相混淆。GUI Trigger则必须使用数组及复杂的判断来达成。
JASS可以大幅简化if判断和loop循环的语法。GUI Trigger可能要很大串的if或者很多个触发串联起来。
一定要学JASS吗?
不一定。一般来说,单纯使用GUI Trigger,就可以达到大多数的功能。笔者建议建议对Trigger有一定程度了解的人稍微学些基本JASS写法,可以省下很多力气,且能让你的地图更不lag!!
 

一、JASS预备知识


在开始学习JASS之前,大家还是有作业要做的。回去自己写一句Trigger,再翻成JASS(Convert to Custom Text)看。看完了按复原(Ctrl+Z),再改再看。一般时间你就能弄熟语法了。这是入门,如果你没做的话,将来别人写JASS,你会很难看懂。

此外,也建议大家看一下blizzard.j和common.j档案里的子程序。基本上懂得越多,你写JASS就越有发挥的空间(记住,重要的不是背起来,而是会灵活运用。反正忘了怎么写,可以查那二个档案)。

好了,以下是正式的JASS教学。前半部在说明JASS的整个语法和结构,这些东西不但无聊(笔者也不是很懂程序的人,里面的数据大多是从别的地方偷来的),而且只要懂程序的人应该就能轻松上手,更重要的是,这对实际写JASS的帮助不大。因此,就像大家学Windows大都不看说明书一样,笔者建议大家先从第八章开始看,看完再回头看第二~七章。


二、JASS语言的源代码

JASS语言的扩展类型定义,基本函数和常数取值都是直接调用游戏的函数,他们被存放在war3x.mpq和war3patch.mpq内的Scripts\common.j和Scripts\common.ai中。JASS还有一些扩展函数, 放在war3x.mpq和war3patch.mpq内的Scripts\blizzard.j中。 common.ai则包含了用于设计AI的大量内部函数和扩展函数,但对于我们只用Jass进行普通脚本编写的人来说可以忽略这个档内的代码。 其中war3patch.mpq里的档案是最新版本的资料,可以使用mpq工具解出来。如果不会解也没有关系,这里提供解出来的1.15版的blizzard.j和common.j(请见附档)。


三、注释

任何写在//后面的都是注释内容,这也是JASS唯一的注释语法。后面的例子会多处用到这个注释符号,这个符号和后面的注释只是用于解释程序代码的功能,并不会被执行到。


四、数据类型

基本数据类型有:
boolean : 布尔, 只有true和false二个值

integer:整数。取值范围为 -2147483648到2147483647(2的31次方)
有4种形式的方法来写整数型的值:
1)全部为数字, 第一个数位不为0。即是10进制表示方法,如:23
2)全部为数字, 第一个数位为0。 这是8进制表示方法,如:023(相当于十位位的19)
3)0x(x可以是大写)开头。 后面全部为数字(16进制的数字包含A,B,C,D,E,F, 分别表示10,11,12,13, 14,15, 可以为小写),这是16进制表示方法。 如:0x23(相当于十位位的35)
4)用单引号括起4个字母,表示单位/技能编号对应的整数。 如:'Hpea'、'A001'

real :实数,取值范围为 1.5 x 10^(-45)到3.4 x 10^38

string :字符串,用双引号括起的若干个字母; 空字符串表示为""。字符串中遇到"可以用\"来表示这是一个字符串中的引号。如:"abc\"def\"", 就表示字符串abc"def"

code :代码,用于表示一个函数地址。 通常用于传值时传递一个函数。其值的形式为function <函数名>。

handle : 句柄,它指向内存的一个地址,用于表示一个较大的结构, 是很多数据类型的基类型。

除了基本数据类型,JASS还提供了大量扩展数据类型,都是以handle为基类型。例如:unit、trigger、timer、rect(Region)、location(Point)、……


五、表达式(expression)

表达式可以是直观可见的值,也可以是函数,计算式等。 如:

布尔: true, false
数值: 1, 3, 5565.33
字符串: "Xasfsfs", "Greedwind"
函数:GetTriggeringUnit()、GetUnitLoc(GetTriggeringUnit())
计算式:(a + b) * c + d

计算式中可用的运算有:

数学计算:+, -, *, / (注意整数除法的结果仍然为整数,小数点无条件舍去)
比较符号(传回boolean布尔值):>, <, >=, <=, ==, != 分别是大于、小于、大于等于、小于等于、等于(注意不是=)、不等于
布尔运算:and, or, not
字符串运算:+ 字符串相加,如"abc" + "def"的结果是"abcdef"


六、前缀

B社为了让程序运作顺畅,而且不让制作者自制的变量名称和War3内部的变量名称混淆。因此WE会自动为玩家自订的变量名称加上前缀。例如:
Variable:udg_
Region:gg_rct_
Trigger:gg_trg_
Unit:gg_unit_

等等...所以像:
set A = 1
翻成Jass以后会变成:
set udg_A = 1

假设你在一个名为Choose Hero的Trigger下加入这一条Event:
Unit - A unit enters HeroChoosePlace 8 <gen>
翻成JASS以后会变成:
 call TriggerRegisterEnterRectSimple( gg_trg_Hero_Choose, gg_rct_HeroChoosePlace_8 )

所以如果要在JASS中用到变量,请务必加上”udg_”之类的前缀


七、函数语法

Jass中定义一个函数的语法为:

function <函数名> takes <参数类型> <参数名> returns <传回类型>
 //函数主体
endfunction

其中<参数>可以有很多个,用逗号隔开,用于传递参数给函数。传递过去的参数一律被视为区域变量,<参数>和<传回类型>可以写nothing 表示不传入或传回任何值。

然后介绍函数基本语法return, 它必须写在函数里, 格式为:
return <表达式>

当函数返回类型为nothing时,后面不需要表达式,否则必须写表达式。它可以出现在函数的任何地方,可以出现不止一次,但是一旦碰到这一行,函数立即返回值并跳出该函数的运行。注意,return的值的类型必须和函数的返回类型相同。例如blizzard.j中:

//传回传入二实数中较小者
function RMinBJ takes real a, real b returns real
 if (a < b) then
   return a
 else
   return b
 endif
endfunction

//计算整数余数的程序(如18 mod 5 = 3)
function ModuloInteger takes integer dividend, integer divisor returns integer
 local integer modulus = dividend - (dividend / divisor) * divisor

 // If the dividend was negative, the above modulus calculation will
 // be negative, but within (-divisor..0). We can add (divisor) to
 // shift this result into the desired range of (0..divisor).
 if (modulus < 0) then
   set modulus = modulus + divisor
 endif

 return modulus
endfunction

注:现在的Jass有编译问题,它只会判断最后一个return返回的类型。而且官方明确表示永远不会修正这个bug(这可以做为War3资料转换工具),但是出于安全考虑,最好保证所有return的值的类型都符合。

函数(function)的调用:

Call Function(自变量1,自变量2,……)
→呼叫Function,传递自变量1,自变量2,……

例如:
 call RMinBJ ( 3.1, 5.4 )
 call ModuloInteger( 18, 5 )
 call RemoveUnit( GetTriggerUnit() )

*如果该函数不需要传递自变量(takes nothing),则后面可直接用(),如上面的GetTriggerUnit()


八、区域变量

local 变数形态 变量名称 (= 值)
→宣告一个区域变量名称(并设定初始值)

例:
 local real Duration
 local integer i = 1

※变数区分大小写!,例如Ability和ability视为不同的两个变数。


九、判断语句(if)

判断语句的基本语法为:
if <表达式> then
//代码段,可以为多行
endif

<表达式>结果必须为布尔型,因此通常用比较符号和布尔型运算进行复合运算,当表达式结果为真时。 执行中间的代码段。

此外,我们还可以判断语句在其中加入否则(else)和否则如果(elseif)的语句:

例如:
 if [条件A] then
  [动作A]
 else
  if [条件B] then
   [动作B]
  else
   if [条件C] then
    [动作C]
   else
    [动作D]
   endif
  endif
 endif

相当于:
 if [条件A] then
  [动作A]
 elseif [条件B] then
  [动作B]
 elseif [条件C] then
  [动作C]
 else
  [动作D]
 endif

例子还是blizzard.j的二个函数:

//传回传入二实数中较小者
function RMinBJ takes real a, real b returns real
 if (a < b) then
   return a
 else
   return b
 endif
endfunction


这个函数也可以改成:
function RMinBJ takes real a, real b returns real
 if (a < b) then
   return a
 endif
 return b
endfunction


//计算整数余数的程序(如18 mod 5 = 3)
function ModuloInteger takes integer dividend, integer divisor returns integer
 local integer modulus = dividend - (dividend / divisor) * divisor

 // If the dividend was negative, the above modulus calculation will
 // be negative, but within (-divisor..0). We can add (divisor) to
 // shift this result into the desired range of (0..divisor).
 if (modulus < 0) then
   set modulus = modulus + divisor
 endif

 return modulus
endfunction


十、循环(Loop)

循环是用来让计算机做相同或相似的动作多次,而不占用太多程序代码的写法。

循环语句的语法为:
loop
 //代码段,可以为多行,也可以不写
 exitwhen <表达式>
  //代码段,可以为多行,也可以不写
endloop

*<表达式>表示跳出循环的条件,结果必须为布尔值,当它为真时,程序会直接跳出循环执行endloop后面一行的语句。

*如果想要强执跳出循环,可以用exitwhen true

*exitwhen语句可以有多个,表示多个跳出条件;也可以不写,那就会成为无穷循环(直接用无穷循环的话会当机,平常使用时会加上Wait延迟以避免)


例如blizzard.j中:

//计算指定单位身上拥有的物品数
function UnitInventoryCount takes unit whichUnit returns integer
 local integer index = 0
 local integer count = 0

 loop
   if (UnitItemInSlot(whichUnit, index) != null) then
     set count = count + 1
   endif

   set index = index + 1
   exitwhen index >= bj_MAX_INVENTORY
   // bj_MAX_INVENTORY是blizzard.j中的整数常数,值为6
 endloop

 return count
endfunction


不知道有人发过没

评分

参与人数 1威望 +12 收起 理由
masker0925 + 12 本区对第一次在本区发教 ..

查看全部评分

发表于 2009-1-16 14:48:01 | 显示全部楼层
2)全部为数字, 第一个数位为0。 这是8进制表示方法,如:023(相当于十位位的19)
3)0x(x可以是大写)开头。 后面全部为数字(16进制的数字包含A,B,C,D,E,F, 分别表示10,11,12,13, 14,15, 可以为小写),这是16进制表示方法。 如:0x23(相当于十位位的35)

--------------------------------------------------------------------------------------------------------------

8进制的023 相当于十位位的20    然后16进制的0x23相当于十位位的36

版主 注意到错误了吗??
回复

使用道具 举报

发表于 2009-1-29 16:31:55 | 显示全部楼层
dividend - (dividend / divisor) * divisor

被除数-(被除数/除数)*除数
.....不是0么?
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-23 18:12 , Processed in 0.096665 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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