系列文章目录
? ? ? ? (更新中。。。)
前言
上一章记录了人物的攻击实现和攻击有效判定,这里实现人物的受伤判定。
实现效果:(敌人的实现见下一章)
提示:以下是本篇文章正文内容,下面案例可供参考
一、人物受伤逻辑分析
三个主要脚本:
Damageable脚本,挂在受攻击对象上,负责接收从对方武器(meleeWeapon)传递的伤害信息,对伤害(Message)进行处理 -->?根据不同的受击效果调用不同委托事件? -->? ?最后将必要的信息传递给伤害接收者。(当然不一定要有接收者,看有没有需要复杂信息传递)
IMessageReceiver接口: 自行定义的接口,在有需要接收伤害信息的对象上实现接口,实现在不同对象受伤或死亡的复杂伤害信息接收。
二、人物受伤和死亡动画逻辑
定义两个trigger参数,连接到在Anystate上;
三、人物受伤脚本实现
1.Damageable脚本(受击对象上)
这个脚本存储了玩家的血量,对伤害的接收处理,和不同伤害事件的响应。
编辑器中的设置:
代码如下(示例):
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
//My受伤反馈脚本
namespace MyPlayer
{
public partial class MyDamageable : MonoBehaviour
{
[SerializeField]
protected int curHitPoints;//当前血量
protected Action schedule;//多播委托
protected float myInvincibleTime = 3.5f;//无敌时间
public int myMaxHipPoints;//最大血量
public bool invincible = false;//无敌的
public TextMesh m_HitPointsShow;//血量显示
public UnityEvent OnDamage, OnDeath, OnResetDamage, OnBecmeVulnerable, OnHitWhileInvulunerable;//不同的受伤事件
//[EnforceType(typeof(MyMessage.IMessageReceiver))]
//public MonoBehaviour[] DemageReceiver;
public List<MonoBehaviour> onDamageMessageReceivers;//伤害接收者,不一定有必要
public int CurHitPoint { get { return curHitPoints; } }
public void OnReSpawn()//复活
{
invincible = true;
myInvincibleTime = 3.5f;
OnResetDamage.Invoke();
curHitPoints = myMaxHipPoints;
}
private void Awake()
{
curHitPoints = myMaxHipPoints;
invincible = false;//开始有一段无敌时间
if(m_HitPointsShow)
m_HitPointsShow.text = curHitPoints.ToString();
}
//受到攻击时调用
public bool OnGetDamage(MyDamageable.DamageMessage data)
{
MyMessage.MesssageType type;
if (invincible || curHitPoints <=0)
{
return false;
}
curHitPoints -= data.amount;
if (m_HitPointsShow)
m_HitPointsShow.text = curHitPoints.ToString();
if (curHitPoints <= 0)
{
schedule += OnDeath.Invoke;//死亡
type = MyMessage.MesssageType.Death;
}
else
{
schedule += OnDamage.Invoke;//仅仅受伤
type = MyMessage.MesssageType.Damage;
}
for (int i = 0;i< onDamageMessageReceivers.Count; i++)//向接收者传递信息
{
var receiver = onDamageMessageReceivers[i] as MyMessage.IMessageReceiver;
receiver.OnMessageReceive(type,data.damager,data);
}
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;
}
}
private void Update()
{
if(invincible)//处于无敌状态
{
myInvincibleTime -= Time.deltaTime;
if(myInvincibleTime <= 0)//无敌时间到
{
invincible = false;
myInvincibleTime = 3.5f;
OnBecmeVulnerable.Invoke();//恢复正常状态,直接调用,不委托
}
}
}
}
}
2.IMessageReceiver接口
定义了伤害信息的类型和伤害接收的接口。
代码如下(示例):
namespace MyPlayer
{
namespace MyMessage
{
public enum MesssageType
{
Damage,Death,Respawn
}
public interface IMessageReceiver//接口
{
void OnMessageReceive(MesssageType type, object sender, object obj);
}
}
}
2.IMessageReceiver接口实现(PlayerController上)
代码如下(示例):
public class PlayerController : MonoBehaviour, IMessageReceiver
{
//省略前面脚本内容
public void OnMessageReceive(MesssageType type, object sender, object data)//实现消息接收的接口
{
switch (type)
{
case MesssageType.Damage:
{
MyDamageable.DamageMessage m_data = (MyDamageable.DamageMessage)data;
Damaged(sender,m_data);
}
break;
case MesssageType.Death:
{
MyDamageable.DamageMessage m_data = (MyDamageable.DamageMessage)data;
Death(sender,m_data);
}
break;
case MesssageType.Respawn://这个没什么必要
break;
}
return;
}
private void Damaged(object sender, MyDamageable.DamageMessage data)
{
if(isDeath || m_damage.CurHitPoint <= 0)//无敌状态或者死亡状态
{
return;
}
//伤害来源进行省略
Vector3 direction = data.damageSource - transform.position;
direction = transform.InverseTransformPoint(direction);
direction.y = 0f;
print("x :" + direction.x + "y:" + direction.z);
m_animator.SetFloat(hashOfHitFromX,direction.normalized.x);
m_animator.SetFloat(hashOfHitFromY,direction.normalized.z);
m_animator.SetTrigger(hashOfHurt);//设置受伤trigger
if (m_HurtAudioPlayer)
m_HurtAudioPlayer.PlayAudioRandomly(null);
}
private void Death(object sender,MyDamageable.DamageMessage data)
{
isDeath = true; //死亡
m_DeathAudioPlayer.PlayAudioRandomly(null);//死亡音效
m_animator.SetTrigger(hashOfDeath);//设置死亡trigger
m_animator.ResetTrigger(hashOfHurt);//重置受伤trigger,避免状态重叠
}
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了Unity中的伤害的传递和接收,这只是其中的一种方法,今后还会继续完善,希望大家多多支持~~博主会继续更新~?
|