前言
這篇學習,作用到(攻擊/治癒/BUFF)到目標後的邏輯處理.
步驟
1 到子彈接觸到目標後,會執行目標上AI腳本的BeHit方法
/// <summary>子彈打到目標,計算傷害值,根據玩家和敵人的屬性,在子彈所有人身上計算出目標承受的傷害值</summary>
public virtual void BeHit(AttackBullteS bullte)
{
//健壯性判斷
if (!CanProgramme()) return;
//判斷技能的類型,將目標設置爲施法者
if (targetObj == null && (bullte.skillData.attackType == SkillType.Attack || bullte.skillData.attackType == SkillType.None))
InputTargetObj(bullte.bullteOwner.gameObject);//如果沒有目標,目標設爲攻擊者
//這裏的操作是停掉所有協程
StopAllCoroutines();
//計算傷害
CostDamage(gameRoleProperty.DamageValue(bullte), bullte);
//計算buff
CostBuff(bullte);
//計算其他邏輯
}
2 計算傷害值,你需要施法者的數值和目標者的數值,進行計算得出,這裏我們定義一個傷害值類,通過一個方法得出
public class BeHitClass
{
//數值
public int damageValue;
/// <summary> 傷害類型,0普通,1暴擊,2治療</summary>
public int damageType = 0;
public float repelValue = 0;
public BeHitClass(int damagevalue, int damagetype)
{
damageValue = damagevalue;
damageType = damagetype;
}
public BeHitClass CloneMe()
{
BeHitClass result = new BeHitClass(damageValue, damageType);
result.repelValue = repelValue;
return result;
}
}
public BeHitClass DamageValue(AttackBullteS bullte)
{
//new一個BeHit類
BeHitClass result = new GameRoleAI.BeHitClass(0, 0);
//通過子彈,得到施法者的數值
GameRoleProperty roleProperty = bullte.bullteOwner.GetComponent<GameRoleProperty>();
//計算總傷害值
result.damageValue = GetDamageAmount(roleProperty, this);//一個公式
//計算多端傷害的比值
result.damageValue = (int)(result.damageValue * roleProperty.skillList[bullte.skillIndex].damageList[bullte.damageIndex].damageRate);
//計算其他
return result;
}
/// <summary> 受到傷害減血或者加血 </summary>
public virtual void CostDamage(BeHitClass damageValue, AttackBullteS bullte)
{
//健壯性判斷
if (bullte.skillData == null) return;
//決定數值類型,是skill中的參數,這點感覺有點彆扭,保留意見
float parammean = -1;//該次傷害產生的效果,(0:hp-)(1:hp+)(2:施法者hp+)(3:施法者hp-)(4:)
///傷害類型 0 : 普通傷害
parammean = bullte.skillData.GetParamByParamMean(0);
BeHitClass tempbehit;
if (parammean >= 0)
{
tempbehit = damageValue.CloneMe();
if (damageValue.damageType == 2) damageValue.damageType = 0;//如果是治療效果,則變成受傷害效果
gameRoleProperty.hpNow = Mathf.Clamp(gameRoleProperty.hpNow - tempbehit.damageValue, 0, gameRoleProperty.hpmaxNow);
gameRoleAnimator.Playinjury(tempbehit, bullte);//執行顯示數值的方法
//播放音效
if (gameRoleProperty.hpNow == 0)
{
ChangeSta2Die();//目標死亡
}
else
{
StartCoroutine(DetectBehitEnd(tempbehit, bullte));//執行擊退效果(屬於一種BUFF)
}
//刷新血條
gameRoleAnimator.SetHpBar((float)gameRoleProperty.hpNow / gameRoleProperty.hpmaxNow);
}
///傷害類型 1 : 治療
parammean = bullte.skillData.GetParamByParamMean(1);
if (parammean >= 0)
{
//目標加血
}
///傷害類型 2 : 吸血
parammean = bullte.skillData.GetParamByParamMean(2);
if (parammean >= 0)
{
//目標扣血
//施法者加血
}
}
public virtual IEnumerator DetectBehitEnd(BeHitClass damageValue, AttackBullteS bullte)
{
if (damageValue.repelValue > 0)//如果擊退值大於0,則被擊退
{
//new一個BUFF
Buff bufftemp = new Buff();
//設置參數
bufftemp.Duration = damageValue.repelValue;
bufftemp.Script = "HitBack";
bufftemp.owner = bullte.bullteOwner.gameObject;
//添加BUFF
gameRoleBuffFX.AddBuff(bufftemp);
}
yield return null;
}
3 看看Animator執行顯示數值的方法
public virtual void Playinjury(GameRoleAI.BeHitClass damageValue, AttackBullteS attackbullteS)
{
GameObject tempo = null;//數值顯示prefab
//設置數字顯示座標
Vector3 temppos = transform.position + new Vector3(Random.Range(-0.5f, 0.5f), Random.Range(0f, 0.5f), Random.Range(-0.5f, 0.5f));
if (bodyPart.bodypartBody != null) temppos = bodyPart.bodypartBody.transform.position;
//怪物和角色數值顯示不一樣
if (tag == "Monster")
{
if (damageValue.damageType == 0 && attackbullteS.skillIndex > 0) damageValue.damageType = 6;
if (damageValue.damageValue > 0) tempo = Instantiate(SAOResources.SAOIcon("damageFX" + damageValue.damageType) as GameObject, temppos, Camera.main.transform.rotation) as GameObject;
//設置目標被擊時的閃紅效果
FXRoleBehitShine fxtemp = gameObject.GetComponent<FXRoleBehitShine>();
if (fxtemp != null)
{
fxtemp.Resum(Color.white, 0.5f);
}
else
{
fxtemp = gameObject.AddComponent<FXRoleBehitShine>();
fxtemp.Initialize(Color.white, 0.5f);
}
}
if (tag == "Player")
{
if (damageValue.damageValue > 0) tempo = Instantiate(SAOResources.SAOIcon("damageFX" + (3 + damageValue.damageType)) as GameObject, temppos, Camera.main.transform.rotation) as GameObject;
}
if (tempo != null && damageValue.damageValue > 0)
{
//保證UI顯示在最前面
UIWidget[] uiws = tempo.GetComponentsInChildren<UIWidget>(true);
foreach (UIWidget uiw in uiws) uiw.depth = UIRoot.list[0].transform.childCount;
Destroy(tempo, 3);
tempo.name = transform.name + " damagetype " + damageValue.damageType;
//顯示數值(用的是sprite)
tempo.GetComponent<DamageFX0>().ShowDamage(damageValue.damageValue, transform);
}
}
4 介紹 BUFF的簡單思路,常見的BUFF有,擊退,石化,冰凍,減速,減益(降低防禦,攻擊),中毒/撕裂(持續掉血)。
BUFF就像一個組件,當中了BUFF時,就掛在目標上,腳本上的Update方法,就在buff持續時間中,執行寫代碼,實現不同的效果
BUFF系統需要哪些腳本呢
BUFF:entity類
BUFFBase:總結出BUFF的通用方法,比如begin,effet,end方法
BUFF_XX:繼承BUFFBase,實現具體代碼
BUFFMgr:控制BUFF的增刪查改
public class Buff
{
public int Id;
public string Name;
public int Type;//類型
public float Duration;//持續時間
public string Script;//腳本名稱,作爲索引
public List<float> Param;//參數
public float ReleaseRate;//觸發機率
public int RealLevel;//基礎等級
public int AddRealLevel;//增加等級
public List<float> Ratio;//成長參數
public int Effect;
public BuffDataEntity Data;
public GameObject owner;
}
using UnityEngine;
using System.Collections;
public class BuffBase : MonoBehaviour {
public Buff buffData;
public GameRoleAI ai; //目標AI
public float intervalTime = 0.5f;//BUFF作用間隔
public float ti = 0;
/// <summary>爲true時使用幀數,爲false使用時間 </summary>
public bool realTime = false;
float time0;
void Start () {
}
void Update () {
//健壯性判斷
if (ai.sta == GameRoleStaus.Die)
{
this.enabled = false;
return;
}
if (realTime)//使用幀數
{
time0--;
if (time0 < 0)
{
BuffEnd();
Destroy(this);
return;
}
ti++;
}
else//使用時間
{
if ((Time.time - time0) > buffData.Duration)//超出持續時間
{
BuffEnd();
Destroy(this);
return;
}
ti += Time.deltaTime;
}
if (ti > intervalTime)//到了作用時間
{
ti = 0;
BuffCost();
}
}
//
public virtual void RefreshBuff(Buff buffdata)
{
buffData = buffdata;
time0 = Time.time;
if (realTime) time0 = buffdata.Duration;
BuffBegin();
}
/// <summary> 初始化 </summary>
public virtual void Initialize(Buff buffdata)
{
ai = GetComponent<GameRoleAI>();
buffData = buffdata;
//Destroy(this, buffduration);
time0 = Time.time;
if (realTime) time0 = buffdata.Duration;
BuffBegin();
}
/// <summary> buff開始時調用的函數</summary>
public virtual void BuffBegin()
{
}
/// <summary> buff結束時調用的函數</summary>
public virtual void BuffEnd()
{
}
/// <summary> buff發揮作用時調用的 </summary>
public virtual void BuffCost()
{
}
public virtual void BuffCancel()
{
BuffEnd();
Destroy(this);
}
}
這裏,寫一箇中毒BUFF
public class Buff_Poison : BuffBase
{
public override void BuffBegin()
{
ai.gameRoleIcon.ShowIcon(GameRoleIconType.Poison);//顯示中毒的圖標
intervalTime = 1f;//間隔時間是1秒
}
public override void BuffEnd()
{
ai.gameRoleIcon.HideIcon(GameRoleIconType.Poison);//去掉中毒圖標
}
public override void BuffCost()
{
//製作一個BeHitClass類
GameRoleAI.BeHitClass beHitClass = new GameRoleAI.BeHitClass((int)buffData.Param[0], 0);
AttackBullteS attackBullteS = new AttackBullteS();
if (buffData.owner == null) return;
attackBullteS.bullteOwner = buffData.owner.GetComponent<GameRoleAnimator>();
ai.CostDamage(beHitClass, attackBullteS);
}
}
public class BuffMgr : MonoBehaviour {
public List<BuffBase> saoBufflist = new List<BuffBase>();//存放目標上所有BUFF
public GameRoleAI ai;//目標AI
void Start () {
ai = GetComponent<GameRoleAI>();
}
void Update () {
if (ai.sta != GameRoleStaus.Die)
{
for (int i =0;i<saoBufflist.Count;i++)//實時刷新BUFF集合
{
if (saoBufflist[i] == null)
{
saoBufflist.RemoveAt(i);
i -= 1;
}
}
}
else
{
//StartCoroutine("BuffDisappear");
}
if (ai.sta == GameRoleStaus.Unusual)//有的BUFF例如中毒,不需要改變AI的狀態,而石化,需要改變AI的狀態,
{
if (CanMove()) ai.sta = GameRoleStaus.Wait;
}
}
IEnumerator BuffDisappear()
{
yield return null;
}
/// <summary> 移除所有有利和不利buff</summary>
public void RemoveAll()
{
foreach (SaoBuffBase bufftemp in saoBufflist)
{
bufftemp.BuffCancel();
}
}
public void RemoveAllDebuff()
{
foreach (SaoBuffBase bufftemp in saoBufflist)
{
if (bufftemp.buffData.Type==1) bufftemp.BuffCancel();
}
}
public void RemoveAllBuff()
{
foreach (SaoBuffBase bufftemp in saoBufflist)
{
if (bufftemp.buffData.Type == 0) bufftemp.BuffCancel();
}
}
/// <summary> 看看餘下的buff是否能夠移動 </summary>
public bool CanMove()
{
foreach (BuffBase buffone in saoBufflist)
{
if (buffone.buffData.Script == "Stone") return false;
if (buffone.buffData.Script == "Frozen") return false;
if (buffone.buffData.Script == "Stun") return false;
if (buffone.buffData.Script == "KnockDown") return false;
}
return true;
}
//添加一個buff效果
public void AddBuff(SAOBuff saobuff)
{
if (saobuff == null) return;
foreach (BuffBase tempb in saoBufflist)
{
if (tempb.buffData.Id == saobuff.Id)//如果id一致則判斷爲相同的buff,則刪除之前的buff,加入新的buff
{
tempb.RefreshBuff(saobuff);
return;//如果爲true,則已經存在,不再添加
}
}
Component buffcomponent = gameObject.AddComponent("SaoBuff_" + saobuff.Script);
BuffBase itemtemp = null;
if (buffcomponent != null) itemtemp = buffcomponent as BuffBase;
if (itemtemp != null)
{
itemtemp.Initialize(saobuff);
saoBufflist.Add(itemtemp);
}
}
}
以上,基本就可以對BUFF進行操作
public virtual void CostBuff(AttackBullteS bullte)
{
//健壯性判斷
if (sta == GameRoleStaus.Die) return;
if (bullte.buff.Count < 1) return;
GameRoleProperty owner = bullte.bullteOwner.GetComponent<GameRoleProperty>();
//將攻擊中帶的BUFF,經過幾率判斷,加到AI上
foreach(SAOBuff bufftemp in bullte.buff) gameRoleBuffFX.AddBuff(gameRoleProperty.BuffValue(bufftemp, owner));
}