amxx插件开发新手教程5-轻难度
条评论前言
我们这一章节将会再深入了解amxx插件的开发,通过本篇文章,你将可以掌握游戏实体、以及更多pev和ham的内容。有疑问可以在文章底部留言。
修改目标生命值
我们可以通过pev来修改玩家生命值
示例:
1 | set_pev(id, pev_health, 120.0) |
我们可以看出来,上面这个代码可以将目标的血量改成指定的值
仅仅是这样还不够,我们大部分需要的效果是加血(在当前生命值的情况下添加指定值)
思路:首先我们需要获取玩家生命值,然后再通过获取到的值来进行添加生命值
获取生命值:
1 | new Float:hp |
上例中存储到hp变量之后,那么此时要做的就是设定生命值=(当前生命值 + 添加的值)
即:
1 | new Float:hp |
注意:
- 索引(index)必须是有效的,不能是非玩家实体并且还没用(比如地图本身)
- 设定的生命值 或者 添加值 必须是浮点数。不然你会发现本来设定140的生命值变成 49239239932 巨大数值了
- 除了 hp + 40.0 你还可以 hp - 40.0,发挥你的想象力吧(不过除法就算了,因为大概会变成0血)
死亡之后重生
虽然说是死亡后重生,但是实际上我们还可以做到即使活着也能重新复活
当然这样就不具有实际价值,只是少加一个判断而已,我们还是做我们需要的目标吧
我们需要用到hamsanwich模块中的ExecuteHamB来触发Ham函数
触发HAM是什么意思?
Ham事件不止可以用来勾住,也可以直接用来触发(触发的时候也可以被勾住)。
比如爆炸的时候造成的伤害我们就可以触发出来,这样即使原有不存在的效果,我们也可以自己做出来
对于Ham事件来说,重新复活的事件代码是Ham_CS_RoundRespawn
我们通过ExecuteHamB来触发这个事件
示例:
1 | ExecuteHamB(Ham_CS_RoundRespawn, id) //通过触发Ham事件中的 Ham_CS_RoundRespawn 来让 id 复活 |
那应该怎么写才能实现死亡后复活?
很简单,我们需要先勾住玩家的死亡事件,然后触发函数,通过这个被触发的函数来延迟复活玩家
不太理解吗?
示例:
1 |
|
注意:
- 写代码的时候需要考虑全面,比如玩家在复活函数被延迟触发的时候,此时玩家已经处于存活状态,此时就不应该继续执行复活代码,所以我们应该添加一个
返回。不然玩家会在延迟时间达到的时候重新又复活一次,这样的效果是我们不希望见到的。 - 延迟函数的时候,触发的函数名一定要和被触发的函数名一致,并且要注意是否大小写一致(不一致的大小写会出现无法触发函数的问题)
- 这个代码只用到了
hamsandwich和amxmodx模块中的代码,所以这里不需要写上fakemeta
目标移动向量
在游戏中,玩家的每次移动或跳跃都是会改变pev_velocity移动向量(速率)的
其移动的向量也是一个数组和坐标系几乎一样,也是三个轴X, Y ,Z
其中Z轴表示了目标上升还是在下降
获取示例:
1 | new Float:vel[3] |
注意是需要新建的是浮点数的数组变量然后通过pev来获取并存储到新建变量中
其中vel[2]代表Z轴,其前面vel[0] (X轴)和vel[1] (Y轴)代表了左右 前后不同的移动方向
比如让目标向上飞起:
1 | new Float:vel[3] |
注意:
- 新建变量用来存储的时候,必须是浮点变量
- 如果
vel[2] (Z轴)中的浮点数值是正数那么代表正在上升或者原地不动,反之如果是负数 代表正在坠落或下降中
手雷的爆炸时间
本次要讲的是修改手雷爆炸时间。似乎这个方法对于烟雾弹没有效果,具体我没有去测试
代码pev_dmgtime用于获取或改变游戏中手雷的爆炸时间
可是应该怎么修改呢?
这里我们要用到一个函数FM_SetModel,这个函数会在设定模型的瞬间触发(本例中代表 投掷手雷的瞬间就会执行)
示例:
1 |
|
上例中,通过触发FM_SetModel事件勾住了我们的Fw_SetModel函数,
该函数中有两个参数,分别是:
- 实体
- 模型路径
什么是实体?
游戏中会见到各种形形色色的实体,比如爆炸点的箱子,安装之后在地上的C4炸弹,丢弃在地上的武器,投掷出去的手雷等等,这些都是实体,实体还分为点实体和固体实体,这里暂不细说。
刚刚我们稍稍了解了一下什么是实体,那么回到本例 即投掷出去的手雷(在空中飞的)就是一个实体
那么回到代码中:public Fw_SetModel(ent, model[])也就是说其中那个ent代表了飞行中的手雷
那么我们需要在这个函数中判断什么?首先需要添加
if(!pev_valid(ent)) return //无效实体即返回
示例:
1 | public Fw_SetModel(ent, model[]) |
为什么要判断 pev_valid( ) 无效的实体?
无效的实体即实体不存在了、实体被删除了、实体获取不到pev_valid()在我们后期制作插件的时候尤其重要,因为无效的实体会导致游戏崩溃或者卡住,甚至控制台报错
为了避免这些不必要的情况,为了代码的稳定性是必须添加这个的
那么接下来我们需要做的也不会太难,我们需要再添加一个判断,判断这个实体的实体名是不是手雷
什么是实体名?
实体名(pev_classname)是用来区分不同实体的最佳途径,对于CS来说几乎每个武器都有自己的实体名,手雷的实体名是grenade,玩家自己的实体名是player,爆炸点的箱子实体名是func_breakable等等。通过判断实体名我们可以清晰的分辨哪些需要修改,哪些是不必要的。
既然我们知道手雷的实体名是grenade接下来要做的也就很简单了:判断实体名是不是我们需要的那个
这里我们会用到一个equal字符串判断代码,稍后会讲到
首先获取实体名,注意这里的索引要改成ent了,因为我们获取的是别的东西
1 | new class[33] |
现在实体名已经存储到了class变量中,接下来我们要做的就是判断这个class中是否是grenade字符串。简单说就是 判断这个实体的名字是不是grenade
示例(判断是否是那个字符串):
1 | if(!equal(class, "grenade")) return //如果class变量中 不是 grenade 字符串 那么 返回 |
然后我们还需要判断一下模型路径,因为grenade实体名还可能包含C4炸弹 (安装后)或烟雾弹
和上面的写法一样 只是要改变一下 变量名
1 | if(!equal(model, "models/w_hegrenade.mdl")) return //如果字符串中的模型路径不是获取的那个 返回 |
我们可能需要同时使两个手雷类型**(高爆手雷,闪光弹)的时间都发生变化,此时我们要用到&&或||来添加多重判断**
示例:
1 | if(!equal(model, "models/w_hegrenade.mdl") && !equal(model, "models/w_flashbang.mdl")) return |
不太懂?那就用代码翻译一下 即:如果不是手雷的路径并且也不是烟雾弹的路径那么返回,这样就可以避免别的相同实体名使用这个函数了
我们组合一下代码就会变成下面这样:
1 |
|
写到这里,几乎就快完成目的了。接下来要做的就是修改手雷的爆炸时间,这里的手雷指的就是实体,所以我们写上ent
示例:
1 | set_pev(ent, pev_dmgtime, 爆炸时间) |
上面这段看上去没什么不对,但是实际上如果在游戏中测试的话,手雷扔出去后会瞬间爆炸所以我们还需要通过游戏时间来决定,配合get_gametime()完成最终效果吧!
1 | set_pev(ent, pev_dmgtime, get_gametime() + 12.0) //爆炸时间设定为 当前游戏时间 + 12秒 |
我们将所有代码组合一下,就会变成这样
1 |
|
如此,你就成功了
注意:
- 本次我们初次涉及到了实体,以后我们还会学习建立一个新的实体
- 如果你需要修改模型则需要将函数触发改为
post,对于当前代码来说即register_forward(FM_SetModel, "Fw_SetModel", 1)- 若将爆炸时间改成
set_pev(ent, pev_dmgtime, get_gametime())手雷将瞬间爆炸equal的判断需要注意 括号()的相符度,具体可参看我的写法
判断按键
判断玩家按的什么键,这是我们在后期经常会遇到的问题
如何解决呢?使用代码:pev_button即可
通过这个代码,可以获取到内置的一些键位,比如基础移动(A,S,D,W),鼠标左键,右键,*E键(使用键),R键(装子弹)*等等…
有哪些键位可以被获取到?
引用于 >> hlsdk_const.inc (你可以查看这个文件)
1 | IN_ATTACK //鼠标左键 |
那应该怎么写出判断代码?
比如说我们要判断:按下了鼠标左键,可以这样写:
1 | if(pev(id, pev_button) & IN_ATTACK) //如果玩家按了鼠标左键 |
其中
&相当于代表一个代码链接,让其获取到的结果对定义的键位进行对比
那如果要表达玩家没有按这个键呢?
我们以鼠标左键为例,需要添加一个!反义判断符
1 | if( ! ( pev(id, pev_button) & IN_ATTACK) ) |
单次键位判断
如果需要判断一个键位,是否处于按下但是没有持续按住的情况(比如手枪USP,按一下射一次) 应该怎么做?
这里我们还需要用到一个pev_oldbuttons,配合&&(并且)来判断上一次键位是否依然是那个
示例:
1 | //如果玩家按下了鼠标左键并且没有一直按住,即继续执行函数括号中的内容 |