偶久网

 找回密码
 注册会员

QQ登录

只需一步,快速开始

搜索

网站魔兽热门地图

查看: 4620|回复: 3

jass基础教程之变量篇

[复制链接]
邪恶叔 title=
发表于 2010-11-23 14:13:31
  学新的程序设计语言, 要先学它的变量类型.
  首先提醒大家: 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(数值)是的范围在 -2147483648 和 2147483647 之间的整数, 不能有小数位
  在Jass中Integer的几中特殊形式:
  1.'xxxx' 单引号加字符形式,该形式为256进制整数,每个字符代表其AscII码值,区分大小写,一般用来表示单位、物品、技能等代码。比如对战单位里剑圣的代码是 'Obla'(在物编中按Ctrl+D可以看到)
  2.0xxx 8进制数字,首位为0表示8进制数字
  3.0Xaa 16进制数字,以0x开头的表示16进制数字
  real
  real是范围很大的32字节数字, 可以有小数位, 123456.33就是real
  小数点前或后是0的话,可以省略这个0;比如0.34=.34 4.0=4. 0.0可以写成0.或.0,但不能都省略
  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
  我们可以这样调用函数: call RunFunctionForAllPlayers(function someFunction) //先运行someFunction
  也可以: call RunFunctionForAllPlayers(null) //不运行其他函数
  用户定义变量类型
  正如上面所说, 上表中location/player等除了integer/real/boean/string外的类型实际上就是handle类型的子类型, 这些变量就是用户类型变量, 实际就是一个数据结构的指针.
  数组
  是指一组同类型的有序列的变量. 数组中包含的元素可以用[n]来指明(n 表示第n + 1个元素, 从 0 算起).
  以上所说的变量类型中除了code类型, 其他类型的变量都可以定义数组变量, 如
  locate integer array dropitems
  set dropitems[0] = 'Xxxx'
  ......
  set dropitems[18] = 'Xbbb'
  dropitems[18]指dropitems中第19个变量.
  注意:
  1) 数组所有元素初始值是"空", 比如integer类型的数组初始值为0, handle类型初始值的为null
  2) 数组不能直接再次初始化, 只能数组按元素赋值, 如:
  locate string array playername = "Greedwind" //数组非法赋值
  locate string array playername //数组元素只能逐个赋值
  set playername[1] = "Greedwind"
  set playername[2] = "Greedwind's girlfriend"
  unit array myUnits
  unit array yourUnits
  ...
邪恶叔 title=
 楼主| 发表于 2010-11-23 14:16:17
  set myUnits = yourUnits // 非法

  set myUnits[0] = yourUnits[10] // 合法

  3) 数组在函数间不能互相传递. 即是不能把数组作为函数参数, 而且函数也不能返回数组类型的变量.

  4) 数组元素域在 0 和JASS_MAX_ARRAY_SIZE = 8192 之间, 即是最多有JASS_MAX_ARRAY_SIZE + 1 个元素. JASS_MAX_ARRAY_SIZE是在common.j中定义的常数

  有问有答

  1)什么是全局变量和局部变量, 怎样声明和使用变量?

  首先要了解, 从作用范围来区分, 变量有全局变量和局部变量.

  全局变量作用于Jass程序的全部分, 即是如果全局变量abc在某个函数中改变了值, 这个值也将影响其他引用了abc变量的函数.

  全局变量声明格式:

  globals

  变量类型 变量名称 = 初始值 //有初始化的全局变量

  变量类型 变量名称 //无初始化的全局变量

  变量类型 array 变量名称 //数组全局变量, 不能再次初始化赋值

  ...

  endglobals

  局部变量只作用于函数内部, 即是如果在函数内部定义了局部变量abc, abc的值只影响该函数内部, 不影响全局变量abc的值.

  局部变量声明格式:

  local 变量类型 变量名称 = 初始值 //有初始化的局部变量

  local 变量类型 变量名称 //无初始化的局部变量

  local 变量类型 array 变量名称 //数组局部变量, 不能再次初始化赋值

  注意:

  1) 不论是全局变量还是局部变量, 必须在程序开始部分首先声明.

  即是全局变量声明总是在程序文件的最前端,

  而局部变量声明总是在函数的最前面.

  2) 在Trigger Editor用变量管理器(Ctrl + B)中定义的变量都是全局变量

  3) 在Trigger Editor的循环GUI语句 For Loop (Integer A)和For Loop (Integer B)中的(Integer A)(Integer B)都是全局变量

  实例:

  globals

  integer abc = 5188

  endglobals

  .......

  function myfunc1 takes nothing returns nothing

  local integer abc

  set abc = 1233

  endfunction

  function myfunc1 takes nothing returns nothing

  local integer myint

  set myint = abc

  set abc = 0

  endfunction

  如果按顺序调用函数myfunc1 和 myfunc1, 那么在函数myfunc2中的myint的值是多少呢, abc最终值又是多少?

  答案是: int = 5188, abc 最终值为 0

  2)怎样在Trigger Editor(GUI)中使用局部变量?

  (有关在Trigger Editor(GUI)中使用局部变量详细方法请参看我的签名中的链接 - 3c的内存泄漏)

  GUI中不能直接引用局部变量,但是我们可以使用全局变量作为中介

  首先声明定义变量类型。声明定义变量类型的语句只能放在TIGGER的开头,不然会出现编译错误

  声明定义变量类型:

  要用:Custom Script - Action

  语法:

  Custom Script: local <变量类型> <变量名>

  变量类型请参看WORLD EDITOR和JASS变量类型对应表

  例如:

  --单位变量

  Custom Script: local unit u

  --单位组变量

  Custom Script: local group g

  然后将它们赋值给临时全局变量就可以在GUI里调用该值了,注意全局变量要加前缀"udg_"

  Custom Script: set udg_TempUnit=u

  局部变量的使用:

  在变量表(Control + B)中先定义好同类型临时变量(不要加前缀udg_)的变量,该变量可以在多个触发里重复利用

  (在变量表中定义此变量是为了方便TIGGER EDITOR引用该变量。)

  以下例子实现了在单位死亡的位置显示5秒的死亡信息(漂浮文字)

  (象这种例子, 如果不使用用局部变量, 将无法准确销毁临时漂浮文字(-Destroy (diesmessage)). 因为在等待5秒后(-Wait 5.00 seconds), 最近创建的漂浮文字(last created floating text)可能已经不是原来的那个了 )

  例子:

  Events:

  A unit dies

  Conditions:

  Actions:

  -Custom Script: local texttag diesmessage

  -Custom Script: set udg_TempTextTag = diesmessage //注意要添加"udg_"前缀

  -Floating Text - Create floating text at ((position of (Triggering Unit))

  with the message ((A+(name of (Triggering Unit))) + "dies") with size 20 , red 100, green 100, blue 0, alpha 100.

  -Set TempTextTag= (last created floating text)

  -Wait 5.00 seconds

  -Custom Script: set udg_TempTextTag = diesmessage

  -Destroy (TempTextTag)

  注意:不要利用同名覆盖的方法在GUI中使用局部变量!(即以udg_开头的局部变量与已定义全局变量名字相同)

  该方法在触发内该类同名变量数量>=2时会出现严重Bug!

邪恶叔 title=
 楼主| 发表于 2010-11-23 14:16:41
  注意: 虽然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个文件.

  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 )

  native ForGroup takes group whichGroup, code callback returns nothing

  // 对指定势力中的每个玩家都运行指定callback函数callback

  // (对应GUI语言的For Each Player in )

  native ForForce takes force whichForce, code callback returns nothing

  输入上面两个函数的callback函数必须是无参数无返回值函数(takes nothing returns nothing)

  同样, 操作可破坏物也可以用在区域内的可破坏物作为队列, 可以以用类似的方法:

  // 在指定区域r内符合指定过滤器filter的都运行指定callback函数actionFunc

  // (过滤器见下节的讲解)

  native EnumDestructablesInRect takes rect r,

  boolexpr filter, code actionFunc returns nothing

  在callback函数, 可以用下面的函数获得队列中的下一个元素:

  // 获得单位组中的下一个单位

  // (对应GUI语言的Pick Every Unit in )

  constant native GetEnumUnit takes nothing returns unit

  // 获得势力中的下一个玩家

  // (对应GUI语言的Pick Every Player in )

  constant native GetEnumPlayer takes nothing returns player

  // 获得可破坏物组中的下一个可破坏物

  // (对应GUI语言的Pick Every Destructables in )

  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)

ou99小茎
发表于 2011-4-23 18:26:14
{:6_361:}
快速回复 返回顶部 返回列表