jass吧 关注:320贴子:783

【教程】JASS基础教程(转自魔兽地图编辑器吧)

只看楼主收藏回复

废话不多说啦,开始我们的教程:
**********************************************************
第一章 变量篇
学新的程序设计语言, 要先学它的变量类型
首先提醒大家: Jass2是区分大小写的, 如ABcd和ABCD是不一样的.
Jass2 变量类型
变量相当于物件的储存箱子, JASS2很多的变量类型只是个指针(变量地址).
使用变量前必须要首先声明变量类型和变量名称.
看个简单的例子:
local string my1stvar //声明1个字符型局部变量, 起名为my1stvar
set my1stvar = "GreedWind" //把"GreedWind"赋值给变量my1stvar
以后的程序中就可以直接引用/重新赋值my1stvar
变量(除了数组变量)可以在声明语句中初始化, 上面可以简化成:
local string my1stvar = "GreedWind" //声明字符型局部变量my1stvar并赋值为"GreedWind"
JASS2有哪些变量类型呢?
我们用WORLD EDITOR和Jass2变量类型做对照便一目了然了
WORLD EDITOR和JASS变量类型对照表:
World Editor 变量名 Jass变量类型
Boolean boolean 布尔型(用于真/假判断)
Destructible destructable 可破坏物
Dialog dialog 对话
Dialog Button button 按钮
Floating Text texttag 漂浮文字
Integer integer 数值
Item item 物品
Leaderboard leaderboard 排行榜
Player player 玩家
Player Group force 玩家组
Point location 位置(点)
Real real 真值型数字
Region rect 地区
Special Effect effect 特效
String string 字符串
Terrain Deformation terraindeformation 地形
Timer timer 计时器
Timer Window timerdialog 计时器窗口
Unit unit 单位
Unit Group group 单位组
Player Score playerscore 积分(1.13版新类型)
World Editor中的Order(命令) , Ability(技能) , Unit Type(单位类型), Destructible type(可破坏物类型) 和 Item type(物品类型) 在JASS中对应的变量类型实际上是integer。
可以用单引号'Xxxx'(Xxxx为在World Editor用View as raw data(以行数据查看)中看到的代码)表示这些类型的值
====================================================
Jass基本变量类型
integer
integer(数值)是的范围在 -2147483647 和 2147483647 之间的整数, 不能有小数位
在Jass中这个也是integer类型:
local integer blademaster = 'Obla'
'Obla'就是剑圣的代码
real
real是范围很大的32字节数字, 可以有小数位, 123456.33就是real
boolean
boolean的值只有true(真)和false(假), 多用于条件判断语句
if (条件==true)
then
(符合条件做某事)
else
(不符合条件就做另一件事)
endif
string
string是字符串变量, 可以是null(空值). 注意Jass的字符串是大小写区分的, 赋值时用双引号 "" 引用
handle
handle句柄, 可以是null(空值). 是用于指向Warcraft III定义的数据结构的指针. 比如上表中的location/player等除了integer/real/boean/string外的的变量实际上就是handle类型的子变量
code
code(程序代码), 可以是null(空值). 函数可以有code类型的传递参数, 表示该函数必须要有其他函数作为参数, 如:
function RunFunctionForAllPlayers takes code theFunction returns nothing



IP属地:四川1楼2011-11-17 20:33回复
    ***************************************************************
    Jass基础教程 第二章 语法篇
    本章主要介绍Jass的语句和语法.
    所有程序语言都是由特定的语句按语法规则组成, 基本和人类的自然语言没什么两样. 只是程序语言要有严谨的逻辑和语法, 而人类的语言可以是模糊不清不知所云的--就象我现在写的可以离题千里却蕴涵禅机, 让你费解一样.
    1) 赋值语句: set
    在第一章中我们已经接触过很多 set 语句了, 就是把 = 号右边的值赋个左边的变量
    语法格式:
    set 变量 = 值(表达式) // (A)
    set 数组变量[index] = 值(表达式) // (B)
    (A)是非数组变量的赋值语句.
    (B)数组变量的赋值语句, 其中[]中的index是指第index + 1个数组元素, index必须是integer类型的非负整数(可以是 0 )
    右边表达式的数据类型必须和左边的变量类型一致, 意思是说不能这样:set 人类 = 猪
    2) 调用函数: call
    用于调用函数. 当使用 call MyFunction(), 则运行了函数MyFunction
    语法格式:
    call 函数名(参数1, 参数2, ...., 参数n)
    ()号内的的用逗号(,)分割开的参数表. 如果被调用的函数要求输入参数, 则 call 语句中必须包含被调用函数要求输入参数类型相同数据类型或用空值.
    这句另人费解的话用人类的模糊语言来说就是:
    我(被调用的函数)要爱情(参数)才可以工作, 你(call 过程)就不要给我面包(传递的参数)
    这个是用Jass写的要爱情和面包但什么也不做而且还不高兴的空函数:
    function isHappy takes unit whichunit, item needbread returns boolean
    return false //函数返回值为"假"
    endfunction
    这个是用Jass写的总是高兴傻笑的空函数:
    function IamAlwaysHappy takes nothing returns boolean
    return true //函数返回值为(真)
    endfunction
    在函数中isHappy()要求传递2个参数, 参数数据类型分别是unit和item
    而函数IamAlwaysHappy()没有要求传递任何参数, 就不要多此一举给它爱情和面包了
    假设girl是unit类型变量, bread是item类型变量. 我们可这样调用:
    call isHappy(girl, bread) //给了爱情又给面包, 真是贴心人啊
    call isHappy(null, bread) //不给爱情只给面包, 不要饿死他
    call isHappy(girl, null) //给爱情不给面包, 为了爱情故, 我把面包抛
    call isHappy(null, null) //两者皆不给, 反正给了也返回"假"值
    call IamAlwaysHappy() //IamAlwaysHappy()没有要求任何参数
    //把PickaGirl()返回的值(unit类型或null)作为参数
    call isHappy(PickaGirl(), null)
    以下非法调用
    call isHappy() //非法调用
    call isHappy(girl) //非法调用
    call IamAlwaysHappy(girl) //非法爱情(不要给我二奶)
    3) 条件分支: if then else
    此语句效果就是: 如果条件成立, 那么做某事, 否则做另一件事
    语法格式:
    if 条件表达式1 then
    语句
    语句
    ...
    elseif 条件表达式2 then
    语句
    语句
    ...
    elseif 条件表达式3 then
    ...
    else
    语句
    语句
    ...
    endif
    其中条件表达式必须是布尔型(boolean)的值(真true和假false).
    这是某人的论坛签名JASS版, 他企盼着当他进入论坛时就....
    事件:单位进入论坛时
    if GetTriggerUnit() == 他 then
    call CreateNUnitsAtLoc( 1, GetUnitTypeId(美女),
    GetOwningPlayer(GetTriggerUnit()),
    GetUnitLoc(GetTriggeringUnit()), bj_UNIT_FACING )
    else
    endif


    IP属地:四川8楼2011-11-18 16:48
    回复
      4) 循环语句 loop 和循环退出语句 exitwhen
      loop 是执行循环的语句, exitwhen 则是控制循环退出的条件
      语法格式:
      loop
      exitwhen 条件表达式 //(A)在循环语句执行前检查循环条件
      ....
      endloop

      loop
      ....
      exitwhen 条件表达式 //(B)在循环语句执行后检查循环条件
      endloop
      同样的, 条件表达式必须布尔型的值
      (A)和(B)的差别相当于先买票再猴戏和看玩猴戏再给钱
      loop 语句可以不用exitwhen. 在没有exitwhen和return语句的情况下, loop ... endloop将成为永久循环(也称死循环), 一般应该避免死循环的产生.
      例:
      在Trigger Editor的GUI语句有: For Loop (Integer A) 的语句, 如
      For each (Integer A) from 1 to 10, do (Set unit_temp[(Integer A)] = 恐龙)
      转化成Jass就是:
      set bj_forLoopAIndex = 1
      set bj_forLoopAIndexEnd = 10
      loop
      exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
      set udg_unit_temp[bj_forLoopAIndex] = 'A001'
      set bj_forLoopAIndex = bj_forLoopAIndex + 1
      endloop
      5) 函数返回语句: return
      当执行到 return 语句时, 退出此函数, 程序运行点将返回到该函数的调用点.
      语法格式:
      return //(A)

      return 表达式 //(B)
      如果函数声明中没要求返回值, 则用(A), 如:
      function Iwanteverthing takes unit whichunit returns nothing
      return //上面函数定义中为returns nothing, 即是没要求返回值
      endfunction
      如果函数声明中要求返回值, 则用(B). 注意, 返回值类型必须和函数声明中要求返回值类型一致.即是声明中要求返回美女, 执行函数后就不能返回恐龙.
      function IamAlwaysHappy takes nothing returns boolean
      return true //函数定义要求返回布尔型的值
      endfunction
      ****************************************************************
      有问有答:
      ****************************************************************
      1) 本教程的表达式是指什么?
      表达式可以是直观可见的值, 如:
      数值型/真值型: 1, 3, 5565.33, ........
      字符串: "Xasfsfs", "Greedwind", ........
      布尔型: true, false
      单位: 'A001', 'Obla', ....
      ........
      也可以是函数, 计算式等, 如
      return GetTriggeringUnit() //返回触发单位
      //将触发单位所在点赋值给udg_loc
      set udg_loc = GetUnitLoc(GetTriggeringUnit())
      return a + b //返回 a + b 的值
      ****************************************************************
      2) Jass 有那些操作符?
      数学计算:
      + 加
      - 减
      * 乘
      / 除
      比较符号:
      >, <, >=, <= 分别是大于,小于, 大于等于, 小于等于
      == 等于
      != 不等于
      注意: 双=号(==)才是比较, 单=号是赋值, 不要搞错了!!!
      布尔条件
      and 条件和
      or 条件或
      not 否定条件
      使用:
      //条件表达式1和2都是true, 则下式为true, 否则下式为false
      条件表达式1 and 条件表达式2
      //在条件表达式1或2中只要有一个是true, 则下式为true
      条件表达式1 or 条件表达式2
      //不是表达式的值, 如 return (not true)则返回false
      not 表达式
      字符串操作符
      + 字符串叠加, 如"Greed" + "wind"的结果"Greedwind"
      3) Jass里还有什么特殊用途的字符和字串?
      // 注释, 以 //开头的语句将不执行
      () 函数参数列表, 如 call myfunction()
      [] 数组元素标记, 如 myarray[0]
      "" 字符串引用符, 如 "I love Greedwind"
      '' 单位/物品/技能代码引用符号, 如 'A001', 'Hpal'
      注意: Jass中可以用单引号括起4个字母表示数值型的值(integer)
      \ 跳脱符号(与Java/C一样),
      如: 在字符串里使用双引号 set mystring = "This is a \"string\""
      mystring 的值实际上是: This is a "string"
      如果直接 set mystring = "This is a "string"" 将出错
      因为""是字符串引用符
      0 用于数字前面, 则表示八进制的数, 如 016
      0x 用于数字前面, 则表示十六进制的数, 如 0x1FA0
      -------------------------------------------------------------------------------------------------------------
      本章结束
      相当重要的一个章节阿!希望大家好好学习!看了这章以后就应该了解jass的语言是怎么运行了的吧?
      看一边不懂没关系,多看几遍把它融会贯通,不信搞不定!


      IP属地:四川9楼2011-11-18 16:49
      回复
        ****************************************************************
        Jass基础教程 第三章 函数篇
        如果你仔细读完并读懂前面两章, 应该对Jass函数并不陌生了. 也许我在前两章写的太过综合紧凑, 所以写到这觉得没什么好写了. 不管怎样, 还是需要进一步深入了解Jass函数规范和注意事项.
        注意, 在此章中不是教你动手写Jass函数, 而是让你基本可以读懂别人写的Jass脚本-->如果你英文足够好而且不傻(这是Jass中布尔并立条件, 上一章提到过).
        关于如何写自己的第一个可以解决实际问题的Jass脚本, 你读完此章后可以研究common.j, Blizzar.j, common.ai这3个文件可以在此下载:
        http://www.vdisk.cn/shuangyaba?tag=%E6%95%99%E7%A8%8B%E9%9C%80%E8%A6%81&p=1
        也可以在Trigger Editor中把一些简单的触发器(Trigger)转化成自定义脚本, 因为事先知道程序逻辑, 这样读起来也比较容易.
        在教程最后, 我会尽量解释common.j, Blizzar.j, common.ai中公共函数/全局变量的作用(我真正研究Jass的时间不到2个星期, 所以水平有限, 难免有错误的理解)
        回头看看说不尽道不完, 乍看比等天还难的函数.
        1)函数定义要素
        语法格式
        function 函数名 takes 参数表 returns 返回类型
        局部变量声明
        局部变量声明
        ...
        表达式
        表达式
        表达式
        ...
        return 返回表达式
        endfunction
        其中:
        a) 定义函数的关键字有: function ... endfunction, takes, returns
        b) 函数名的首个字母不能是数字, 函数名中不能有第2章中所说的操作符, 特殊字符和多数非字母符号(如: 空格~`!@#$%^&*()-+=|\{}[];:'"<>?,./), 也不能使用中文. 函数命名要尽量简明易懂, 突出函数功能.
        c) 参数表是规定传递入函数的数据类型和参数数量, 作用是函数间的数据交换(输入), 参数之间用逗号( , )分开. 不能定义数组作为参数, 这点在的第一章已经做了说明.
        参数必须规定数据类型或者是无参数, 如
        function myfunction1 takes nothing returns nothing
        endfunction
        function myfunction2 takes integer creatnum, unit myunit returns boolean
        call CreateNUnitsAtLoc(creatnum, GetUnitTypeId(myunit), Player(1),
        GetUnitLoc(GetTriggeringUnit()), bj_UNIT_FACING )
        return true
        endfunction
        myfunction1为无参数的函数, 调用时不需要传递参数, 即是用 call myfunction1()
        myfunction1为2参数函数, 参数类型规定为 integer 和 unit. 调用myfunction2时必须同时传递数据类型分别integer和unit的参数, 或者传递入空值(参看第二章的举例).
        注意: 数字的空值为 0, handle(句柄)类型及其子类别的空值为 null. 关于handle类型请参看第一章. 我在本章背后会列出各数据类型所对应的空值.
        d) 返回类型是规定函数返回的数据类型, 作用同样是函数间的数据交换(输出), 可以用returns nothing 说明没有返回参数
        e) 局部变量声明必须写在函数开始部分. Jass总是先声明, 再使用. 如:
        function myfunction3 takes nothing returns nothing
        local integer i = 5
        local integer j = 10
        call myfunction2(i,美女 )
        sleep(360)
        call myfunction2(j,美女 )
        endfunction
        下面的函数是错误的:
        function myfunction3 takes nothing returns nothing
        local integer i = 5
        call myfunction2(i,美女 )
        local integer j = 10
        sleep(360)
        call myfunction2(j,美女 )
        endfunction
        f) 表达式是函数的骨干, 是逻辑的实现部分. 写好这部分, 需要对common.j, blizzar.j,commond.ai有一定的了解.


        IP属地:四川10楼2011-11-18 16:56
        回复

          g) 返回表达式的值必须和该函数声明时的返回类型一致, 不要声明返回为恐龙类型, 却偷梁换柱返回个美女. 返回值不能是数组.
          2) 程序执行入口函数
          每个Jass脚本文件都需要定义执行程序的入口函数
          在触发器脚本文件war3map.j中, config()和main()是入口函数.
          config()函数作用是在开始游戏之前初始化地图, 如按设计时指定点放置单位/可破坏物,初始化单位状态等.
          main()函数在游戏开始才执行.
          在AI脚本文件中, 用户需自定义main()函数作为该脚本文件的程序入口.
          脚本文件执行入口函数的固定格式:
          function main takes nothing returns nothing //触发器和AI脚本均使用
          function config takes nothing returns nothing //触发器脚本使用
          注意: 一张地图中只能有1个触发器脚本文件war3map.j, 此文件包含在w3m或w3x中
          一张地图中可以包含多个AI脚本文件, 输入AI脚本文件的目录为: \scripts\
          有问有答:
          *****************************************************************
          1) 什么是空值? 不同数据类型的空值是什么?
          当变量声明时, 如果在声明语句中不直接赋值, 则该变量的初始化值为空值, 表示没有赋值. 如:
          local unit myunit
          在上句声明中, myunit没有直接赋值, 那么myunit在声明后值是null
          以下是数据类型的空值对应表
          WORLD EDITOR和JASS变量类型对照表:
          World Editor
          变量名 Jass变量类型 空值
          Boolean boolean 布尔型(用于真/假判断) false
          Destructible destructable 可破坏物 null
          Dialog dialog 对话 null
          Dialog Button button 按钮 null
          Floating Text texttag 漂浮文字 null
          Integer integer 数值 0
          Item item 物品 null
          Leaderboard leaderboard 排行榜 null
          Player player 玩家 null
          Player Group force 玩家组 null
          Point location 位置(点) null
          Real real 真值型数字 null
          Region rect 地区 0
          Special Effect effect 特效 null
          String string 字符串 null
          Terrain Deformation terraindeformation 地形 null
          Timer timer 计时器 null
          Timer Window timerdialog 计时器窗口 null
          Unit unit 单位 null
          Unit Group group 单位组 null
          Player Score playerscore 积分(1.13版新类型) null
          ____________________________________________________________
          由上表可以看出, 除了integer, real的空值为 0 和 boolean 的空值为false以外, 其他数据类型的空值都是null. 原因很简单: 除了integer, real, boolean外, 其他数据类型都是handle(句柄)的子类型, handle类型的空值为null, 它的儿子们也跟着null到底了.
          2) 什么是common.j, Blizzard.j, common.ai?
          这3个文件都是支持War3 Jass的公共库文件, 文件里面包含和声明了所有(几乎是所有)Jass可以调用的函数和全局变量.
          common.j 是最基础的API库文件, 在Trigger Jass和AI Jass中都可以调用.
          Blizzard.j 包含使用Trigger Editor时生成的Trigger Jass中经常调用的库函数/全局变量, 实际上是基于common.j写的子函数. Blizzard.j只能在Trigger Jass中调用.
          common.ai 只能在AI Jass中调用, 它有AI中需要使用的函数和全局变量.
          注意: 在Trigger Jass中, 不能调用common.ai中的函数和全局变量; 同样地, 在AI Jass中, 也不能使用Blizzard.j的函数和全局变量.
          3) 如何获得最新的common.j, Blizzard.j, common.ai?
          在war3.mpq/war3x.mpq/war3patch.mpq都有common.j/Blizzard.j/common.ai, 要获得最新版本的文件, 可以用WINMPQ打开war3patch.mpq, 在WINMPQ右上方的输入框中输入: scripts\* ,如果你的war3patch.mpq没有"加密"过, 那么可以找到这3个文件. 如果是"加密"过的, 则需要把war3patch.mpq的文件全部解压到临时目录, 然后用Ultra-Edit中的在文件中搜索字符的功能寻找这3个文件.
          这三个文件可以在这里下载:
          http://www.vdisk.cn/shuangyaba?tag=%E6%95%99%E7%A8%8B%E9%9C%80%E8%A6%81&p=1
          


          IP属地:四川11楼2011-11-18 17:00
          回复
            4) 可以在自己的地图中使用自定义的common.j, Blizzard.j, common.ai吗?
            可以. 用输入管理器输入自定义的common.j, Blizzard.j, common.ai, 输入目录应为\scripts\. 这样, 运行地图中的脚本时, War3就不会到war3patch.mpq寻找这3个文件了而直接从地图中的\scripts\目录调用. 这样做的好处就是可以使库文件的同步一致. 通常, 版本相同的WAR3, 其库文件也相同, 所以多数时候不需要在地图中输入这3个文件. 但如果你更改了这3个基本文件来支持你的Jass, 或者确保为了库文件的一致性, 便可以在地图中输入基础库文件.
            5) 怎么解读公共库文件(common.j, Blizzard.j, common.ai)的函数/全局变量?
            Blizzard对函数/全局变量的命名是相当规范简明易懂的(当然需要一定的英文基础), 它定义的函数/全局变量的名基本上是英语语句. 我举些例子:
            native CreateUnit takes player id, integer unitid, real x, real y, real face returns unit
            本地函数CreateUnit() 即是Create Unit, 意思为创建单位, 从参数表(takes 和 returns之间的声明)来看, 这个函数需要输入玩家, 单位编码, 坐标x, 坐标y, 方向角度, 返回值是单位类型变量.
            从函数的名字和参数表, 可以猜测/确认CreateUnit()是用来在地图的x/y坐标中为指定玩家创建指定单位, 并且使创建单位面向所定义的角度, 返回值是创建单位.
            在地图入口函数main()中, CreateUnit()被大量调用, 用来重现地图设计时用WORLD EDITOR(GUI)放置的单位.
            注意: 就如前面所说过, integer可以用单引号括起4个英文字母/数字来表示. 所以CreateUnit()中integer unitid参数可以用 'Xxxx'来表示. 如:
            set u = CreateUnit( Player(5), 'ndgt', -2944.0, -3136.0, 270.000 )
            上句意思是为玩家5在地图坐标(-2944.0, -3136.0)中创建编码为'ndgt'的单位, 并使创建单位面向角度为270度, 然后把创建单位保存在变量u中.
            我总结下Blizzard函数名/全局变量名的规律:
            a) 前坠Get 取得某属性, 此类函数一般有返回值
            b) 前缀Set 设置某属性
            c) 前缀Is 是否判断, 此类函数返回类型都是boolean, 返回true或false
            d) 中间有2 数据类型转化函数, 如S2I(), I2R, I2S()等
            e) 有Item/Unit/... 肯定是与物品/单位/...相关的函数
            f) 后缀BJ 此函数肯定是在Blizzard.j中定义的, 不能在AI中使用.
            g) 前缀bj_ 在Blizzard.j中定义声明的全局常量(常量是指定义并赋值后不能再改变的值)
            h) 前缀Create 创建
            i) 前缀Remove 移除
            k) 全部大写 在common.j中定义声明的全局常量
            6) 实用问题: 如何创建外观随机可变的地图?
            上面说过, main()是地图入口函数, 在main()调用了一些再现地图设计时原貌的子函数如CreateAllUnits(). 因此, 我们可以在CreateAllUnits()中加入随机函数GetRandomInt()来控制单位/物品/可破坏物等初始化过程.
            我们可以用WINMPQ打开要修改的地图, 提取war3map.j来修改main()函数及其相关函数. 修改完war3map.j后, 再用WINMPQ导入修改后的war3map.j.
            a) 函数修改/增加方法:
            这是3C地图中的CreateAllUnits()函数
            function CreateAllUnits takes nothing returns nothing
            call CreateNeutralPassiveBuildings() //用户自定义函数
            call CreatePlayerBuildings() //用户自定义函数
            call CreateNeutralHostile() //用户自定义函数
            call CreateNeutralPassive() //用户自定义函数
            call CreatePlayerUnits() //用户自定义函数
            endfunction
            注意: CreateAllUnits()也不是库函数, 是用户自定义函数):
            我们可以根据CreateAllUnits()创建另一个函数:
            function CreateAllUnitsRandom takes nothing returns nothing
            


            IP属地:四川12楼2011-11-18 17:01
            回复
              // randomint 是 1,2,3中的随机数
              local integer randomint = GetRandomInt(1, 3)
              call CreateNeutralPassiveBuildingsRandom(randomint)
              call CreatePlayerBuildingsRandom(randomint)
              call CreateNeutralHostileRandom(randomint)
              call CreateNeutralPassiveRandom(randomint)
              call CreatePlayerUnitsRandom(randomint)
              endfunction
              因为原来调用的函数都是无参数函数, 所以相应的函数应该做些修改, 如:
              //创建玩家单位, 以CreatePlayerUnits()为蓝本增加新函数
              function CreatePlayerUnitsRandom takes integer randomint returns nothing
              //此函数以CreateUnitsForPlayer0为蓝本增加新函数
              call CreateUnitsForPlayer0Random(randomint)
              ......
              endfunction
              //创建中立敌对单位
              //此函数以CreateNeutralHostile为蓝本增加新函数
              function CreateNeutralHostileRandom integer randomint returns nothing
              local player p = Player(PLAYER_NEUTRAL_AGGRESSIVE)
              local unit u
              local integer unitID
              local trigger t
              local real life
              //加入条件控制, 根据随机数创建不同单位组合.
              if randomint == 1 then
              //可掉宝物的单位
              set u = CreateUnit( p, 'nC26', -6533.2, 445.1, 220.680 )
              set t = CreateTrigger( )
              call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_DEATH )
              call TriggerRegisterUnitEvent( t, u, EVENT_UNIT_CHANGE_OWNER )
              call TriggerAddAction( t, function Unit000012_DropItems )
              //不掉宝物单位
              set u = CreateUnit( p, 'nelb', -373.5, 3533.4, 44.518 )
              set u = CreateUnit( p, 'nomg', -233.6, 3436.2, 140.871 )
              elseif randomint == 2 then
              //不掉宝物单位
              set u = CreateUnit( p, 'a001', -373.5, 3533.4, 44.518 )
              set u = CreateUnit( p, 'a002', -233.6, 3436.2, 140.871 )
              else
              ......
              endif
              endfunction
              别忘了修改main()
              function main takes nothing returns nothing
              ........
              //call CreateAllUnits() //原版的单位初始化函数, 不再使用
              call CreateAllUnitsRandom() //使用新的单位初始化函数
              ........
              endfunction
              b) 初始设置复制方法:
              问题的关键就是, 这么多初始单位, 怎么样修改起来不累人?
              这里介绍一种方法:
              1. 先把要修改的地图复制
              2. 修改复制地图初始单位的类型/位置/宝物等, 删除所有TRIGGER, 并保存
              3. 用WINMPQ打开复制地图, 提取war3map.j
              4. 复制war3map.j中对应函数中创建单位的语句
              5. 把复制的语句粘贴在原地图中相应函数的适当位置
              6. 重复1-5, 复制更多的随机初始化设置
              注意: 如果用World Editor再次修改并保存, main()将使用GUI默认生成的call CreateAllUnits(), 而不是call CreateAllUnitsRandom(). 此时还需要打开war3map.j修改main()函数.
              同样, 使可破坏物等初始设置有随机变化也可以用此方法.
              看完这一章节就离胜利不远啦~继续努力啊!
              


              IP属地:四川13楼2011-11-18 17:01
              回复
                ****************************************************************
                Jass基础教程 第四章 库函数
                这章是Jass基础教程中最难的部分, 也是最实用的部分.
                Jass的关键字有26个, 跟英文字母一样多. 我们来回顾一下:
                and, array, call, constant, else, elseif, endfunction, endglobals, endif, endloop, exitwhen, extends, function, globals, if, local, loop, native, not, or, return, returns, set, takes, type, then
                以此看来, Jass是语法结构最简单的一种准计算机语言. Jass实现功能基本依靠调用common.j, blizzad.j, common.ai中的库函数.
                本章所述内容不属于Jass语法部分, 最主要讲述:
                触发器(Triggers)
                跨脚本通讯(Inter-Script Communication)
                队列(Enumerations)
                队列过滤器(Filters)
                线程(Threads)
                1) 触发器(Triggers)
                触发器用于地图触发器脚本(Trigger Jass), 用于响应特定事件. 它是种响应信号(callback), 触发器不能应用于AI, 即是说AI Jass中不能有触发器的语句.
                触发器包含创建触发器, 设置触发条件, 设置动作.
                a)创建触发器
                触发器的数据类型为trigger(触发器), 是handle(句柄)的子类型.
                创建触发器的函数在common.j中的声明:
                native CreateTrigger takes nothing returns trigger
                参数:
                nothing //无参数
                返回:
                trigger //返回创建的触发器
                使用格式: set 表达式 = CreateTrigger()
                其中表达式是trigger类型的变量
                新数据类型:
                trigger类型: 是handle的子类型, 用于调用和处理触发器
                b)触发事件
                触发事件的数据类型为event(事件). 可以引起触发响应的触发器必须先在游戏中注册触发事件, 用于监视游戏事件发生.
                注册触发事件的函数在common.j中的声明:
                native TriggerRegister*Event takes
                trigger whichTrigger, ... returns event
                函数名:
                根据事件对象的不同, 有不同的事件响应. TriggerRegister*Event中的 * 号为对象名, 如: TriggerRegisterUnitEvent, TriggerRegisterEnterRegion 等, 注册不同对象的事件要求传递相应指定对象作为参数, 有些事件注册要求传递下面所说的过滤器(Filters)
                参数:
                trigger whichTrigger //触发器变量
                ... //相应指定对象的变量
                返回:
                event //返回该事件
                使用方法(举注册单位事件的例子):
                call TriggerRegisterUnitEvent(哪个触发器, 哪个单位, 哪种类型的单位事件)
                新数据类型:
                event //事件
                c)触发条件
                触发条件是一组布尔表达式(boolexpr)数据, 它的数据类型为条件函数(conditionfunc), 是布尔表达式(boolexpr)类型的子类型.
                建立触发条件的函数在common.j中的声明:
                native Condition takes code func returns conditionfunc
                参数:
                code func //函数代码作为参数
                返回:
                conditionfunc //返回建立的条件
                其中takes code func是指需要函数代码func作为参数, 参数函数 func 必须的声明格式必须是: takes nothing returns boolean. 即是说, 用作参数的函数本身应该是无参数且返回值为布尔型(boolean).
                使用格式: set 表达式 = Condition(function 布尔型函数名)
                其中表达式是条件函数(conditionfunc)
                新数据类型:
                boolexpr 布尔表达式
                conditionfunc 条件函数, 是布尔表达式的子类型
                比如:
                function Girl1 takes nothing returns boolean
                ...
                return true
                endfunction
                function Girl2 takes integer i returns boolean
                


                IP属地:四川14楼2011-11-18 17:04
                回复
                  ...
                  return true
                  endfunction
                  function Girl3 takes nothing returns nothing
                  ...
                  return
                  endfunction
                  // 假设 c 为conditionfunc类型变量
                  set c = Condition(function Girl1) //(A)
                  set c = Condition(function Girl2) //(B) 本身要求参数
                  set c = Condition(function Girl3) //(C) 返回值不是boolean类型
                  解释: Girl1() 是无参数且返回为boolean的函数, 可以用作 Condiction() 中的参数函数code func. 而Girl2() - 本身要求参数, Girl3() - 返回值不是boolean类型, 所以(B)(C)函数不可作为Condiction()的参数.
                  在第一章变量篇中我没有详细说明code类型的数据, 因为怕读者不能理解. 现在我说明下code类型数据. 我们用例子说明, 比如:
                  call myfuction1(IsGirl()) //(A)
                  call myfuction2(function IsGirl()) //(B)
                  (A)和(B)之间有什么不同呢? 按我的理解: (A)(B)都把IsGirl()运行返回后的值当作myfunction1()/myfunction2()的参数. IsGirl()在(A)中是一次性的处理过程. 而(B)是创建了一个运行IsGirl()逻辑的监视线程, 只要线程没给清除/终止, IsGirl()将一直监视变化. 注意这里所说的线程跟下面要说的AI线程是两码事.
                  d) 增加触发条件:
                  触发条件可以用TriggerAddCondition()增加
                  增加触发条件的函数在common.j中的声明:
                  native TriggerAddCondition takes trigger whichTrigger,
                  boolexpr condition returns triggercondition
                  参数:
                  trigger whichTrigger //触发器变量
                  boolexpr condition //触发条件变量
                  返回:
                  triggercondition //返回该触发条件的handle(句柄)
                  使用格式:
                  set tc = TriggerAddCondition(触发器, 触发条件)
                  其中 tc 为triggercondition类型变量
                  新数据类型:
                  triggercondition 触发条件句柄
                  (注意: 触发条件和上面要说的触发事件是不一样的!!!)
                  例:
                  这是增加/移除/改变触发条件的例子
                  //文件头声明个全局变量tc
                  globals
                  ...
                  triggercondition tc = null
                  trigger mytrigger = null
                  ...
                  endglobals
                  function Girl takes nothing returns boolean
                  ...
                  return true
                  endfunction
                  function notGirl takes nothing returns boolean
                  ...
                  return false
                  endfunction
                  //为 mytrigger 增加触发条件
                  function addcondition takes nothing returns nothing
                  ...
                  set mytrigger = CreateTrigger()
                  set tc = TriggerAddCondition(mytrigger, Condition(function Girl))
                  ...
                  endfunction
                  //因为tc是mytrigger触发条件的句柄, 把tc清空便清除了指向的触发条件.
                  function removecondition takes nothing returns nothing
                  ...
                  set tc = null
                  ..
                  endfunction
                  //改变 mytrigger 的触发条件
                  function modifycondition takes nothing returns nothing
                  ...
                  set tc = null //先把原来的触发条件移掉
                  set tc = TriggerAddCondition(mytrigger, Condition(function noGirl))
                  ...
                  endfunction
                  e)触发器动作
                  触发器动作是当指定事件发生并符合触发条件的执行的语句.
                  增加触发器动作的函数在common.j中的声明:
                  native TriggerAddAction takes trigger whichTrigger,
                  code actionFunc returns triggeraction
                  参数:
                  trigger whichTrigger //触发器变量
                  code actionFunc //执行函数
                  注意: 执行函数必须是无参数无返回值(takes nothing returns nothing)的函数
                  


                  IP属地:四川15楼2011-11-18 17:04
                  回复
                    返回:
                    triggeraction //触发动作
                    新数据类型:
                    triggeraction //触发动作, handle字类
                    把有关触发器主要函数糅合在一起, 我们来看个例子, 研究下触发器是怎么创建的:
                    //文件头声明全局变量mytrigger
                    //假设mytrigger是监视单位死亡事件的触发器
                    globals
                    ...
                    trigger mytrigger = null
                    ...
                    endglobals
                    //判断是否掉物品
                    function isDrop takes nothing returns boolean
                    local boolean conditcion
                    ...
                    if conditcion = true then
                    return true
                    else
                    return false
                    endif
                    endfunction
                    //掉物品
                    function DropItems takes nothing returns nothing
                    //获得触发单位
                    local unit trigUnit = GetTriggerUnit()
                    ....
                    call UnitDropItem( trigUnit, 'IC21' )
                    ...
                    endfunction
                    function ThisIsMyTrigger takes nothing returns nothing
                    local unit u
                    //在-5630.5, -4723.1坐标为玩家5创建单位'n00I', 面向90.260度
                    set u = CreateUnit(Player(5), 'n00I', -5630.5, -4723.1, 90.260 )
                    //创建触发器(相当于mytrigger的初始化)
                    set mytrigger = CreateTrigger()
                    //为mytrigger注册触发器事件, 让游戏系统监视所创建单位u的死亡事件
                    //EVENT_UNIT_DEATH是common.j中定义的常量
                    call TriggerRegisterUnitEvent( mytrigger, u, EVENT_UNIT_DEATH )
                    //为mytrigger增加触发条件
                    //isDrop是无参数返回为布尔值的函数
                    set tc = TriggerAddCondition(mytrigger, Condition(function isDrop))
                    //为mytrigger增加触发器动作 - 掉宝物
                    //DropItems是无参数无返回值的函数
                    call TriggerAddAction(mytrigger, function DropItems )
                    ...
                    endfunction
                    可以看出, 创建触发器顺序是:
                    1. 触发器初始化 - CreateTrigger()
                    2. 触发器事件注册 - TriggerRegister*Event()
                    3. 定义触发条件(可选) - TriggerAddCondition()
                    4. 触发器动作 - TriggerAddAction()
                    注意:
                    1. 创建触发器必须先用CreateTrigger()初始化.
                    2. 没有注册事件的触发器只是个处理过程, 不会响应事件执行程序
                    3. 触发器可以不加触发条件, 因为可以用触发动作调用的函数来控制逻辑.
                    


                    IP属地:四川16楼2011-11-18 17:04
                    回复
                      ******************************************************************
                      2)线程(Threads)
                      (这部分属于AI部分, 作为入门者做一般性了解就行了, 因为AI都是纯JASS写的, 也没有真正好的AI EDITOR. 本人也对此一知半解, 关于AI的文章也不多, 没什么好参考的.)
                      线程只应用于AI脚本(AI JASS), 不能用于触发器脚本(Trigger Jass). 通常, 当AI脚本开始运行时只创建一个线程, 创建更多的线程可以用comman.j的本地函数:
                      native StartThread takes code func returns nothing
                      调用 call StartThread(function myfunc) 将创建一个从函数myfunc开始执行的线程.
                      每个玩家最多可以拥有6个线程, 包括一开始执行的主线程. 当一个玩家有6个线程数时, 调用StartThread()的语句将被忽略. 线程不能回收, 当你为某玩家创建了5个自定义线程, 将无法为该玩家创建更多的线程.
                      当新线程创建时, 线程立即生效. 当线程让步执行时, 创建此线程的父线程将继续执行.
                      在同一玩家中的所有线程都共享全局状态(包括变量). 即是修改某个全局变量, 修改后的值在此玩家的所有线程中都是可见的.
                      线程在以下的情况让步执行, 返回父线程
                      a) 当线程中的操作码(opcode)超出限制, 线程会自动休眠 1 秒
                      b) 当线程中用使用 Sleep(n), 线程将休眠 n 秒, 然后继续执行.
                      线程在以下情况会中止, 返回父线程
                      a) 如果 call StartThread(null)中, 线程中止
                      b) 当线程的主函数返回, 线程中止.
                      (StartThread()中之间调用的函数就是主函数.)
                      c) 当线程中使用没有声明的变量, 线程中止. 在使用之前, 变量必须声明.
                      d) 当线程中出现零为被除数时, 线程中止
                      e) 线程主函数出现语法错误.
                      注意: 虽然AI脚本可以使用大部分common.j的库函数, 但有些类型的函数在AI不能正常工作, 如:
                      a) 返回字符串类型(string)的本地函数, 如I2S(), SubString()等
                      b) 需要以code, trigger, boolexpr 等类型数据为参数的本地函数, 如触发器函数, 队列函数(ForGroup, 等)
                      注意: AI中不可以使用Blizzard.j的函数, 触发器中也不可以使用common.ai的函数, AI和触发器都可以使用common.j的函数(当然, 对于AI, 还受上面所说的限制)
                      common.ai和common.j是写AI时可以调用和参考库文件, 要研究AI, 先去读这2个文件.
                      


                      IP属地:四川17楼2011-11-18 17:04
                      回复
                        ******************************************************************
                        3) 跨脚本通讯(Inter-Script Communication)
                        在游戏中, 可能会有多个独立的Jass脚本文件同时运行. 比如在对战地图中的游戏, 运行触发器脚本文件的同时, 也可能运行了每个电脑玩家的AI脚本文件. 每个脚本文件之间的全局变量不是共享的. 所以, 一个电脑玩家的AI脚本中设置的全局变量不会影响另一个电脑玩家的AI脚本的执行.
                        触发器脚本也不可以和AI脚本共享全局变量. 但可以用传递命令的方法进行脚本之间的数据交换. 命令由一对数值型数据(integer)组成: 命令值(command value)和数据值(data value).
                        从触发器脚本向AI脚本发出通讯命令, 可以使用common.j中定义的以下本地函数:
                        native CommandAI takes player num,
                        integer command, integer data returns nothing
                        参数:
                        player num //玩家
                        integer command //命令
                        integer data //命令数据
                        以下是AI中使用的common.j函数, 注意: 每个电脑玩家都会有独立的AI脚本, 所以, 以下函数都没有要求玩家作为函数参数.
                        每个电脑玩家都有命令堆来堆放接受到的命令. 想知道有多数个命令堆放在命令堆, 可以用下面的函数:
                        native CommandsWaiting takes nothing returns integer
                        参数: 无
                        返回: 命令堆的命令数(integer)
                        获得存放在命令堆中最顶端的命令():
                        //返回命令
                        native GetLastCommand takes nothing returns integer
                        //返回命令数据
                        native GetLastData takes nothing returns integer
                        上面2个函数都不会移除命令堆中的命令, 要移除堆中的命令, 可以用:
                        native PopLastCommand takes nothing returns nothing
                        ******************************************************************
                        4) 队列(Enumerations)
                        虽然JASS不能自定义数据结构(因为JASS缺少指针操作符), 但API库中提供了一些实现队列操作的函数. 如一组单位为单位组(group), 一组玩家为势力(force), 虽然一组可破坏物没有明确定义它的数据类型, 但也可以用API函数来操作.
                        单位组和势力的操作函数很类似.
                        单位组处理函数
                        // 初始化单位组
                        native CreateGroup takes nothing returns group
                        // 在指定单位组中增加指定单位
                        native GroupAddUnit takes group whichGroup, unit whichUnit returns nothing
                        // 在指定单位组中移除指定单位
                        native GroupRemoveUnit takes group whichGroup, unit whichUnit returns nothing
                        势力处理函数
                        // 初始化势力
                        native CreateForce takes nothing returns force
                        // 在指定势力中增加指定玩家
                        native ForceAddPlayer takes force whichForce, player whichPlayer returns nothing
                        // 在指定势力中移除指定玩家
                        native ForceRemovePlayer takes force whichForce, player whichPlayer returns nothing
                        JASS不能直接操作队列里面的元素, 它是通过callback类型的函数来实现对队列的操作:
                        // 对指定单位组中的每个单位都运行指定callback函数callback
                        // (对应GUI语言的For Each Unit in <Group>)
                        native ForGroup takes group whichGroup, code callback returns nothing
                        // 对指定势力中的每个玩家都运行指定callback函数callback
                        // (对应GUI语言的For Each Player in <Force>)
                        native ForForce takes force whichForce, code callback returns nothing
                        输入上面两个函数的callback函数必须是无参数无返回值函数(takes nothing returns nothing)
                        


                        IP属地:四川18楼2011-11-18 17:08
                        回复

                          同样, 操作可破坏物也可以用在区域内的可破坏物作为队列, 可以以用类似的方法:
                          // 在指定区域r内符合指定过滤器filter的都运行指定callback函数actionFunc
                          // (过滤器见下节的讲解)
                          native EnumDestructablesInRect takes rect r,
                          boolexpr filter, code actionFunc returns nothing
                          在callback函数, 可以用下面的函数获得队列中的下一个元素:
                          // 获得单位组中的下一个单位
                          // (对应GUI语言的Pick Every Unit in <Group>)
                          constant native GetEnumUnit takes nothing returns unit
                          // 获得势力中的下一个玩家
                          // (对应GUI语言的Pick Every Player in <Force>)
                          constant native GetEnumPlayer takes nothing returns player
                          // 获得可破坏物组中的下一个可破坏物
                          // (对应GUI语言的Pick Every Destructables in <Region>)
                          constant native GetEnumDestructable takes nothing returns destructable
                          注意: AI中不支持队列函数的使用.
                          这是杀死单位组中所有单位的实例:
                          // 这是callback函数, 无参数并无返回值
                          function KillGroupCallback takes nothing returns nothing
                          // 获得单位组中的下一个单位
                          local unit nextUnit = GetEnumUnit()
                          // 杀死该单位
                          call KillUnit(nextUnit)
                          endfunction
                          // 调用ForGroup
                          // 对单位组groupToKill中的每个单位都运行函数KillGroupCallback
                          call ForGroup(groupToKill, function KillGroupCallback)
                          另一个经常是用的例子是在队列中查找特定条件的元素. 不幸的是, 因为JASS只支持callback函数来处理队列中的元素, 所以只有用全局变量来保存不同单位的属性. 下面是找出单位组里生命最高的单位的例子:
                          //定义全局变量
                          globals
                          //用于储存两单位比较后较高的生命值, 初始化为 0
                          real mostLifeSoFar
                          //用于储存两单位比较后有较高生命值的单位, 初始化为 null
                          unit unitWithMostLifeSoFar
                          endglobals
                          //比较单位生命值的callback函数
                          function MostLifeCallback takes nothing returns nothing
                          //获得单位组中的下一个单位
                          local unit nextUnit = GetEnumUnit()
                          //获得单位属性 - 生命
                          //UNIT_STATE_LIFE是common.j中定义的常量
                          local real life = GetUnitState(nextUnit, UNIT_STATE_LIFE)
                          //比较生命值
                          if life > mostLifeSoFar then
                          //把较大的生命值储存
                          set mostLifeSoFar = life
                          //把有较大生命的单位储存
                          set unitWithMostLifeSoFar = nextUnit
                          endif
                          endfunction
                          ...
                          //初始化全局变量的值为空值
                          set mostLifeSoFar = 0
                          set unitWithMostLifeSoFar = null
                          //调用ForGroup
                          //对单位组myGroup中的每个单位都运行函数MostLifeCallback比较生命
                          call ForGroup(myGroup, function MostLifeCallback)
                          //上句运行后, 全局单位类型变量unitWithMostLifeSoFar便指向单位组myGroup中最高生命的单位, 或:
                          //如果单位组myGroup是空组, 那么unitWithMostLifeSoFar便是空值null
                          ...
                          当然, 实现队列操作, 也可以用数组的方法来处理. 但, 数组不能使用紧接着要说的队列过滤器, 也不能定义数组中包含数组. 这些都是队列所拥有的优势, 如可以有数组型的单位组(相当于数组中包含数组), 也可以用队列过滤器.
                          *****************************************************************
                          5)队列过滤器(Filters)
                          队列过滤器用于在队列中增加符合条件的元素. 比如, 在创建一个法力小于20的单位组时, 便可以用队列过滤器(Filters)来创建.
                          


                          IP属地:四川19楼2011-11-18 17:08
                          回复

                            //在单位组中增加指定单位名为unitname, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsOfType takes group whichGroup, string unitname,
                            boolexpr filter returns nothing
                            //在单位组中增加指定玩家为whichPlayer, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsOfPlayer takes group whichGroup, player whichPlayer,
                            boolexpr filter returns nothing
                            //在单位组中增加指定玩家为whichPlayer, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsOfTypeCounted takes group whichGroup, string unitname,
                            boolexpr filter, integer countLimit returns nothing
                            //在单位组中增加指定区域为r, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsInRect takes group whichGroup, rect r, boolexpr filter
                            returns nothing
                            //在单位组中增加countLimit个指定区域为r, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsInRectCounted takes group whichGroup, rect r,
                            boolexpr filter, integer countLimit returns nothing
                            //在单位组中增加在指定点坐标范围之内, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsInRange takes group whichGroup, real x, real y,
                            real radius, boolexpr filter returns nothing
                            //在单位组中增加在指定点范围之内, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsInRangeOfLoc takes group whichGroup,
                            location whichLocation, real radius, boolexpr filter returns nothing
                            //在单位组中增加指定个数, 在指定点坐标范围之内, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsInRangeCounted takes group whichGroup, real x, real y,
                            real radius, boolexpr filter, integer countLimit returns nothing
                            //在单位组中增加指定个数, 在指定点范围之内, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsInRangeOfLocCounted takes group whichGroup,
                            location whichLocation, real radius, boolexpr filter,
                            integer countLimit returns nothing
                            //在单位组中增加被指定玩家选中, 并符合队列过滤器filter的单位
                            native GroupEnumUnitsSelected takes group whichGroup, player whichPlayer,
                            boolexpr filter returns nothing
                            类似地, 对于势力也有相应的操作函数
                            //在势力中增加符合队列过滤器filter的玩家
                            native ForceEnumPlayers takes force whichForce, boolexpr filter returns nothing
                            //在势力中增加指定个数, 并符合队列过滤器filter的玩家
                            native ForceEnumPlayersCounted takes force whichForce, boolexpr filter,
                            integer countLimit returns nothing
                            // Add all units that are allies of 'whichPlayer' that satisfy 'filter'
                            //在势力中增加和指定玩家同盟, 并符合队列过滤器filter的玩家
                            native ForceEnumAllies takes force whichForce, player whichPlayer,
                            boolexpr filter returns nothing
                            //在势力中增加和指定玩家敌对, 并符合队列过滤器filter的玩家
                            native ForceEnumEnemies takes force whichForce, player whichPlayer,
                            boolexpr filter returns nothing
                            以上函数中boolexpr filter在本章第1)节触发器中有提到, 通常可以使用过滤器(filterfunc).过滤器跟触发器的条件函数(conditionfunc)类似. 创建过滤器可以用以下语句:
                            native Filter takes code func returns filterfunc
                            其中参数函数code func必须是无参数返回值为布尔值的函数(takes nothing returns boolean), 过滤器用于在创建队列时增加额外的条件. 在过滤器中, 可以使用下面的函数获得下一个待查的单位/玩家/不可破坏物:
                            //获得下个待查单位
                            constant native GetFilterUnit takes nothing returns unit
                            //获得下个待查玩家
                            constant native GetFilterPlayer takes nothing returns player
                            //获得下个待查可破坏物
                            constant native GetFilterDestructable takes nothing returns destructable
                            我们来看个创建一个法力小于20的单位组例子:
                            //过滤函数, 是无参数返回值为布尔值的函数
                            function LessThan20ManaCallback takes nothing returns boolean
                            //获得下个检查的单位
                            local unit nextUnit = GetFilterUnit()
                            //检查待查单位的法力是否小于20
                            //小于20则返回true, 否则返回false
                            return GetUnitState(nextUnit, UNIT_STATE_MANA) < 20
                            endfunction
                            ...
                            //创建过滤器, 过滤函数是LessThan20ManaCallback
                            local filterfunc myFilter = Filter(function LessThan20ManaCallback)
                            //在单位组中增加指定区域, 符合过滤条件的单位
                            call GroupEnumUnitsInRect(myGroup, someRect, myFilter)
                            // Destroy the filter if we are not going to use it again
                            //不再使用过滤器, 销毁过滤器, 避免内存泄漏
                            call DestroyFilter(myFilter)
                            ...
                            第四章要是看完应该可以自己做个1,2,3了吧?
                            呵呵
                            


                            IP属地:四川20楼2011-11-18 17:08
                            回复

                              Jass基础教程--(第五章 工具篇)(由于工具下载的链接都不能用了所以不复制超链接了,想要的话可以在百度里查到。)
                              1) 下载Ultra-Edit 32-Bit.
                              2) 下载wordfile.建议使用, 可以编辑其他语言
                              3) 下载JASS的语法检查器
                              4) 下载common.j, blizzard.j 和 common.ai
                              这3个文件可以用WINMPQ在war3patch.mpq中解压出来
                              把解压出来的common.j, blizzard.j 和 common.ai 放到C:\PJASS目录(或你指定的JASS语法检查器所在的目录)
                              5) Ultra-Edit的设置:
                              在Ultra-Edit中, 菜单: 高级(Advanced)-> 配置(Configuration) -> 语法高亮(Syntax-Highlighting) -> 浏览(Browse) -> 选择你解压出的war3wordfile.txt -> 应用(Apply)
                              ->选择所有可选项(打钩)
                              JASS的语法检查器的引用:
                              高级(Advanced)-> 工具配置(Tools Configuration) -> 在命令行填写(路径需指向你的JASS的语法检查器安装目录):
                              C:/PJASS/pjass.exe "C:/PJASS/common.j" "C:/PJASS/blizzard.j" %F
                              -> 在菜单项目名称中填写菜单名称, 如: Jass 语法检查(以后可以在菜单"高级"中找到你定义的菜单"Jass 语法检查")
                              -> 选择: 保存活动文件(Save Active File), 输出到列表方块(Output to List Box), 捕捉输出(Capture Output)
                              -> 其他不选择: Windows Program, Save All Files First, Show DOS Box
                              -> 点击"插入"("Insert")
                              -> 点击"确认"("OK")
                              更新: 需要检查AI的应该在JASS的语法检查器的引用设置中加入"C:/PJASS/common.ai"
                              同时把common.ai复制到JASS的语法检查器所在的目录C:\PJASS\
                              注意: 因为AI中不可以引用 blizzard.j 的全局变量和函数, 同样trigger中也不可以引用 common.ai 的全局变量和函数, 所以最好在Ultra-Edit中创建2个自定义菜单来分别检查AI和TRIGGER
                              


                              IP属地:四川21楼2011-11-18 17:09
                              回复