找回密码
 点一下
查看: 3033|回复: 0

VJass语法说明完全汉化(二)

[复制链接]
发表于 2008-1-29 14:56:24 | 显示全部楼层 |阅读模式



在所很多简单的工作的时候,我们仅仅是需要简单地复制,粘贴,替换。宏的出现让一切变得更简单

语法仅仅是以 //! textmacro NAME [takes argument1, argument2, ..., argument n] 开始然后以//! endtextmacro 结束。并用一个//! runtextmacro 使得这个宏在需要的地方生效。一个例子会更好地帮助理解。
[jass]
//! textmacro Increase takes TYPEWORD
function IncreaseStored$TYPEWORD$ takes gamecache g, string m, string l returns nothing
call Store$TYPEWORD$(g,m,l,GetStored$TYPEWORD$(g,m,l)+1)
endfunction
//! endtextmacro

//! runtextmacro Increase("Integer")
//! runtextmacro Increase("Real")
[/jass]
结果是
[jass]

function IncreaseStoredInteger takes gamecache g, string m, string l returns nothing
call StoreInteger(g,m,l,GetStoredInteger(g,m,l)+1)
endfunction
function IncreaseStoredReal takes gamecache g, string m, string l returns nothing
call StoreReal(g,m,l,GetStoredReal(g,m,l)+1)
endfunction
[/jass]
在替换时需要使用 $$ 符号。

使用宏的时候参数要加上引号。字符串和注释不会被替换。

当你仅仅是简单地替换关键字时,也可以不带参数。
[jass]
//! textmacro bye
call BJDebugMsg("1")
call BJDebugMsg("2")
call BJDebugMsg("3")
//! endtextmacro

function test takes nothing returns nothing
//! runtextmacro bye()
//! runtextmacro bye()
endfunction
[/jass]
宏也可用于模板。下面就是一个很好的例子。
[jass]
//! textmacro GetSetHandle takes TYPE, TYPENAME
function GetHandle$TYPENAME$ takes handle h, string k returns $TYPE$
return GetStoredInteger(udg_handlevars, I2S(H2I(h)), k)
return null
endfunction
function SetHandle$TYPENAME$ takes handle h, string k, $TYPE$ v returns nothing
call StoredInteger(udg_handlevars,I2S(H2I(h)),k, H2I(v))
endfunction
//! endtextmacro

//! runtextmacro GetSetHandle("unit","Unit")
//! runtextmacro GetSetHandle("location","Loc")
//! runtextmacro GetSetHandle("item","Item")
[/jass]

宏,域与库之间可以配合使用。
[jass]
//! textmacro STACK takes NAME, TYPE, TYPE2STRING
scope $NAME$
globals
private $TYPE$ array V
private integer N=0
endglobals
public function push takes $TYPE$ val returns nothing
set V[N]=val
set N=N+1
endfunction

public function pop takes nothing returns $TYPE$
set N=N-1
return V[N]
endfunction

public function print takes nothing returns nothing
local integer a=N-1
call BJDebugMsg("Contents of $TYPE$ stack $NAME$:")
loop
exitwhen a<0
call BJDebugMsg(" "+$TYPE2STRING$(V[a]))
set a=a-1
endloop
endfunction
endscope
//! endtextmacro

//! runtextmacro STACK("StackA","integer","I2S")
//! runtextmacro STACK("StackB","integer","I2S")
//! runtextmacro STACK("StackC","string","")
function Test takes nothing returns nothing
call StackA_push(4)
call StackA_push(5)
call StackB_push(StackA_pop())
call StackA_push(7)
call StackA_print()
call StackB_print()
call StackC_push("A")
call StackC_push("B")
call StackC_push("C")
call StackC_print()
endfunction
[/jass]


结构体

结构体向Jass引进了面向对象编程的能力。

先给出一个例子:
[jass]
struct pair
integer x
integer y
endstruct

function testpairs takes nothing returns nothing
local pair A=pair.create()
set A.x=5
set A.x=8

call BJDebugMsg(I2S(A.x)+" : "+I2S(A.y))

call pair.destroy(A)

endfunction
[/jass]
你可以看到,一个结构体中可以存放很多变量。像很多其他的高级语言一样“.”号用来表示结构体的成员

声明一个结构体
在使用一个结构体之前你必须定义它,语法仅仅是struct STRUCTNAME... endstruct要注意的是结构体的定义必须放在全局范围中。即不能写在库中或域中。

在结构体定义一个成员的语法是这样的:<类型名> <成员名> [= 初始值]

在上面的例子中,我们的结构体有两个成员,分别是x和y。而且没有初值。

赋予全局变量一个初值,可以省去了我们在声明一个结构体之后的额外的初始化工,比如null。

结构体创建与销毁
结构体可以被认为是动态的(尽管是伪动态),因此你要在使用前创建和使用后销毁。

可以这样创建一个结构体:SturctTypeName.create([argument,...])

在上面的例子中,想要创建一结构体,调用pair.create()即可。

JassHelper实际上只是一个预处理器,它并不是一个Hack产物。并不是让魔兽真正地接受VJass,因此为了让魔兽读懂VJass,解析器还是要把VJass解析为Jass。所以,在VJass中仍然存在着Jass那些不明不白的限制。比如Jass中一个数组的尺寸限制为8191,结构体在这里也受到限制。下标为0的元素因为某种原因无法使用,所以一个结构体类型,不论如何,只能创建8190次,如果其中含有数组,那么能船舰的次数又要成倍减少。当超过限制,返回的实例为空。(结构体实际上就是有数组做.的声明一个结构体,则返回一个整数,这个整数即代表这个实例,结构体中所有的成员都会写入全局变量比如一个POINT结构实数成员x,y在全局变量中就是real array POINT_x和real array POINT_y,当创建一个实例A,得到的整数假定是1,那么A.x实际上就是POINT_x[1],A.y就是POINT_y[1],再创建一个实例B,得到99,则B.x,B.y就是POINT_x[99],POINT_y[99]。)

但这种限制不是大问题,一张地图很少会超过限制。

除非,你再使用一个结构体后并没有销毁。当然这是你的问题了。

即使这样,假定一个结构体实例平均每秒创建一个,游戏依然可以坚持2小时16分钟。

因此,在每次创建一个结构体,最好检查一下其是否为0(即创建失败)。这也就是我上文说的为什么0号元素不能使用的原因。

如果是测试地图时,创建失败时,就会发出创建失败这样的文本信息。

销毁一个结构体只需要调用.destroy()方法,再上例中,你可以pair.destroy(a),也可以a.destroy()。

如果你的脚本试图去销毁一个0的实例,则它什么也不做,在测试地图的模式下,还会发出警告信息。

结构体的使用
声明结构体就像声明一个变量,参数,或是函数一样。

当你声明一个结构体之后,你当然会访问这个结构体,访问的方式会是:<实例名>.<成员名>。

成员的访问与一个变量的使用是相同的。比如set和return这样的表达式。

[jass]
struct pair
integer x=1
integer y=2
endstruct

function pair_sum takes pair A, pair B returns pair
local pair C=pair.create()
set C.x=A.x+B.x
set C.y=A.y+B.y
return C
endfunction

function testpairs takes nothing returns nothing
local pair A=pair.create()
local pair B=pair_sum(A, A)
local pair C=pair_sum(A,B)

call BJDebugMsg(I2S(C.x)+" : "+I2S(C.y))

//Dont forget, if you are not using an struct instance anymore, you destroy it
call B.destroy()
call C.destroy()
call pair.destroy(A)

endfunction
[/jass]
结果是3:6

实例成员
当然,你的结构体的成员可以是任何东西,比如可以是一个结构体。但是,你不能声明一个结构数组作为成员,当然,在后面的版本中这个问题应得到解决。
[jass]
struct pairpair
pair x=0 //这里不能是pair.create()而应该是一个常数。
pair y=0
endstruct

function testpairs takes nothing returns nothing
local pairpair A=pairpair.create()
local pair x

set A.x=pair.create()
set A.y=pair.create()

set x=A.y //我们用一个变量来备份A.y这样方便将其销毁
set A.y= pair_sum(A.x,A.y) //用这种方式来代替A.y,因为我们已经保存过了

call BJDebugMsg(I2S( A.y.x )+" : "+I2S( A.y.y )) //注意这里的“.”

call A.x.destroy()
call A.y.destroy()
call A.destroy()
call x.destroy()
endfunction

[/jass]
全局的结构体变量
你可以声明一个全局的结构体变量,但由于Jass的限制,你不能直接的初始化它。
[jass]
globals
pair globalpair=0 //合法
pair globalpair2= pair.create() //非法
endglobals
[/jass]
静态成员
在结构体中,静态成员的使用就像一个全局变量一样。只要在之前加上static即可。静态成员当然也可以是数组。

公有,私有结构
在域中,你可以自由地定义结构体,和声明结构体变量。
[jass]
scope cool
public struct a
integer x
endstruct

globals
a x
public a b
endglobals


public function test takes nothing returns nothing
set b = a.create()
set b.x = 3
call b.destroy()
endfunction

endscope

function test takes nothing returns nothing
local cool_a x=cool_a.create()
set a.x=6
call a.destroy()
endfunction
[/ass]
方法
方法很像函数,区别只是方法为结构体所有。

例子:
[jass]
struct point
real x=0.0
real y=0.0

method move takes real tx, real ty returns nothing
set this.x=tx
set this.y=ty
endmethod

endstruct

function testpoint takes nothing returns nothing
local point p=point.create()
call p.move(56,89)

call BJDebugMsg(R2S(p.x))
endfunction
[/jass]
this:这是一个表示结构体自身实例的关键字,只能在一般方法中使用。在静态方法(见后文)中出现则出错。因为静态方法不需要创建实例即可使用,而this必须指向一个实例(即自己)。

方法的语法方法的语法与函数的语法是很接近的。

this是可选的 : 在方法中你可以仅仅使用一个“.”来表示这个实例的成员。

方法不同于函数的是,它们可以先使用,然后再写出定义,因为最终预处理器会将它们一道顶部。而且再方法中最好不要使用Wait(),和GetTriggeringTrigger()这样的函数。在今后的版本中它们可能会引起语法错误。

封装
封装是一种面向对象编程的思想。具体的说,有些东西你有权限去访问,而有些东西则不能。在封装中,要用到结构体的公有、私有成员。
[jass]
struct encap
real a=0.0
private real b=0.0
public real c=4.5

method randomize takes nothing returns nothing
// 全部正确:
set this.a= GetRandomReal(0,45.0)
set this.b= GetRandomReal(0,45.0)
set this.c= GetRandomReal(0,45.0)
endmethod

endstruct

function test takes nothing returns nothing
local encap e=encap.create()
call BJDebugMsg(R2S(e.a)) //legal
call BJDebugMsg(R2S(e.c)) //legal
call BJDebugMsg(R2S(e.b)) //syntax error
endfunction
[/jass]
私有成员只能被使用在结构体内部。不论是私有成员变量,还是私有成员函数。

默认的情况下,一个成员会是公有的。所以public关键字是可选的。但是私有的属性是必须指定的。这里要指出的是,存在一个readonly关键字,顾名思义,就是让一个成员变量在结构体外部可以被使用,但不能被赋值,但在现行的版本中,它仍是不标准的,所以这里并不建议你去使用。
您需要登录后才可以回帖 登录 | 点一下

本版积分规则

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

GMT+8, 2024-5-4 01:08 , Processed in 0.243151 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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