语言参考
From SA-MP Wiki
Contents |
出发!
以下是一个最基本的脚本例子:
#include <a_samp> main() { print("Hello World!"); return 1; }
我们先来看第一行.
引用 (Include)
#include <a_samp>
它主要装载pawno/includes/a_samp.inc的代码到你的脚本里, 因此每次你都需要使用它. 它具有的事情之一:
#include <core> #include <float> #include <string> #include <file> #include <time> #include <datagram> #include <a_players> #include <a_vehicles> #include <a_objects> #include <a_sampdb>
a_samp.inc包含了所有其他INC文件在它的目录里,所以添加了a_samp.inc就相当于把所有的函数都添加进了SA:MP (以后还会有更多的函数).
调用
The next part has two sides of a function call. main() is a function which you write the code for and is called from elsewhere, print(string[]) is a function with the code elsewhere which you call. Currently all this will do is load, print a string (i.e. print "Hello World!" (without the ""s) (a tradition in all scripting languages)) to the server console and end. The:
接下来的部分使用了两个函数.函数main()执行你写在这里和调用来自别处的代码,函数print(string[])与别处的代码被你调用.现在所有的工作的结果就是输出一个字符串对象(也就是输出"Hello World!"(没有双引号"")(这是所有语言的惯例))到服务器控制台和结束.这里:
return 1;
Passes a value (1) back to the place which called main to tell it what happened (the exact value passed here doesn't matter but in other places it does). You now have your first (very basic) script. If you select file->new in pawno it will give you a much bigger start point will all the callbacks in (see below), including main (which isn't technically a callback but acts like one).
传递一个返回值(1)给被调函数main告诉它发生了什么(在这里传递的确切值并不重要,但是在其他的地方它是有用的).现在你已经有了你的第一个(非常基础的)手稿了.如果你在pawno里选择file->new他将给你一个存有所有回调在里面的非常大的出发点(看下面),包括main(它不是一个专门的回调,但是它不可缺少且只能有一个).
语句
The print and return lines have ';' (a semi colon) on them, this just denotes the end of a statement (a statement is a group of one or more functions and operators which together do something, similar to a sentence in common language). Most people put separate statements on separate lines but this is not required, it just makes things clearer, the following is equally valid:
在print和return的行末处都有';'(一个分号),这里这个分号仅仅表示语句的结束(语句是一个或更多函数和运算符在一起共同做某些事情,类似普通语言里的语句).多数人放单独的语句在单独的行,这是不必要的,那样仅仅让事物清晰些,下面的写法效果相同:
main() { print("Hello World!"); return 1; }
The {}s (braces (curly brackets), not parenthesis (brackets)) enclose a group of statements which should be executed together (like a paragraph in common language). If you did:
在{}(花括号)里面的语句组都将被一起执行(就像普通语言中的段落).假如你这样写:
main() print("Hello World!"); return 1;
You would get an error because now the "return 1;" statement is not grouped so is not part of main. Braces group a set of statements into a single statement (called a compound statement) and functions have a single statement with them. Without the braces print and return are entirely separate statements, so there's two or them so, as a function can only have a single statement, the second is not in a function, which code can't be.
你将得到一个错误,因为现在"return 1;"语句不是mian的一部分.花括号把一组语句组织成一个的语句(称之为复合语句)和函数的单一语句.没有花括号的话print和return就是完全单独的语句,因此有两个或更多的语句,因为一个函数只能有一个语句,第二个它不是一个函数,所以这段代码不成立.
函数
A function is basically a chunk of code which does something and can be told to do this thing from somewhere else. It can also pass data about what it did back to the place which told it to run (the place which "called" it).
函数是代码的基本部分,它可以告诉你这里在干些什么或者这里所作的事情来自别的地方.它也可以传递数据,它可以返回数据到需要的位置运行(这里称之为调用).
调用
print("Hello World!");
As described in Starting out, this calls the function called "print" (defined in a_samp.inc, which is why you need to include it) and tells it to display something in the server console (the word hello).
依照开始的描述,这里调用函数"print"(定义在a_samp.inc,所以你明白为什么你必须包含它了)和告诉它显示某些事物到服务器的控制台(显示word hello).
A function consists of the function name (e.g. print), which tells the system which chunk of code you want to call, and a parameter list, enclosed in ()s after the function name, which pass additional data to the function to help it run. If you didn't have parameters you would need millions of functions:
函数的名字预示着它的功能(例如print),告诉系统你想要调用的代码部分,参数表在函数名之后的括号里面,通过附加数据到函数帮助它更好的运行.如果你不使用参数那么你就需要成千上万的函数:
printa(); printaa(); printab(); printac(); etc...
Functions can have as many parameters as you like, from 0 up (there may be an upper limit but it's at least 128):
函数可以有许多参数,从0开始(这有可能是它的上限,但它至少128):
printf("Hello World!", 1, 2, 3, 4, 5, 6);
Don't worry about what that function does for now, just that it has 7 parameters, each separated by a comma.
现在不必但是那些对函数有效,它有7个参数,每个之间都用逗号隔开.
定义
As well as being able to call existing functions you can also write and call your own:
就像调用现有的函数一样,你可以书写和调用你自己的函数:
#include <a_samp> main() { return MyFunction(); } MyFunction() { print("Hello World!"); return 1; }
This just does exactly the same as the original code but is arranged differently. When main() is called when the mode is started (it's called automatically) it calls the new custom function called MyFunction(). This function prints the message in the server console then returns the number 1 to main(). main() takes the returned value (1) and then returns it to the server itself (i.e. the place which called main in the first place). As "return MyFunction();" is a single statement you could do:
这样写的效果和源代码是一样的,只是排列不同.当main()被调用时启动的模式(这就是所谓的自动),它调用自定义的新函数MyFunction().这个新函数显示消息到服务器的控制台并返回一个值1给main().main()得到这个返回值后把它返回给服务器本身(i.e. the place which called main in the first place).因为"return MyFunction();"是单独的语句,你可以这样写:
#include <a_samp> main() return MyFunction(); MyFunction() { print("Hello World!"); return 1; }
But most people don't for clarity. You can also not use the MyFunction return value at all and do:
但是多数人会觉得不够清晰.你也可以不使用MyFunction返回一个值:
#include <a_samp> main() { MyFunction(); return 1; } MyFunction() { print("Hello World!"); return 1; }
参数
Parameters are a type of variable which you don't need to declare as they come from the place which called the function:
参数是变量的一种类型,你不必对它进行说明,它的功能取决于所调用的函数:
#include <a_samp> main() { return MyFunction("Hello World!"); } MyFunction(string[]) { print(string); return 1; }
This code still does the same thing but we're now telling MyFunction() what to display. The call passes the string "Hello World!" to the function where it is stored in a variable called string (the [] means it's an array as explained later). The print function is the called, passing the contents of the string variable, we know it's a variable because it doesn't have the "" any more.
这段代码仍然做同样的工作,但是我们现在告诉MyFunction()显示了什么.这个调用传送字符串对象"Hello World!"存储到调用的函数(这里[]意味它是一个数组,稍后解释).调用打印函数,传递字符串对象变量的内容,我们知道它是一个变量,因为它没有使用""包围.
变量
A variable is basically a bit of memory, it's where data is stored and can be changed and read as required. Variables are one or more cells, a cell is 32 bits (4 bytes) big and by default signed so they can store from -2147483648 to 2147483647 (although -2147483648 is poorly defined in PAWN and gives odd results if displayed). A variable made from more than one cell is called an array, strings are a special type of array where each cell holds a character of the string (or 4 characters in packed strings, but they're not covered here).
变量是内存的一个基本位,这里存储的数据是可以被读取和更改的.变量是一个或多个单元格,一个单元格是32位大(4字节),并且默认签名,所以他们能够存储从-2147483648到2147483647(although -2147483648 is poorly defined in PAWN and gives odd results if displayed).许多的单元格构成的变量称之为数组,字符串是特殊类型的数组,它的每个单元格保存一个字符串对象的字符(或4个字符一起的字符串,但是在这里不讨论他们).
声明
To create a new variable you have to declare it:
声明你创建了一个新的变量
new
myVariable;
This tells the system to create a new variable called myVariable, the initial value of this variable will be 0.
这将告诉系统创建一个名为myVariable的新变量,这个变量的初始值将是0.
赋值
new myVariable = 7;
This declares a new variable and sets it's initial value to 7, so printing the variable now will give 7. To display a variable which isn't a string we need to go back to the printf() function mentioned earlier and do:
声明创建一个新变量并且给它赋初始值为7,所以现在这个变量的输出值将是7.我们可以追述使用前面提到过的printf()函数来显示这个变量的值:
new myVariable = 7; printf("%d", myVariable);
Again, for now all you need to know is that this will print the value of myVariable (i.e. 7 at this point) to the server. 此外,现在你需要知道的是以上代码会显示myVariable的值到你的服务器上.
new myVariable = 7; printf("%d", myVariable); myVariable = 8; printf("%d", myVariable);
That code will print 7, change the value of the variable to 8 and display the new value in the server window too. There are many other things you can do to variables, some are listed below, most are listed elsewhere: 代码将输出7,改变变量的值为8同时显示在服务器上.但让你也可以改变成其他值,在下面为大家列举了一些实例,当然别的地方还有很多这样的实例:
myVariable = myVariable + 4;
Sets the value of myVariable to the old value of myVariable plus 4, i.e. increase it's value by 4. This can also be written as: 设置myVariable为myVariable的旧值加4,也就是它的值增加4.它也可以这样书写:
myVariable += 4;
Which just means "increase myVariable by 4". 刚才试使myVariable增加4的方法.
myVariable -= 4;
That will decrease the value by 4. 这是减少4的方法.
myVariable *= 4;
That will multiply the value by 4. 这是乘以4.
myVariable /= 4;
That will divide the value by 4. 除以4.
数组
声明
An array is a variable in which you can store multiple pieces of data at once and access them dynamically. An array is declared to a set size at compile time so you need to know how many pieces of data you need to store in advance, a good example of this is the very common MAX_PLAYERS array, this will have one slot for every possibly connected player, so you know data for one player will not interfere with data for another player (more on defines later).
new myArray[5];
That code will declare an array 5 slots big, so you can store 5 pieces of normal data at once in that single what you can't do is something like the following:
new myVariable = 5, myArray[myVariable];
That code looks like it would create an array the size of whatever number is stored in myVariable (here 5 but it could be anything), but you can't do this. In PAWN the memory for variables is assigned when you compile your code, this means arrays are always one size, you can't set the size to anything you like whenever you like.
访问
To set a value in an array you need to say which part of the array you want to store the data in, this CAN be done with another variable:
new myArray[5]; myArray[2] = 7;
This will declare an array with 5 slots and give the THIRD slot a value of 7, given that variables always start as 0 this will make the values in the array:
0, 0, 7, 0, 0
Why is it not:
0, 7, 0, 0, 0
you're wondering? It's because counting actually starts from the number 0, not 1. Consider the following:
2, 4, 6, 8
If you go through the list then after the number 2 you have already had one number (the 2), this means that if you are counting the numbers by the time you reach the number 4 you are already at one, you're not at one when you reach the 2, you're at zero. Thus the 2 is at position zero and the 4 is at position one, and thus it follows that the 6 is at position two, which is where the 7 in the first example above is. If we label the slots for the first example we get:
0 1 2 3 4 0 0 7 0 0
There are five slots but as you can see, and this is very important, THERE IS NO SLOT FIVE, doing the following could crash your server:
new myArray[5]; myArray[5] = 7;
As mentioned above the array index (the index is the slot to which you're writing) can be anything, a number, a variable, or even a function which returns a value.
new myArray[5], myIndex = 2; myArray[myIndex] = 7;
Once you have an array and an index you can use that block exactly as if it were any other variable:
myArray[2] = myArray[2] + 1; myArray[2] += 1; myArray[2]++;
范例
As mentioned above a common type of array is the MAX_PLAYERS array. MAX_PLAYERS is not a variable, it's a define which is explained later, but for now accept that it is a constant number equal to the max number of players a server can hold (this by default is 500, even if you change the number in your server.cfg file). The following code uses normal variables to hold data for 4 players and do something with those players in a function (for simplicity's sake assume MAX_PLAYERS is 4 for now):
new gPlayer0, gPlayer1, gPlayer2, gPlayer3; SetPlayerValue(playerid, value) { switch(playerid) { case 0: gPlayer0 = value; // is the same as doing if(playerid == 0) case 1: gPlayer1 = value; // is the same as doing if(playerid == 1) case 2: gPlayer2 = value; // is the same as doing if(playerid == 2) case 3: gPlayer3 = value; // is the same as doing if(playerid == 3) } }
See the section on control structures for more information on what's going on there, also note this could be done as a switch but that's less clear for the example and effectively the same code anyway.
Now compare that to using an array with one slot per player, bearing in mind an array index can be any value:
new gPlayers[MAX_PLAYERS]; SetPlayerValue(playerid, value) { gPlayers[playerid] = value; }
That will create a global array (see section on scope) with one slot for every player, then the function will assign whatever is in the variable "value" to the slot for the player specified. The first example was large with only four players, using 4 lines per player, that's 2000 lines for 500 players (if can be less but it's still a lot), the second version is a single line no matter how many players you have.
字符串
标准用法
A string is a special type of array, one which is used to hold multiple characters to create a word or sentence or other human readable text. A character is one byte big (although there are extended sets where a character is multiple bytes but these are not well defined in SA:MP) and by default a character takes up one cell (one normal variable or one array slot). Characters are encoded in a system called ASCII, the character "A" is represented by the number 65, telling the system to display a number will give 65, telling the system to display a character will give a capital a. Obviously is a single character takes up a single cell multiple characters (i.e. text) will take up multiple cells, collections of cells, as just explained, are called arrays.
Strings in PAWN (and other languages) are what's called "NULL terminated", this means that when 0 is reached, the string ends. This is not the same as the character "0", represented by the number 48, this is the NULL character, represented by the number 0. This means that you can have a string array 20 cells large but only have a string 3 characters long if the fourth character is the NULL character, signalling the end of the string. You can not however have a string 20 characters long as the NULL character MUST be in the string, so in a 20 cell array you can have a 19 character string and a NULL termination character.
new myString[16] = "Hello World!";
That code declares a new string with enough space for a 15 character string and sets it initially to the 5 character string "Hello World!", the double quotes around the text indicate that it's a string. Internally the array will look like:
104 101 108 108 111 0 x x x x x x x x x x
The "x"s mean anything, in this example they will all be 0 but as they're after the null character is doesn't matter what they are, they won't affect the string.
Strings can be manipulated like normal arrays, for example:
new myString[16] = "Hello World!"; myString[1] = 97;
Will change the character in slot 1 to the character represented by the number 97 (a lower case "a"), resulting in the string reading "hallo". This can be written much more readably and easy to edit as:
new myString[16] = "Hello World!"; myString[1] = 'a';
The single quotes around the "a" mean it's a character, not a string, characters don't need to be NULL terminated as they're only ever one cell long, they can also be used interchangeably with numbers if you know what they represent.
new myString[16] = "Hello World!"; myString[1] = '\0';
'\0' is two characters, however the \ is a special character which modifies the next character, \0 means NULL, that code is the same as doing:
new myString[16] = "Hello World!"; myString[1] = 0;
But is NOT the same as doing:
new myString[16] = "Hello World!"; myString[1] = '0';
The first and second versions will result in the string being simply:
h
The third version will result in the string being:
h0llo
转义符
As briefly mentioned a backslash is a special character, doing:
'\'
or:
"\"
Will give a compiler error because the \ modifies the next character so those constants will not be ended correctly, this can be used to create characters which can't normally be created, for example:
new myString[4] = "\"";
That code will create a string consisting of only a double quote, normally a double quote signals the end of a written string but the backslash makes the double quote immediately after it a part of the string, and the double quote after that ends the string instead. Other special characters are:
\0 | NULL character | Ends a string. |
\n | Line feed | use \n for a new line in Linux (also works in Windows) |
\r | Carriage return | Use \r\n for a new line in Windows |
\\ | Backslash | Used to put an actual backslash in a string |
\' | Single quote | Used to use an actual single quote as a character in single quotes (use: '\'') |
\" | Double quotes | Used to put an actual double quote in a string |
\xNNN; | Hex number | Used to set the character to the character represented by the hex number specified in place on NNN |
\NNN; | Number | Used to set the character to the character represented by the number specified in place of NNN (see \0) |
There are others but those are the main ones.
标签
A tag is an additional piece of information on a variable which defines where it can be used. For example:
new Float:a = 6.0;
The "Float" part is the tag, this defines this variable as a float (non-whole number) and determines where it can be used.
native SetGravity(Float:gravity);
This means the SetGravity function takes a single parameter which has to be a float, for example:
SetGravity(6.0); new Float:fGrav = 5.0; SetGravity(fGrav);
That will set the gravity to 6 (6.0 as a float) then 5 (5.0 as a float). Using the wrong tag in the wrong place will often give a tag mismatch:
SetGravity(MyTag:7);
That will try set the gravity to 7 with the tag "MyTag", that is clearly not a "Float" so is wrong. Also note that tags are case sensitive.
作用域
Scope is where a variable can be used. There are four main scopes: local, local static, global and global static. All variables can only be used after they are declared so this is right:
new var = 4; printf("%d", var);
This is wrong:
printf("%d", var); new var = 4;
局部
A local variable is one declared "new" inside a function or part of a function:
MyFunc() { new var1 = 4; printf("%d", var1); { // var1 still exists as this is a lower level new var2 = 8; printf("%d %d", var1, var2); } // var2 no longer exists as this is a higher level } // var1 no longer exists
Local variables are reset every time, for example:
for (new i = 0; i < 3; i++) { new j = 1; printf("%d", j); j++; }
Will print:
1 1 1
Because j is created, printed, incremented then destroyed, then the code loops.
局部静态
A static local can be used in the same place as a local but doesn't forget it's old value, for example:
MyFunc() { static var1 = 4; printf("%d", var1); { // var1 still exists as this is a lower level static var2 = 8; printf("%d %d", var1, var2); } // var2 no longer exists as this is a higher level } // var1 no longer exists
That code will behave exactly the same as the new example, however this:
for (new i = 0; i < 3; i++) { static j = 1; printf("%d", j); j++; }
Will print:
1 2 3
Because j is static so remembers its old value.
全局
Global variables are declared outside a function and can be used in any functions:
全局变量是指给声明在函数之外和可以使用在任何函数中的变量:
new gMyVar = 4; MyFunc() { printf("%d", gMyVar); }
They are never reset or lost.
他们从不复位和失效.
全局静态
Global static variables are like normal globals but can only be used in the file in which they are declared:
全局静态变量看起来就像一个标准的全局变量,但是它只能在声明它的文件中使用:
File1:
static gsMyVar = 4; MyFunc() { printf("%d", gsMyVar); } #include "File2"
File2:
MyFunc2() { // This is wrong as gsMyVar doesn't exist here printf("%d", gsMyVar); }
static can also be applied to functions in the same way.
静态全局变量在函数中的使用方式和全局变量是相同的。
控制结构
控制结构决定了程序走向. 程序可以依据变量内容、函数返回值或其他东西执行或不执行某些代码。 程序也可以在需要的情况下重复做某些事。