amxx插件开发新手教程6-中难度
条评论前言
我们这一章节将会再深入了解amxx插件的开发,了解玩家属性状态、固体、距离、角度,以及阻断玩家命令等内容。有疑问可以在文章底部留言。
flags状态
我们可以通过实时状态来获取玩家 是否处于蹲下,在地面,在水中等情况。
玩家实时状态是我们经常用在插件中进行判断的部分,比如某些情况下,玩家在空中就不能继续执行我们的效果,亦或者玩家蹲着的时候如果按G键使用技能 会提示在蹲伏状态下不能使用技能,这些都是依靠pev_flags来完成的。
那究竟是怎么样的代码?
例如我们要判断玩家 是不是蹲着可以这样写
1 | if(pev(id, pev_flags) & FL_DUCKING) |
那如果没有蹲着呢?通过之前我们学到的!1`反义就可以判断了
示例:
1 | if( ! (pev(id, pev_flags) & FL_DUCKING) ) |
除了蹲着,还有在空中,在水里等各种情况 详情可以通过hlsdk_const.inc来查看
注意:蹲着不需要你按住CTRL键不放。就比如你在管道被上方障碍物抵挡,也属于蹲伏状态。
Movetype移动类型
不同的实体具有不同的移动类型,移动类型决定了目标实体是否以抛物线或者直线移动
移动类型是实体设定的一种物理引擎检测的方式,比如直线飞行,抛物线飞行,抛物线并且带弹开效果(参考手雷撞击墙壁),光线的折射弹开效果(反射效果),完全不动等等,这些都属于移动类型。
每个实体几乎都具备上述的其中(可能没有包含所有)一个条件,比如玩家的移动类型是MOVETYPE_WALK,手雷是MOVETYPE_BOUNCE
移动类型有大量返回值,你可以参考下面的移动类型(MOVETYPE)表来查看详情
引用于 >> hlsdk_const.inc
1 | MOVETYPE_NONE = 0 //不移动 |
示例:
获取是什么移动类型?
1 | pev(id, pev_movetype) |
通过上述代码得到的返回值就是了。
设置移动类型?
1 | set_pev(id, pev_movetype, MOVETYPE_NOCLIP) //设定目标id(index)为穿墙的移动方式 |
Solid固体类型
不同的固体类型(pev_solid)决定了实体目标的穿透性
若两个玩家在一起互相碰撞,他们只会撞在一起,而不会穿透过去这就是Solid的阻挡效果
很多实体都拥有pev_solid,比如手雷飞出去撞击玩家后会弹开
那到底有哪些呢?和pev_movetype移动类型一样,pev_solid也拥有一些返回值
引用于 >> hlsdk_const.inc
1 | SOLID_NOT = 0 //对其他实体没有任何作用,例如无碰撞 |
设置或获取的方法 与pev_movetype大同小异。
示例:
- 获取:pev(id, pev_solid)
- 设置:set_pev(id, pev_solid, SOLID_BBOX)
注意:SOLID_TRIGGER在某些情况下不能直接设置,不然服务器会崩溃。
Distance通过两点获取距离
通过获取两个目标的坐标点,我们可以取得他们的间隔距离
要知道距离,我们必须知道两个坐标点位置,坐标点的获取方法可以参考之前的教程
通过pev_origin获取两个坐标点之后,接下来要做的就是获取距离
获取距离的代码是get_distance_f,该代码有两个参数
- 坐标点A
- 坐标点B
比如我们取到的两个坐标点分别是org1和org2就可以这样写:
1 | get_distance_f(org1, org2) |
然后他就会通过这两个坐标点自动帮我们算出距离,我们利用这个距离的返回值就可以了
示例:
1 | new Float:iDist = get_distance_f(org1, org2) |
Pev_Angle获取/设定角度
我们的视角瞄准角度,或扔出的手雷他飞向哪边等等,都可通过pev_angle来取得方向
通过pev_angles可以取得目标角度,该代码也是类似于pev_origin的三次数组
示例:
1 | new Float:ang[3] |
注意:我们不能用pev_angles代码直接为玩家设置角度,还需要一个代码:pev_v_angle,他和pev_angles的区别仅仅是上下相反。另外对于玩家来说还需要用到pev_fixangles才能成功修改角度
示例:
1 | new Float:ang[3] |
延迟执行函数
在很多情况下,我们需要执行一个带延迟的函数,这种情况下需要用到set_task来完成
示例:
1 | set_task(2.0, "headfunc", id) |
set_task拥有三个参数(也有更多 但这里不讲),他们分别如下:
- 延迟的时间(浮点数)
- 延迟执行什么函数(填写函数名)
- 延迟执行的触发者(填写索引)
比如我们要用set_task延迟10秒触发thefunc函数,可以这样写:
1 |
|
循环
很多情况下都会用到循环,他可以帮助我们实现不同的效果以及获取更多的数据
在什么情况下会用到循环?
当我们需要通过 AMXX 插件获取玩家人数的时候,或者 需要用循环给所有符合条件的玩家 执行一些命令 就需要用到循环
循环写法1:杀死所有人
示例如下,创建i作为索引 循环32个目标
1 | for(new i=1; i<33; i++) |
比如说,我们需要输入一个命令然后干掉所有的目标,可以像下面这样写:
1 |
|
不太理解?
循环主代码为for
定义首先是new i = 1,然后用了i < 33来表达需要循环的次数,其中33代表玩家数量(预留一位)
在循环中,代码continue是用来忽略该目标,比如说找到了一个死亡的玩家,那么如果用continue来判断的话,循环不会终止,而只是会忽略那个判断到的目标,而继续执行循环
其中,我们新建了一个叫i的索引,他是用来存储我们循环到的目标的,比如说通过循环找到的目标 如果定义为i那么我们随时都可以使用这个新的索引来帮助我们执行一些效果
代码中user_kill是杀死玩家的函数(amxmodx.inc),这里填写的索引就是i而不是id (不然你只会把自己杀死)
循环写法2:获取指定目标的数量
有时候我们可能会遇到,获取目标数量的问题,我们同样可以用到循环来解决问题
示例:
1 |
|
没有看懂?
和上一个例子几乎一样,不过这里添加了一个临时变量xp,这个临时变量是用来充当计数器的,每次循环的时候continue会阻止不符合条件的目标,然后会触发xp += 1
这个时候,xp变量中的值就会随着循环到的目标数量而增加,然后我们用client_print再调用 xp 临时变量的值 就可以显示了
改变玩家重力
在某些情况下,我们可能需要改变玩家的重力,越轻跳得越高
实现的代码为pev_gravity(PEV函数)
示例:修改玩家重力为200.0
1 | set_pev(id, pev_gravity, 200.0 / 800.0) |
不太明白?
虽然看出200.0是重力值,但是后面的800.0是什么?
我们需要通过800.0需要算一个值,对于pev_gravity来说,800.0就是1.0,所以我们的200.0/800.0也就是200除以800.0,该计算出的值就是最终结果
为什么是800.0?
不,并不是 800.0 ,这个800.0是取决于服务器参数sv_gravity的设置
所以如果我们要实现一个完美的重力设置,需要这样写:
写法(1):用变量分开再最终组合
1 | new Float:setgravity = 200.0 |
写法(2):直接组合
1 | set_pev(id, pev_gravity, 200.0 / get_cvar_float("sv_gravity")) |
以上这两种方法都可以实现 同一个目的
注意:代码中的
/是计算方式的 除以
打断数据(简单办法)
有些情况下,我们需要打断原有的数据
比如:我们按G键可以丢弃一把武器,但是我们不希望他被丢弃
这种情况下,我们需要打断原有数据
G键的默认命令是drop也就是丢弃武器。我们可以HOOK(勾住)这个命令以实现我们的目的
这里我们用register_clcmd就可以了,示例如下:
1 |
|
可是这样不能达成我们的目的,武器依然被丢弃了,我们现在只是可以在 按[G]键 的时候提示一下信息
所以,我们需要打断原有数据,让其不丢弃武器
这里我们需要用到返回,代码为return,但是 我们用到的不是一般的返回,而是带有特定返回值的返回
打断这种丢弃数据需要用到的返回值是PLUGIN_HANDLED
配合返回代码 我们组合后可以写出这样:
1 | return PLUGIN_HANDLED |
这就是我们需要的打断效果。通过组合后我们可以得到这样的代码:
1 |
|
注意:通过
drop这个命令进行hook,再配合返回值PLUGIN_HANDLED我们可以完全阻断丢弃武器的事件,但如果玩家死亡的时候,武器依然会掉落。
编译后再测试效果吧。