AMXXPawn enum关键字

目录

1. 核心功能

enum可声明一组带有相同值类型标签、数值有规律、关联性强的常量,替代“魔法数字”,提高代码的可读性。

enum还可以设计结构体,结合数组可模拟查改结构体属性,方便用户管理复杂数据。

若未来需增减数据,只需修改枚举定义,无需修改所有用到数字索引的代码。

编译器会对枚举相关代码进行更加灵活的类型标签检查,引导用户编写正确代码。

2. 枚举声明语句

枚举声明语句的语法:

<enum> \常量标签覆盖/ \枚举类名/ \升值器/ <{> \枚举常量声明/ <}> \;/

标签覆盖语法拆解:

<值类型标签名称> <:>

升值器语法拆解:

<(> \<升值型赋值运算符> <常量表达式>/ <)>

枚举常量声明语法拆解:

\属性标签覆盖/ \枚举常量名称/ \属性尺寸声明/ \初始化表达式/ \,/

属性尺寸声明语法拆解:

<[> <常量表达式> <]>

初始化表达式语法拆解:

<=> <常量表达式>

<>是必填项目,\/是可选项目。

\枚举常量声明/若以逗号结尾,可继续声明下一个枚举常量。

不填写枚举类名,则为匿名枚举。

填写枚举类名,则为命名枚举。

3. 常量标签覆盖注意事项

4. 枚举类名注意事项

5. 升值器注意事项

6. 属性标签覆盖注意事项

7. 枚举常量注意事项

8. 属性尺寸声明注意事项

9. 初始化表达式注意事项

10. 三种核心用法

基础用法:替代"魔法数字"

用途:定义一组有意义,强相关的常量,代替 0, 1, 2... 这样的数字,提高代码可读性。

enum LibType { LibType_Library, LibType_Class }; // 参数2带有LibType标签,暗示用户填写LibType枚举的成员,若填写无关的表达式,则会触发警告 native LibraryExists(const library[], LibType:type); static gErrorText[128]; public plugin_natives() { // 调用LibraryExists函数,参数2根据需求填LibType_Library或LibType_Class if (!LibraryExists("zombienpc", LibType_Library)) { formatex(gErrorText, charsmax(gErrorText), "'ZombieNpc' plugin must initialize earlier than the current plugin. Check plugins.ini."); return; } }

反面教材:定义一组强相关的宏常量,在没有注释的情况下,用户根本猜不出这些宏常量的用途。

#define AMX_ERR_NATIVE 10 #define AMX_ERR_MEMACCESS 5 #define AMX_ERR_NONE 0 #define AMX_ERR_BOUNDS 4 #define AMX_ERR_STACKERR 3 #define AMX_ERR_STACKLOW 7 #define AMX_ERR_HEAPLOW 8 #define AMX_ERR_DIVIDE 11 #define AMX_ERR_NOTFOUND 19 #define AMX_ERR_PARAMS 25 #define AMX_ERR_GENERAL 27 // 参数1带有_标签,用户绝对猜不到要填写名称以AMX_ERR_开头的宏常量 native abort(error, const fmt[] = "", any:...); public plugin_precache() { if (gErrorText[0] != EOS) { // 填写任何带有_标签的表达式作为参数1,都不会触发警告.原生inc文件中存在大量这样的缺陷设计 abort(AMX_ERR_NONE, gErrorText); } }

进阶用法:位掩码(Bitmask)

用途:定义二进制位标志,表示可并存的状态,比如同时按下多个按键,同时拥有多种权限。

/// 障碍物特征 enum ObstacleAttribute (<<= 1) // 每次左移1位(相当于*= 2) { /// 值为0,表示无任何特征,无法与其它特征并存 OA_Static, /// 显式赋值为1,让接下来的常量可以自动赋值 (二进制 0b_0001) OA_Dynamic = 1, /// 自动赋值为2 (0b_0010) OA_Ladder, /// 自动赋值为4 (0b_0100) OA_Virtualized } // 表示某个障碍物同时含有的特征:运动中的爬梯,由于被虚化而无法产生碰撞 值为1|2|4=7 (0b_0111) new ObstacleAttribute:obsAttributes = OA_Dynamic | OA_Ladder | OA_Virtualized;

高级用法:模拟结构体(重要!)

用途:用 enum + 数组模拟 C 语言的 struct,方便管理复杂数据。

// 僵尸外观数据结构 enum tZombieAppearance { _: ZA_MdlPath[64], _: ZA_BodyId, _: ZA_SkinId, bool: ZA_SunkInGround }; // 僵尸类型数据结构 enum tZombieClass { _: ZC_Name[32], // 属性尺寸声明要求[]内填写带有_标签的常量表达式,表示结构体属性的尺寸 // 若填写枚举类名,表示该这个结构体属性也是结构体.编译器自动切换tZombieAppearance的标签为_ _: ZC_Appearance[tZombieAppearance], _: ZC_MaxHealth, _: ZC_MaxSpeed, Float: ZC_EyePos[3] }; // 维度声明要求[]内填写带有_标签的常量表达式,编译器自动切换tZombieClass的标签为_ // tZombieClass让2维数组gDefaultZombieClasses内的1维数组变成结构体, // 解析器允许用户使用结构体字面量对这些1维数组进行初始化 static gDefaultZombieClasses[][tZombieClass] = { // 第1个结构体字面量 { "普通僵尸", { "models/player/zombie_classic/zombie_classic.mdl", 0, 0, true }, 1000, 250, { 0.0, 0.0, 35.0 } }, // 第2个结构体字面量 { "快速僵尸", { "models/zombie_fast.mdl", 0, 0, false }, 500, 320, { 0.0, 0.0, 0.0 } } }; static Array:gZombieClasses = Invalid_Array; native Array:ArrayCreate(cellsize = 1, reserved = 32); native ArrayPushArray(Array:which, const any:input[], size = -1); // native ZombieClasses_Add(zombieClass[tZombieClass]); public @ZombieClasses_Add(pluginId, numParams) { // tZombieClass让1维数组zombieClass变成结构体 new zombieClass[tZombieClass]; get_array(1, zombieClass, sizeof zombieClass); if (gZombieClasses == Invalid_Array) { // ArrayCreate的参数1要求填写带有_标签的表达式,编译器自动切换tZombieClass的标签为_ gZombieClasses = ArrayCreate(tZombieClass); } // 用ZC_Name访问1维数组zombieClass的元素,允许额外添加[]索引器访问元素的元素 // ZC_Name值为0,但若之间填0,会触发标签不匹配的警告,且第二个[]索引器会触发语法错误 // zombieClass本质是1维数组,不可能升维,这两个索引器会被解析为[ZC_Name + 0] if (zombieClass[ZC_Name][0] == EOS) { log_error(AMX_ERR_NATIVE, "The name of zombie class connot be empty."); return; } // ZC_Appearance让结构体属性也变成了结构体,允许使用第二,甚至第三个[]索引器 if (zombieClass[ZC_Appearance][ZA_MdlPath][0] == EOS) { log_error(AMX_ERR_NATIVE, "The appearance of zombie classes cannot use empty model paths."); return; } // 参数2要求索引器使用_标签,编译器自动切换zombieClass索引器标签为_ ArrayPushArray(gZombieClasses, zombieClass); }

访问结构体属性时,可使用sizeof关键字获取该属性尺寸。

比起直接填写具体尺寸数值,sizeof的可读性更高。

server_print("僵尸名称尺寸:%d, 实际单元数:%d", sizeof zombieClass[ZC_Name], strlen(zombieClass[ZC_Name]));