一、技能系统设计思想
二、模型层与挥出一刀
(一)添加玩家攻击状态
在State文件夹中添加一个脚本
这个脚本继承状态基类StateBase;并且持有玩家控制器;
先进行初始化,大体上与移动逻辑一致
然后重写基类里面的周期函数
public class Player_Attack : StateBase<PlayerState>
{
public Player_Controller player;
public override void Init(FSMController<PlayerState> controller, PlayerState stateType)
{
base.Init(controller, stateType);
player = controller as Player_Controller;
}
public override void OnEnter()
{
//攻击
Attack();
}
public override void OnExit() { }
public override void OnUpdate() { }
public void Attack() { }
}
(二)移动状态切换到攻击状态
1、先在玩家控制器中添加一个枚举状态(攻击)
2、写一个方法判断是否是攻击状态
3、状态切换
需要在移动的代码中时刻判断当前的枚举状态
(三)模型层驱动动画
先添加一个Bool值的变量 判断移动和攻击状态的切换
注:不需要退出时间
在模型层代码中,调用这个动画
(四)攻击动画的动画事件
1、动画添加动画事件
对应事件函数
//开启技能伤害
private void StartSkillHit()
{
//开启刀光的拖尾
//启用伤害检测的触发器
}
//停止技能伤害
private void StopSkillHit()
{
//关闭刀光的拖尾
//停止伤害检测的触发器
}
//技能结束
private void SkillOver()
{
animator.SetBool("攻击", false);
player.ChangeState<Player_Move>(PlayerState.Player_Move);
}
2、Bug解决方法
在调用了攻击的方法之后
会出现人物攻击之后,无法运行
原因是:当前接管人物的还是Play_Attack状态,而不是Play_Move状态
因此需要在攻击结束的方法中传递泛型(移动状态)
攻击时会调用这个事件,所以接管人物状态重新变为移动
三、武器层与武器拖尾
1、拖尾及触发器制作
2、代码实现
先声明变量 触发器、拖尾组件
先初始化,将这两个组件设置为false
在调用时,设置为true
因为停止攻击时候,要全部设置为false,所以就直接调用这个停止的方法
注:拖尾组件有单独的接口开关
3、判断怪物的受攻击次数
当玩家的面前有多个怪物,碰撞体较大,可能会出现多次触发的情况
因此需要保证:目标是怪物,并且是第一次触发
使用一个List集合,然后每一次攻击往这个集合里面添加一个对应的敌人
攻击结束后清除。
public class WeaponCollide : MonoBehaviour
{
public BoxCollider BoxCollider;
public TrailRenderer TrailRenderer;
private List<GameObject> monsterList;
public void Init()
{
//BoxCollider.enabled = false;
//TrailRenderer.emitting = false;
monsterList = new List<GameObject>();
StopSkillHit();
}
public void StartSkillHit()
{
BoxCollider.enabled = true;
TrailRenderer.emitting = true;
}
public void StopSkillHit()
{
BoxCollider.enabled = false;
TrailRenderer.emitting = false;
//清空怪物列表
monsterList.Clear();
}
private void OnTriggerEnter(Collider other)
{
//保证一段伤害只会击中一次怪物
//对方是怪物,并且我此次攻击第一次碰到他
if (other.tag == "Monster" && !monsterList.Contains(other.gameObject))
{
//输出伤害
monsterList.Add(other.gameObject);
//TODO:实际输出伤害给敌人,附加硬直、击退、击飞、生命值消减...
}
}
}
四、怪物受伤:硬直、击退、掉血
1、怪物的动画设置
一般怪物会有多个受伤的动画,进行切换调用。
首先给怪物模型一个父物体Monster
设置三个触发状态,受伤结束返回待机状态,两个受伤状态切换条件是对方
全部取消退出时间
在模型层实现动画的跳转
声明变量动画控制器;声明一个当前动画的索引
初始化获取这个动画组件
写一个方法,播放当前的受伤动画,因为加了一
所以先执行受伤1,然后判断,如果当前是受伤1,就调用受伤2
写一个受伤结束的方法,将触发器播放为受伤结束,动画执行完会回到待机状态
public class Monster_Model : MonoBehaviour
{
private Animator animator;
private int currHurtAnimationIndex = 1;//当前受伤动画的索引
public void Init()
{
animator = GetComponent<Animator>();
}
public void PlayHurtAnimation()//播放受伤动画
{
animator.SetTrigger("受伤" + currHurtAnimationIndex);
if (currHurtAnimationIndex == 1) currHurtAnimationIndex = 2;
else currHurtAnimationIndex = 1;
}
public void StopHurtAnimation()
{
animator.SetTrigger("受伤结束");
}
}
在怪物控制层实现调用逻辑
public class Monster_Controller : MonoBehaviour
{
private Monster_Model model;
private int hp = 100;
private void Start()
{
model=transform.Find("Model").GetComponent<Monster_Model>();
model.Init();
}
//受伤
public void Hurt()
{
//注意目前都是采用硬编码,先实现功能
//硬直与播放动画
model.PlayHurtAnimation();
CancelInvoke("HurtOver");//取消之前可能还在执行中的硬直
Invoke("HurtOver", 3);//一秒硬直
//击退 击飞
//生命值减少
}
private void HurtOver()//受伤结束
{
model.StopHurtAnimation();
}
}
2、怪物的受伤逻辑
怪物受伤会有三种效果:硬直、击退、掉血
硬直
使用延迟函数和取消延迟函数的方法,播放受伤动画并且持续一段时间
击退
首先需要几个变量
1、布尔值是否击中
2、V3变量 受击的位移
3、受击过渡时间
4、当前时间
首先在Update中进行一直判断是否受到伤害,而这个条件会在伤害方法调用时,置为true
使用Ucc在进行位移,好处是不会穿模,对应的API有Move和SimpleMove
效果是受击后有一个向上的位移然后向下,所以else中给出一个向下的位移
五、ScriptableObject基本使用
代码需要继承ScriptableObject
一般用作配置数据等功能,也支持Resource.Load的方法
代码开头可以使用编辑器扩展功能,CreateAssetMenu(),这是一个特性
filename是这个配置文件创造出来的默认名称,后续可以修改,所以比较鸡肋
menuname是一个路径
写三个类并且在上面持有这三个类,方便再别的代码中调用类中的配置文件
无法通过声明这个代码调用类方法。只能配置文件持有这个类在调用类中的配置信息
类中的信息如果显示出来,需要一个特性Serializable
[CreateAssetMenu(fileName = "技能配置", menuName ="配置/技能配置/技能数据")]
public class Conf_SkillData : ScriptableObject
{
//技能名称
public string Name;
//释放数据
public Skill_ReleaseModel ReleaseModel;
//命中数据
public Skill_HitModel HitModel;
//结束数据
public Skill_EndModel EndModel;
/// <summary>
/// 技能释放
/// </summary>
[Serializable]
public class Skill_ReleaseModel
{
}
/// <summary>
/// 技能命中
/// </summary>
[Serializable]
public class Skill_HitModel
{
public int DamageValue;
}
/// <summary>
/// 技能结束
/// </summary>
[Serializable]
public class Skill_EndModel
{
}
}