实操挑战:羽落技能
终于,我们来到了这个教程的(或许是)最后一期!
这一次,我们将从挂钩开始做起,完整体验一个角色技能的制作过程。在阅读本文之前 我强烈建议你完成上一节的所有内容 并且阅读了序言中提到的C#基础知识。这将会大大降低本文的阅读难度,也有助于你灵活运用在这里学习到的内容。
设计算法
我们将要实现的效果是让玩家处在空中时 如果跳跃键被按下 则会减缓玩家的下落速度 松开按键后效果将会解除。要实现这个效果 需要先明确大致的实现方案,也就需要以自然语言或者流程图描述算法。
这里以自然语言描述羽落效果大致的算法如下:
- 重复执行以下的判断:
- 如果玩家是你的mod角色,并且当前正在空中且没有死亡或昏厥 则认为玩家满足技能条件
- 如果玩家满足条件且跳跃键被按下,则认为玩家进入羽落技能,否则退出羽落技能
- 当玩家羽落技能为真时,玩家下落时在垂直方向上的速度反复变为当前的0.2倍大小,并且播放特效
算法并不复杂 但是包含了不少细节。接下来的步骤将会解释如何完成这个算法。
技能实现
挂钩(Hook)
首先,你需要把钩子挂在一个会高速重复执行的原版方法上 并且最好能够跟玩家的状态相关联。因此 你可以猜测自己需要的就是玩家的更新方法。
在OnEnable方法里面写上On.Player. 然后找到名为Update的方法。
接下来 模仿另外几条的写法对它进行挂钩。你可以自己决定hook方法的名字,在这里我给它指定的名称为Player_Skills。
然后 在Plugin类的其他地方插入这一段
private void Player_Skills(On.Player.orig_Update orig,Player self , bool eu )
{
orig(self, eu);
//在这里插入技能实现
}
实际上这大致就是通用的挂钩思路:判断并且寻找到自己想要修改的原版方法,用On.语句建立委托,然后再根据特定的格式构造自己的方法。
判断是否是本Mod的角色
一般情况下其实没有必要像这个模板一样把每一个技能都写一个判断条件,对于大部分人来说 只要能判断这个角色是自己的一个mod角色就可以。因此你需要在Plugin类中插入一个字段
public static readonly PlayerFeature<bool> IsMyCat = PlayerBool("slugtemplate/is_my_cat");
//为了方便管理 字段一般都放在一个类里面的最上方 就像上次的那个jumpcount一样。
//"slugtemplate/is_my_cat"可以自行修改
//比如对于我的旅者mod,这个属性叫做"thetraveler/is_traveler_cat"
技能实现
首先,我们需要判断只对自己这个mod角色触发技能。向Player_Skills方法中插入这个判断
然后在里面插入是否可以使用技能的判断,用bodymode判断玩家是否处于空中bool can_slowfall =
self.Consious
&& self.bodyMode != Player.BodyModeIndex.Stand
&& self.bodyMode != Player.BodyModeIndex.Crawl
&& self.bodyMode != Player.BodyModeIndex.Stunned
&& self.bodyMode != Player.BodyModeIndex.Swimming
&& self.bodyMode != Player.BodyModeIndex.ClimbIntoShortCut
&& self.bodyMode != Player.BodyModeIndex.CorridorClimb
&& self.bodyMode != Player.BodyModeIndex.ClimbingOnBeam
&& self.bodyMode != Player.BodyModeIndex.WallClimb
&& self.bodyMode != Player.BodyModeIndex.ZeroG;
//如果玩家没有昏迷 且没有处在站立爬行眩晕游泳爬进捷径爬管道爬杆子爬墙也没有零重力漂浮...
//也即是说 用排除法判断玩家现在清醒在空中...
//并不是一个很高效的算法 过于冗长 但是相对来说比较好理解...你也可以试着写出自己的方案
//如果需要对一些细致的动作状态进行判断,可以使用self.animation和AnimationIndex
if (self.input[0].jmp && can_slowfall)
{
player_slowfall = true;
}
else
{
player_slowfall = false;
}
//根据玩家的跳跃键输入和玩家是否可以使用技能判断技能的开启与关闭
//input[0].jmp就是获取当前的跳跃输入,如果方括号里面是1则是获取上一次更新的输入
if (player_slowfall == true && self.mainBodyChunk.vel.y < 0f)
{
self.mainBodyChunk.vel.y *= 0.2f;
}
//如果玩家开启技能而且身体垂直速度小于0(也就是在下落)就把速度缩减到0.2倍
这样基本上就实现了这个技能!记得保存,编译一下然后重新加载这个mod 进游戏看看效果吧!另外你也可以尝试用自己喜欢的方式给它加一个特效。
关于咱的实现方法可以参考下面的示例代码。
示例
private void Player_Skills(On.Player.orig_Update orig,Player self , bool eu )
{
orig(self, eu);
Vector2 pos = self.mainBodyChunk.pos;
Room room = self.room;
if (IsMyCat.TryGet(self, out bool is_my_cat) && is_my_cat)
{
bool can_slowfall =
self.Consious
&& self.bodyMode != Player.BodyModeIndex.Stand
&& self.bodyMode != Player.BodyModeIndex.Crawl
&& self.bodyMode != Player.BodyModeIndex.Stunned
&& self.bodyMode != Player.BodyModeIndex.Swimming
&& self.bodyMode != Player.BodyModeIndex.ClimbIntoShortCut
&& self.bodyMode != Player.BodyModeIndex.CorridorClimb
&& self.bodyMode != Player.BodyModeIndex.ClimbingOnBeam
&& self.bodyMode != Player.BodyModeIndex.WallClimb
&& self.bodyMode != Player.BodyModeIndex.ZeroG;
if (self.input[0].jmp && can_slowfall)
{
player_slowfall = true;
}
else
{
player_slowfall = false;
}
if (player_slowfall == true && self.mainBodyChunk.vel.y < 0f)
{
self.mainBodyChunk.vel.y *= 0.2f;
room.AddObject(new ExplosionSpikes(room, pos, 3, 35f, 5f, 5f, 15f, Color.white));
}
}
}
//补充:其实这里有一个小问题,玩家的所在房间有时可能为空...
//虽然在这个例子里一般不会有问题....最好还是写一个判断条件来避免出现故障(
(起猛了 看到会轻功的蛞蝓猫)
总结
这个羽落技能并不复杂 但是也大致展示了完整的创建一个自定义技能的步骤 同样的思路也可以用于创建更多独特的自定义能力。因此千万不要让技术上的问题约束你的想象力。在大胆尝试和改错的过程中获取经验 并且多阅读和学习他人作品中的实现,这样才能取得进步。
至此 自定义角色的教程就告一段落了。自己或许还会继续更新一些补充篇目,解释如何添加自定义外观、修改场景和竞技场头像 或是添加Remix菜单(当然我认为你现在或许已经有能力自己去尝试实现这些部分了。
你也可以删掉所有不必要的代码和不想要使用的技能,然后根据已有的经验从头开始构建你自己想要的效果!如果有任何疑问也可以在这里留下评论 我会尽我所能给出解答————
总之 祝你好运啦 也期待看到你能做出让自己满意的作品!