@sogouwap
2017-06-06T04:24:03.000000Z
字数 5810
阅读 5450
前言
本教程由小灰编写,这是对于
低难度
更上一层教程
建议在对低难度
学习之后再阅读。
我们的QQ群:139659650
点击上述列表中
未打钩
旁边的切换按钮,以切换学习等级。
这个教程学习下来需要多少时间?
你需要花一些时间直到你掌握它,并且每天都要坚持编写代码。
根据理解力的不同,需要的时间也不一样(三个月,六个月,或一个星期)
我需要准备什么样的系统?
你需要 Windows 7/8/10 或者 Windows XP 系统。
我们可以通过实时状态来获取玩家 是否处于 蹲下
, 在地面
, 在水中
等情况
玩家实时状态是我们经常用在插件中进行判断的部分,比如某些情况下,玩家
在空中
就不能继续执行我们的效果,亦或者玩家蹲着的时候如果按G键使用技能 会提示在蹲伏状态下不能使用技能
,这些都是依靠pev_flags
来完成的
那究竟是怎么样的代码?
例如我们要判断玩家 是不是 蹲着
可以这样写
if(pev(id, pev_flags) & FL_DUCKING)
{
client_print(id, print_chat, "你是蹲着的")
}
那如果没有蹲着呢?通过之前我们学到的 !
反义就可以判断了
示例:
if( ! (pev(id, pev_flags) & FL_DUCKING) )
{
client_print(id, print_chat, "你站着的噢~")
}
除了蹲着,还有在空中,在水里,等各种情况 详情可以通过 hlsdk_const.inc
来查看
注意:
蹲着
不需要你按住CTRL不放。就比如你在管道被上方障碍物抵挡,也属于蹲伏状态。
不同的实体具有不同的移动类型,移动类型决定了 目标实体是否以 抛物线
或者 直线
移动
移动类型是实体设定的一种物理引擎检测的方式,比如直线飞行
,抛物线飞行
,抛物线并且带弹开效果(参考手雷撞击墙壁)
,光线的折射弹开效果(反射效果)
,完全不动
等等,这些都属于移动类型。
每个实体几乎都具备上述的其中(可能没有包含所有)
一个条件,比如玩家的移动类型是 MOVETYPE_WALK
,手雷是 MOVETYPE_BOUNCE
移动类型有大量返回值,你可以参考下面的 移动类型(MOVETYPE) 表
来查看详情
引用于 >> hlsdk_const.inc
MOVETYPE_NONE = 0 //不移动
MOVETYPE_WALK = 3 //在地上移动(只能用于玩家实体上)
MOVETYPE_STEP = 4 //有重力,特殊边缘处理(用在怪物实体上 HL ?)
MOVETYPE_FLY = 5 // 没有重力,但能和实体碰撞(如果有推力 呈直线飞行)
MOVETYPE_TOSS = 6 //有重力,能和实体碰撞(如果有推力呈 抛物线飞行)
MOVETYPE_PUSH = 7 //no clip to world , push and crush (具体不明)
MOVETYPE_NOCLIP = 8 //没有重力没有碰撞,只移动(穿墙用)
MOVETYPE_FLYMISSILE = 9 //给怪物实体设定额外尺寸(不理解)
MOVETYPE_BOUNCE = 10 //和 MOVETYPE_TOSS 差不多,但会弹起来(TOSS是停在地上)
MOVETYPE_BOUNCEMISSILE = 11 //如光线反射,没有重力的飞行,弹开
MOVETYPE_FOLLOW = 12 //跟随瞄准的实体(需要设置 pev_aiment ; 参考帽子插件)
MOVETYPE_PUSHSTEP = 13 //需要物理效果,世界的碰撞BSP地图模型(用于服务器中的NPC)
示例:
pev(id, pev_movetype)
通过上述代码得到的返回值就是了。
set_pev(id, pev_movetype, MOVETYPE_NOCLIP) //设定目标id(index)为穿墙的移动方式
不同的固体类型(pev_solid) 决定了实体目标的穿透性
若两个玩家在一起互相碰撞,他们只会撞在一起,而不会穿透过去 这就是Solid
的阻挡效果
很多实体都拥有 pev_solid
,比如手雷飞出去撞击玩家
后会弹开
那到底有哪些呢?和 pev_movetype
移动类型一样,pev_solid
也拥有一些返回值
引用于 >> hlsdk_const.inc
SOLID_NOT = 0 //对其他实体没有任何作用,例如无碰撞
SOLID_TRIGGER = 1 //与实体的边缘发生碰撞效果,但不会挡住实体
SOLID_BBOX = 2 //与实体边缘产生碰撞,并且挡住实体
SOLID_SLIDEBOX = 3 //与实体边缘发生碰撞效果,但被撞击的这个实体必须不在地上
SOLID_BSP = 4 // BSP clip ,与实体的边缘发生碰撞效果,挡住实体 (Clip 是一些手雷或子弹能穿过的透明墙,而玩家不能穿过)
设置或获取的方法 与 pev_movetype
大同小异。
示例:
pev(id, pev_solid)
set_pev(id, pev_solid, SOLID_BBOX)
注意:
SOLID_TRIGGER
在某些情况下不能直接设置,不然服务器会崩溃。
通过获取两个目标的坐标点,我们可以取得他们的间隔距离
要知道距离,我们必须知道两个坐标点
位置,坐标点的获取方法可以参考之前的教程
通过 pev_origin
获取两个坐标点之后,接下来要做的就是获取距离
获取距离的代码是 get_distance_f
,该代码有两个参数
1. 坐标点A
2. 坐标点B
比如我们取到的两个坐标点分别是 org1
和 org2
就可以这样写:
get_distance_f(org1, org2)
然后他就会通过这两个坐标点自动帮我们算出距离,我们利用这个距离的返回值
就可以了
示例:
new Float:iDist = get_distance_f(org1, org2)
client_print(id, print_chat, "两点的距离是: %.0f", iDist)
我们的视角瞄准角度
,或扔出的手雷他飞向哪边
等等,都可通过 pev_angle
来取得方向
通过 pev_angles
可以取得目标角度,该代码也是类似于 pev_origin
的三次数组
示例:
new Float:ang[3]
pev(id, pev_angles, ang)
ang[0] //X轴(上下角度)
ang[1] //Y轴(左右角度)
ang[2] //Z轴(倾斜角度)
注意:我们不能用
pev_angles
代码直接为玩家设置角度,还需要一个代码:pev_v_angle
,他和pev_angles
的区别仅仅是上下相反。
另外对于玩家来说还需要用到pev_fixangles
才能成功修改角度
示例:
new Float:ang[3]
set_pev(id, pev_angles, ang)
set_pev(id, pev_v_angle, ang)
set_pev(id, pev_fixangle, 1)
在很多情况下,我们需要执行一个带延迟的函数,这种情况下需要用到 set_task
来完成
示例:
set_task(2.0, "headfunc", id)
set_task
拥有三个参数(也有更多 但这里不讲),他们分别如下:
1.延迟的时间(浮点数)
2. 延迟执行什么函数(填写函数名)
3. 延迟执行的触发者(填写索引)
比如我们要用 set_task
延迟 10秒 触发 thefunc 函数 ,可以这样写:
#include <amxmodx>
public plugin_init()
{
register_clcmd("say /test", "testfunc")
}
public testfunc(id)
{
set_task(10.0, "thefunc", id)
}
public thefunc(id)
{
client_print(id, print_chat, "触发测试")
}
很多情况下都会用到循环,他可以帮助我们实现不同的效果以及获取更多的数据
当我们需要通过 AMXX 插件获取玩家人数的时候,或者 需要用循环给所有符合条件的玩家 执行一些命令 就需要用到循环
示例如下,创建 i 作为索引 循环 32 个目标
for(new i=1; i<33; i++)
比如说,我们需要输入一个命令然后干掉所有的目标,可以像下面这样写:
#include <amxmodx>
public plugin_init()
{
register_clcmd("say /kill", "kill_all")
}
public kill_all(id)
{
for(new i=1; i<33; i++)
{
if(!is_user_alive(i)) continue
user_kill(i)
}
}
循环主代码为 for
定义首先是 new i = 1
,然后用了 i < 33
来表达需要循环的次数,其中 33
代表玩家数量(预留一位)
在循环中, 代码 continue
是用来 忽略该目标,比如说找到了一个 死亡的玩家,那么如果用 continue 来判断的话,循环不会终止,而只是会忽略那个判断到的目标,而继续执行循环
其中,我们新建了一个叫 i
的索引,他是用来存储我们循环到的目标的,比如说通过循环找到的目标 如果定义为 i
那么我们随时都可以使用这个新的索引来帮助我们执行一些效果
代码中 user_kill
是杀死玩家的函数(amxmodx.inc
),这里填写的索引就是 i
而不是 id
(不然你只会把自己杀死)
有时候我们可能会遇到,获取目标数量的问题,我们同样可以用到循环来解决问题
示例:
#include <amxmodx>
public plugin_init()
{
register_clcmd("say /get", "get_playernumber")
}
public get_playernumber(id)
{
new xp = 0
for(new i=1 ; i<33; i++)
{
if(!is_user_alive(i)) continue
xp += 1
}
client_print(id, print_chat, "存活的玩家数量是 : %d 个", xp)
}
和上一个例子几乎一样,不过这里添加了一个临时变量 xp
,这个临时变量是用来充当计数器的,每次循环的时候 continue
会阻止不符合条件的目标,然后会触发 xp += 1
这个时候,xp变量中的值就会随着循环到的目标数量而增加,然后我们用 client_print
再调用 xp
临时变量的值 就可以显示了
在某些情况下,我们可能需要改变玩家的重力,越轻跳得越高
实现的代码为 pev_gravity
(PEV函数)
示例:修改玩家重力为200.0
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 是取决于 服务器参数 sv_gravity
的
所以如果我们要实现一个完美的重力设置,需要这样写:
写法(1):用变量分开再最终组合
new Float:setgravity = 200.0
new Float:getserver = get_cvar_float("sv_gravity")
set_pev(id, pev_gravity, setgravity / getserver)
写法(2):直接组合
set_pev(id, pev_gravity, 200.0 / get_cvar_float("sv_gravity"))
以上这两种方法都可以实现 同一个目的
注意:代码中的
/
是计算方式的 除以
有些情况下,我们需要打断原有的数据
比如:我们按G键可以丢弃一把武器,但是我们不希望他被丢弃
这种情况下,我们需要打断原有数据
G键的默认命令是 drop
也就是丢弃武器。我们可以 HOOK(勾住)
这个命令以实现我们的目的
这里我们用 register_clcmd
就可以了,示例如下:
#include <amxmodx>
register_clcmd("drop", "dropfunc")
public dropfunc(id)
{
client_print(id, print_center, "你触发了丢弃命令。")
}
可是这样不能达成我们的目的,武器依然被丢弃了,我们现在只是可以在 按[G]键 的时候提示一下信息
所以,我们需要打断原有数据,让其不丢弃武器
这里我们需要用到 返回
,代码为 return
,但是 我们用到的不是一般的返回,而是带有特定返回值的返回
打断这种丢弃数据需要用到的返回值是 PLUGIN_HANDLED
配合返回
代码 我们组合后可以写出这样:
return PLUGIN_HANDLED
这就是我们需要的打断效果。通过组合后我们可以得到这样的代码:
#include <amxmodx>
public plugin_init()
{
register_clcmd("drop", "dropfunc")
}
public dropfunc(id)
{
client_print(id, print_center, "你无法丢弃武器。")
return PLUGIN_HANDLED
}
编译后再测试的话就是这样的效果了:
注意:
通过drop
这个命令进行hook,再配合返回值PLUGIN_HANDLED
我们可以完全阻断丢弃武器的事件,但如果玩家死亡的时候,武器依然会掉落
你可以查看 低难度 (上一节) / 升级难度(下一节)