amxx插件脚本编写教程2-Pawn语言基础
条评论Pawn是一个嵌入式、无类型、且易于使用的脚本语言,它能够编程成被Small虚拟机识别的二进制代码。AMX Mod X使用Small插件将脚本功能路由到Half-Life引擎,原理就是Small插件可以被Small虚拟机加载运行,并且能够使用Metamod功能,从而间接地使用Half-Life引擎的功能。(Small虚拟机使用C语言编写,Metamod平台使用C++编写)。Small脚本*.sma可以使用任何一种文本编辑器来编写,最后都要通过Small编译器来编译成Small虚拟机能够识别的二进制代码,即*.amxx文件。这个编译器由AMX Mod X官方提供。
cell是Pawn语言最小的数据单位,占4字节(32位系统)/8字节(64位系统)。
变量
Pawn是一个比较简单的脚本语言,不像C/C++这些高级编译语言,它没有很复杂的概念,例如指针、向量、结构、类、流等等,它都没有。Small脚本只有3种用来声明变量的数据类型(整型、浮点型、布尔型)。在声明变量时,如果不指定变量类型,则默认为数字类型整型。变量名的长度不能超过19个字符,且必须以字母开头。它可以包含的字符有A-Z、a-z、0-9和_(下划线)。值得注意的是,变量名是大小写敏感的,例如myvar和MyVar是两个不同的变量。我们可以使用new关键字来声明变量。
1 | new a //Declare empty variable "a" |
另外,你还可以明确地声明浮点型类型的数字变量。
1 | new Float:a //Declare empty floating point variable "a" |
最后就是布尔类型的变量了。
1 | new bool:IsItOn //Declares a new variable "IsItOn" which is automatically false |
数组
Pawn支持最基础的数组。数组是一个重要的聚合数据类型,它能够让你将多个数据存储到一个变量名。在同一个数组中,每个元素的数据类型都是相同的。你可以使用中括号[]来定义数组。
1 | //This will declare a variable called "Players" which holds 32 numbers. |
数组也可以在定义式初始化。
1 | new Numbers[4] = {0,1,2,3} |
你可以使用任何一种数据类型来定义数组。
1 | //Array of floating points: |
字符串
你可以已经注意到了,我们还没有讲到一个重要的数据类型,那就是字符串。在Pawn中,字符串是用数字类型的数组来表示的。数组中,每个元素代表着一个ASCII码,对应着相应的字符。
1 | //This will declare a number array "myString" that contains the data "Hello". |
值得注意的是,在
Pawn中,数组的每个元素变量均是4字节或8字节的cell(Pawn的最小单位变量)
函数
Pawn允许你自定义函数,这对于代码重复利用是很有用的。值得注意的是,在Pawn中,每个函数都需要有return返回值。如果函数中没有return,那么函数将不会被Small虚拟机执行。
1 | //This is a function that takes no parameters and returns 1. |
你还可以定义一个带参数的函数
1 | //This declares a function called "add_two_numbers", which takes two numbers and returns the sum. |
你无需关心传入参数的类型,你可以传入任意数据或变量到你的函数。
1 | //This defines a new function called "add_two_floats" |
当你传入的参数是数组是,那么你实际传入函数的是数组的引用,并不是数据的拷贝副本(只有整型、浮点型和布尔型才会传入副本,其他都是引用)。这里的引用有点儿类似C语言的指针,例如,在修改引用参数的值,会直接修改原数据。可以在定义函数参数时,添加const关键字,确保引用参数不会被修改。
1 | //This function will switch slots a and b inside any array passed to this function. |
表达式和操作符
表达式听起来有点数学的味道。它能够通过加减乘除、以及与或之类的操作符对数据变量进行计算,并返回相应的结果。你可以通过表达式,将计算结果赋值给变量,也可以直接作为参数传入函数。
1 | //This is the simplest expression. It returns the number zero. |
表达式不仅可以是0或false,也可以是true或者一个确切的整数、浮点数。
1 | //Here are more mathematical expressions. The mathematical operators are |
这里有个地方需要注意一下,a++和++a,其中a++是表达式执行后a加1,而++a是表达式执行前a加1,两者区别在于表达式中a的值是否已经加1。同样的a--和--a也是一样的道理。
1 | a-- //returns 4, post decrement |
当然,表达式不仅能够对数据进行加减乘除计算,还有其他布尔型计算。
1 | //The and operator takes in the left expression and right expression. |
除此之外,Pawn也支持位运算的操作符
1 | //This will return 8, which means 8(1000) is indeed a bit in 9(1001). |
位移运算操作符<<和>>也是支持的
1 | //This takes the number 3 (00011) and shifts it three places to binary (11000), or 24. |
还有取反操作符!
1 | //This returns false |
条件语句
条件语句能够让你根据表达式的情况,选择程序执行的不同路径。最常见的就是if...then模式,即如果if条件符合,那么就执行then的代码。
1 | if (a == 5) |
当然,还有if...then...else模式
1 | if (a == 5) |
if的表达式,可以是能够返回true或者false的表达式,也可以是返回0或者非0的表达式
1 | //This will return true if a does not equal 5 |
对于数组的比较,不能是只比较数组的变量名,下边的这个比较方法是错误的
1 | my arrayOne[3] |
数组的比较应该是比较其中的元素,例如:
1 | if ((arrayOne[0] == arrayTwo[0]) && |
当然,像这种数组或者字符串(也是数组)的比较,会有相应的函数来进行比较,不需要你自己遍历每个元素来比较。
另外的,还有if...then...else if...else模式
1 | //Example of "if...else if" |
值得注意的是,if...else if中,条件表达式是按照从上到下顺序执行的,但是只要有一种表达式满足条件,那么后续的表达式将不会被执行。
同理,swtich...case模式也是一样的意思。不同于C/C++,在Pawn中的switch...case中,是没有break的。
1 | //Example of a switch statement |
循环
一个中是for循环,和C语言相似,支持break和continue关键字。
1 | /*A for loop has three parameters: |
通过for循环,我们可以比较简便的管理我们的数组
1 | //Note: this provides a nice way to loop through arrays! Observe this function below. |
还有一种循环,叫做while循环,同样的,也支持break和continue关键字。
1 | //Basic loop |
二维数组
二维数组,即一维数组中的每个元素也是数组,而不是数值。二维数组的声明方法如下:
1 | //This declares an array with 50 rows and 50 columns. |
二维数组的第一个元素,也是一个数组,可以看做是一张表格,可以对二维数组进行赋值
1 | new BigArray[3][3] |
| BigArray | 0 | 1 | 2 |
|---|---|---|---|
| 0 | 10 | 20 | 30 |
| 1 | 40 | 50 | 60 |
| 2 | 70 | 80 | 90 |
接着,我们使用之前的sum_of_array()函数,来测试一下数组传参
1 | new sum = sum_of_array(BigArray[2], 3) |
因为BigArray[2]其实指向的是一个一维数组{70,80,90},所以此时函数依然能够正常执行。当然,我们也可以在函数参数中,定义二维数组参数:
1 | //This function will tally up a two dimensional array. |
接下来,我们再来看一下字符串数组
1 | new StringList[3][] = {"Hello", "my", "friend"} |
展开成表格的话,可以很清楚的看出它的数据结构:
| StringList | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | H | e | l | l | o | \0 | |
| 1 | m | y | \0 | ||||
| 2 | f | r | i | e | n | d | \0 |
比较字符串,可以简单的使用equali函数
1 | if (StringList[0] == "Hello") //INVALID |
编译指令(预处理)
Pawn是支持一些预处理指令的,例如#define、#if defined、#else、#endif、#pragma等。
1 | //To bind a symbol to a value, you can do this: |
总结
这篇文章大致说明了Pawn语言的一些基础语法,其实并不全面,你可以上网搜索Pawn语言的更多资料来深入学习。