[Unity Demo]从零开始制作空洞骑士Hollow Knight第十六集(下篇):制作小BOSS龙牙哥

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

hello大家好久没见,之所以隔了一天时间才来更新是因为CSDN有个限制每天发图片的数量,然后昨天我喜提24小时冷却,现在终于有被放出来了就来讲讲上期遗漏的内容,来介绍我们这期的主角!


一、制作小BOSS龙牙哥

1.导入素材制作动画

看到这里你可能会觉得,就上面几个敌人还不够自己塞牙的,行为逻辑也没有看上去这么难理解,感觉没什么技术含量,但是你知道我专门会把有一些难度的内容放到最后面来讲,因此在这一节制作的敌人更是重量级,它是谁呢?当然是令空洞萌新胆寒的三大新人杀手之一------龙牙哥:

对于它的动画,首先介绍攻击分为慢攻击attack和快攻击attack2:

Stomp即脚踩地面制造两个方向的冲击波的动画,它也分为三个阶段:

摇摆龙牙时的动画:

我们先来制作龙牙哥的子对象:

它拥有警觉区域和攻击区域两个alert Range

攻击时产生的烟尘粒子系统:

跑步时扬起的灰尘粒子系统:

攻击时产生的岩石粒子系统

这个是践踏地面时产生的岩石粒子系统:

判断头顶有无撞到Terrain层级的地板

这个Swipe相当于上一期我讲到的僵尸防御者的slash,只有在攻击的时候才打开,注意这里的damageHero的伤害值要设置成2(所以说为啥是萌新杀手)

践踏产生的灰尘

这个是和梦之钉有关的,先别管:

回到主体对象,把敌人该有的脚本都给他添加上去:

2.制作两种攻击行为

制作一个同名脚本"Zombie Guard"的playmakerFSM:

设置好相应的变量和事件

初始化阶段,设置好hero,self的引用找到子物体的attack range,设置好roam L和R

开始时的朝向:

然后进入打瞌睡阶段:注意勾选上everyframe每帧都在检测

如果检测到了两个条件都符合触发ATTACK ALERT事件或者被玩家用骨钉抽了触发TOOK DAMAGE事件进入wake状态

等个0.21s再来处理接下来的事:

进入Idle 状态:

根据不同的Bool All True满足条件我们发送不同的事件

首先看看ATTACK ALERT事件,它的接受者叫状态Face Hero,这里的CameraShake是后续才用到的,这里你可以先到CameraParent中添加好对应的事件名和变量名以防止报错。

设置好速度的正负值

随机选择发送一个事件:

这些变量有关In A Row的都是防止运气太差连续几次都播放同一种行为而加以限制的,比如这里的Clubs In A Row如果连续触发四次,就会返回到Attack Choice状态中,毕竟不怕一万,只怕万一嘛

准备攻击阶段:

攻击阶段,记得要激活Swipe

视觉效果和听觉效果展示:

这里根据Facing Right变量来判断生成slam和swipe的位置:

攻击产生的后坐力阶段:

攻击结束,准备回到冷却阶段:

我们再来随机发送事件的第二个分支:

践踏行为准备阶段:

起跳阶段:

注意这个JUmp Velocity是指横向的速度,并不是y方向上的

这里除了生成了音效,slam effect以外,还生成了左右两个方向上的冲击波

Stomp行为结束,回到cooldown状态:

打断一下,我们先来做冲击波Shockwave预制体:

首先制作子对象:我咧个滚滚浓烟

爆出来的石头:

一个平面Plane

制作playmakerFSM"shockwave":

开始的阶段

开始移动:速度逐帧递增

如果碰到墙壁或者地下的Terrain检测不到了,就结束吧

如果击中玩家了:

cs 复制代码
using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
    [ActionCategory(ActionCategory.GameObject)]
    [Tooltip("Spawns a prefab Game Object from the Global Object Pool on the Game Manager.")]
    public class SpawnObjectFromGlobalPoolOverTimeV2 : FsmStateAction
    {
	[RequiredField]
	[Tooltip("GameObject to create. Usually a Prefab.")]
	public FsmGameObject gameObject;
	[Tooltip("Optional Spawn Point.")]
	public FsmGameObject spawnPoint;
	[Tooltip("Position. If a Spawn Point is defined, this is used as a local offset from the Spawn Point position.")]
	public FsmVector3 position;
	[Tooltip("Rotation. NOTE: Overrides the rotation of the Spawn Point.")]
	public FsmVector3 rotation;
	[Tooltip("How often, in seconds, spawn occurs.")]
	public FsmFloat frequency;
	[Tooltip("Minimum scale of clone.")]
	public FsmFloat scaleMin = 1f;
	[Tooltip("Maximum scale of clone.")]
	public FsmFloat scaleMax = 1f;

	private float timer;
	public override void Reset()
	{
	    gameObject = null;
	    spawnPoint = null;
	    position = new FsmVector3
	    {
		UseVariable = true
	    };
	    rotation = new FsmVector3
	    {
		UseVariable = true
	    };
	    frequency = null;
	}

	public override void OnUpdate()
	{
	    timer += Time.deltaTime;
	    if(timer > frequency.Value)
	    {
		timer = 0f;
		if(gameObject.Value != null)
		{
		    Vector3 a = Vector3.zero;
		    Vector3 euler = Vector3.up;
		    if (spawnPoint.Value != null)
		    {
			a = spawnPoint.Value.transform.position;
			if (!position.IsNone)
			{
			    a += position.Value;
			}
			euler = ((!rotation.IsNone) ? rotation.Value : spawnPoint.Value.transform.eulerAngles);
		    }
		    else
		    {
			if (!position.IsNone)
			{
			    a = position.Value;
			}
			if (!rotation.IsNone)
			{
			    euler = rotation.Value;
			}
		    }
		    if (gameObject != null)
		    {
			//TODO:
			GameObject gameObject = Object.Instantiate(this.gameObject.Value, a, Quaternion.Euler(euler));
			if (scaleMin != null && scaleMax != null)
			{
			    float num = Random.Range(scaleMin.Value, scaleMax.Value);
			    if (num != 1f)
			    {
				gameObject.transform.localScale = new Vector3(num, num, num);
			    }
			}
		    }
		}
	    }
	}
    }
}

真正有造成伤害和图像显示的其实是Shockwave Spurt,上述的Shockwave顶多算个底盘,用来制作粒子系统和处理判断是否击中玩家和离开墙壁的行为。

制作playmakerFSM:主要是做造成伤害的时间段

Shockwave spurt L也是同理,区别在于记得设置它的rotation为180,这里我们用playmaker来实现:

3.制作从惊醒到转身到走路or跑步行为

回到龙牙哥的playmakerFSM来,我们在idle还有两个事件没有接受者,

先看TRUE状态下,进入惊醒状态Statle

检查方向:

这里的HERO ABOVE事件到底要怎么触发呢,当然是我们上面讲到的子对象Overhead Detect,给它一个新的playmakerFSM:在它的变量string类型添加上事件名字

接着回来制作Check Right和Turn Right

再来制作Turn Left和CheckLeft状态:

如果不用Turn,直接顺着FALSE事件来到追逐chase状态:

如果决定进入走路状态:

跟丢了话就进入丢失玩家Lose Hero状态:

ATTACK ALERT来到Face Hero状态

WAIT就回到Alert状态

RUN就来到Run状态:

Stop Run状态:

ATTACK ALERT的话来到Face Hero状态

WAIT就回到Alert状态

如果Idle状态上过了四秒钟都没有检测到要发送ATTACK ALERT和ALERT事件,我们就发送WAIT事件

总结一下就是,刚开始龙牙哥在初始化阶段后进入睡眠阶段,当玩家进入can see hero和alert range范围后龙牙哥就进入苏醒阶段,如果过了4秒玩家离开区域后就设置好朝向,如果突然返回了就发送惊醒alert阶段,然后就开始根据距离决定跑步还是走路接近玩家,当进入attack range距离后就开始进入Face hero阶段,然后根据random二选一一种攻击方式,第一种是挥舞龙牙的行为,第二种是践踏地面产生冲击波伤害玩家行为。其实理一下还是比较简单的,只是连线太多了给人一种很晕的感觉。


总结

最后我们来看看效果吧:

直接干两滴血真的bt:

压迫感来了:

超出距离的就一直盯紧玩家:

相关推荐
神仙别闹几秒前
基于C#和Sql Server 2008实现的(WinForm)订单生成系统
开发语言·c#
向宇it9 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
九鼎科技-Leo10 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
Heaphaestus,RC11 小时前
【Unity3D】获取 GameObject 的完整层级结构
unity·c#
芋芋qwq11 小时前
Unity UI射线检测 道具拖拽
ui·unity·游戏引擎
baivfhpwxf202311 小时前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#
直裾11 小时前
Scala全文单词统计
开发语言·c#·scala
tealcwu12 小时前
【Unity服务】关于Unity LevelPlay的基本情况
unity·游戏引擎
ZwaterZ13 小时前
vue el-table表格点击某行触发事件&&操作栏点击和row-click冲突问题
前端·vue.js·elementui·c#·vue
大眼睛姑娘14 小时前
Unity3d场景童话梦幻卡通Q版城镇建筑植物山石3D模型游戏美术素材
unity·游戏美术