系列文章目录
文章目录
目录
系列文章目录
文章目录
前言
一、攻击的准备
二. 武器跟随手部实现
三. 攻击动作逻辑实现
四. 武器的脚本的实现
五. 受攻击实现
总结
前言
本文记录本人在Unity3D中的案例的人物攻击和受伤逻辑的实现,受伤要结合被攻击对象的实现,所以这里主要还是攻击的实现。
? 实现效果:
一、攻击的准备
为人物的武器添加对应的组件,确保有控制器脚本,跟随手部脚本和box碰撞检测。?
二. 武器跟随手部实现
[DefaultExecutionOrder(9999)]
public class FixedUpdateFollow : MonoBehaviour
{
public Transform toFollow;
private void FixedUpdate()
{
transform.position = toFollow.position;
transform.rotation = toFollow.rotation;
}
}
比较简单,找到人物手部的骨骼对象,每帧使得武器中心和它的位置和方向一致就行。
三. 攻击动作逻辑实现
这里默认只有落地情况才能攻击,当然还可以实现空中攻击。?
?攻击状态机实现:
Attack1到4对应脚本:
实现传递攻击状态给playerController脚本?,激活武器和武器特效。
public class MyMeleeEffect : StateMachineBehaviour
{
public int index;
// OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
//动作开始时加载对应动作特效
MyPlayerController ctrl = animator.GetComponent<MyPlayerController>();
ctrl.m_playWeapon.timeEffects[index].Activate();
ctrl.isAttacking = true;
ctrl.PlayAttackAudio();
//将武器设置为attack状态
ctrl.MyMeleeAttackStart();
}
// OnStateExit is called when a transition ends and the state machine finishes evaluating this state
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
MyPlayerController ctrl = animator.GetComponent<MyPlayerController>();
ctrl.isAttacking = false;
}
}
四. 武器的脚本的实现
这里的事件是由武器的OntriggerEnter和OntriggerStay触发的,从而进入攻击状态。
public class MyPlayerWeapon : MonoBehaviour
{
public int damage = 1;
//攻击时的武器特效
public TimeEffect[] timeEffects;
public LayerMask m_TargetLayer;
public bool isAttacking;
public Transform attackPoint;
//事件可以绑定在状态机上,也可以就绑定在动画animation中
private void OnTriggerEnter(Collider other)
{
if (!isAttacking)//非攻击状态
{
print("非attack状态!");
return;
}
isAttacking = false;//一次碰撞只产生一次伤害
MyDamageable d = other.GetComponent<MyDamageable>();
if (d == null)
return;
CheckDamage(other);
}
void CheckDamage(Collider col)
{
MyDamageable.DamageMessage data = new MyDamageable.DamageMessage() ;
data.damager = this;
data.amount = damage;
data.damageSource = attackPoint.position;
var d = col.GetComponent<MyDamageable>();
if(d)
d.OnGetDamage(data);
}
}
五. 受攻击实现
在受攻击对象添加Damageable脚本,脚本包含本身的血量、受攻击的处理事件(每个对象受攻击后的处理方式不同),用来接收受击信息,受击信息包括受击伤害、受击点、受击方向、攻击对象、攻击对象坐标等。
主要用到一个多播委托,在unity编辑器中赋予受击事件,脚本中的适当时机调用受击后的事件。
public partial class MyDamageable : MonoBehaviour
{
[SerializeField]
protected int curHitPoints;
protected Action schedule;
public int myMaxHipPoints;
public bool invincible = false;//无敌的
public TextMesh m_HitPointsShow;
public UnityEvent OnDamage, OnDeath, OnResetDamage, OnBecmeVulnerable, OnHitWhileInvulunerable;
public void OnReSpawn()
{
curHitPoints = myMaxHipPoints;
}
private void Awake()
{
curHitPoints = myMaxHipPoints;
invincible = false;//开始可以有一段无敌时间
if(m_HitPointsShow)
m_HitPointsShow.text = curHitPoints.ToString();
}
//受到攻击时调用
public bool OnGetDamage(MyDamageable.DamageMessage data)
{
if (invincible || curHitPoints <=0 )
{
return false;
}
curHitPoints -= data.amount;
if (m_HitPointsShow)
m_HitPointsShow.text = curHitPoints.ToString();
if (curHitPoints <= 0)
{
schedule += OnDeath.Invoke;//死亡
}
else
{
schedule += OnDamage.Invoke;//仅仅受伤
}
return true;
}
//直接死亡
public bool Death()
{
if (invincible || curHitPoints <= 0)
{
return false;
}
curHitPoints = 0;
schedule += OnDeath.Invoke;
return true;
}
private void LateUpdate()
{
if(schedule!=null)
{
schedule.Invoke();//使用多播委托
schedule = null;
}
}
}
总结
一直以来最想做的就是人物的攻击模块,如果是简单的攻击很好实现,但是要做一个炫酷华丽而且流畅的动作系统,还是比较有难度的,主要是笔者主要是脚本的开发,动作或者特效什么的就基本没有开发经验,就局限性很大。。
|