RPG2.0戰鬥框架學習4之技能釋放過程

前言


這篇,主要分析角色接收到技能釋放的信號,執行技能釋放的動作


步驟


1 角色的行爲由狀態機來劃分,不同狀態下,會執行不同操作,攻擊敵人這一行爲,是由等待狀態-》發現目標狀態-》攻擊狀態,

當達到目標附近後,切換成爲攻擊狀態,接到攻擊指令,執行攻擊操作


    public virtual void ActionAttack()
    {
		//進行健壯性判斷
        if (!this.enabled) return;
        //進行邏輯判斷,比如,停止走路      
        if (上次攻擊沒有結束) return;
		//目標不存在,return
        if (!TargetAlive(targetObj)) { TargetObjLost(); return; }
		
        Vector3 targetDir = targetObj.transform.position - transform.position;
        targetDir.y = 0;
        transform.forward = Vector3.MoveTowards(transform.forward, targetDir.normalized, 0.5f);
        //檢測是否在技能施法範圍中, 
        if (targetDir.magnitude < (gameRoleProperty.skillList[defaultSkillIndex].skillRange + gameRoleProperty.stepDistance + targetObj.GetComponent<GameRoleProperty>().stepDistance))
        {
			//判斷 技能是否冷卻完畢&&技能動作是否執行完畢&&上次攻擊是否結束
            if (roleProperty.skillList[skillIndex].skillTimeCount < 0.01f &&roleProperty.skillList[skillIndex].skillColdTimeCount < 0.01f && roleAnimator.attackEnd)
            {
				//進行技能執行時間的協程,在技能動作進行過程中,不會執行攻擊操作
                StartCoroutine(RestAffterAtaction(gameRoleProperty.skillList[skillIndex].skillColdTime));
				//
                roleAnimator.PlayAttack(roleProperty.skillList[skillIndex], skillIndex, targetObj);
				//處理其他邏輯處理 
                return;
            }
        }
        else //如果技能都不能釋放,則說明不在攻擊範圍內,變成鎖定目標狀態
        {		
            sta = GameRoleStaus.Target;
        }
    }

2 Animator中的PlayAttack方法,這裏在說明下,技能的三個階段,A階段:施法者釋放時的特效,B階段:特效在施法者和目標者之間,C階段 特效子啊目標者(攻擊到了)


    public virtual void PlayAttack(SkillProperty skillproperty, int skillIndex, GameObject targetobj)
    { 
	//攻擊沒有結束,返回
        if (!attackEnd) return; 
		//目標的賦值
        targetObj = targetobj;	
        StartCoroutine(AttackBullteNormal(skillproperty, skillIndex, skillTargets));
    }
	/// <summary> 攻擊特效 </summary> 
    IEnumerator AttackBullteNormal(SkillProperty skillproperty, int skillIndex, List<GameObject> targetObjbullet)
    {
        attackEnd = false;
        playSkillIndex = skillIndex;//記錄下技能的索引,用來判斷當前技能是普攻還是技能
		//面向目標
        Face2Target();
		//這裏怪物的攻擊和角色的攻擊表現形式有差別,這裏作區分
        if (tag == "Monster")
        {
            FXRoleBehitShine fxtemp = gameObject.GetComponent<FXRoleBehitShine>();
            if (fxtemp != null)
            {
                fxtemp.Resum(Color.red, 0.5f);
            }
            else
            {
                fxtemp = gameObject.AddComponent<FXRoleBehitShine>();
                fxtemp.Initialize(Color.red, 0.5f);
            }
        }
        //根據技能index不同,播放不同的攻擊動畫
        if (skillproperty.attackActionIndex <6 )//如果是普攻
        {
            ani.CrossFade("attack" + skillproperty.attackActionIndex, 0.01f, 0, 0);
        }
        AnimatorStateInfo aniInfo = ani.GetCurrentAnimatorStateInfo(0);
        while (!aniInfo.IsName("attack" + skillproperty.attackActionIndex))
        {
            aniInfo = ani.GetCurrentAnimatorStateInfo(0); 
            yield return null;
        }
		//創建技能的開始的特效
        CreateSkillEffect(skillproperty, skillIndex, targetObjbullet);
		//開始技能冷卻邏輯處理
        skillproperty.BeginColdDown(aniInfo.normalizedTime);
		//多段攻擊處理
        int damageIndex = 0;
        while (aniInfo.normalizedTime < 1)
        {
			//當攻擊階段index超出
            if (damageIndex >= skillproperty.damageList.Count) {
                aniInfo = ani.GetCurrentAnimatorStateInfo(0);
                if (!aniInfo.IsName("attack" + skillproperty.attackActionIndex)) break;
                yield return null; 
                continue; 
            }
            aniInfo = ani.GetCurrentAnimatorStateInfo(0);
			//動作播放到一個時刻,處理攻擊
            if (skillproperty.damageList[damageIndex].damageTime <= aniInfo.normalizedTime)
            {
                //生成子彈,發射!
                CreateDamageBullte(skillproperty, skillIndex, damageIndex, targetObjbullet);
                damageIndex++;

            }
            yield return null;
        }
		//攻擊結束
        attackEnd = true;
        ai.AttackEnd();
        ani.Play("idle"); 
    }
	//生成子彈
	private void CreateDamageBullte(SkillProperty skillproperty, int skillIndex, int damageIndex, List<GameObject> targetObjList)
    {
		//需要技能範圍中的攻擊目標
        skillTargets = GetSkillTarget(skillproperty, skillIndex, targetObj);
        if (skillproperty.damageList[damageIndex].damageBullet.objInstance == null) return;
		//生成特效B階段(在角色和敵人中間飛行的特效,如果是近距離攻擊,就沒有嘍)
        GameObject tempo = Instantiate(skillproperty.damageList[damageIndex].damageBullet.objInstance) as GameObject;
        tempo.SetActive(true);  
        //使子彈附着到施法目標
        tempo.SendMessage("AttachBodyPart", gameObject, SendMessageOptions.DontRequireReceiver);
        FXAttachRoleBodyPart[] fs = tempo.GetComponentsInChildren<FXAttachRoleBodyPart>();
        foreach (FXAttachRoleBodyPart f1 in fs)
        {
            if (f1.attachToTarget)//如果是加到敵人的位置
            {
				//有一個問題,如果是禁錮技能,技能B階段直接綁在目標(們)上,從而直接判斷攻擊到了,做C階段的處理
            }
            else f1.AttachBodyPart(gameObject);///加到玩家的某部位
        }
		//控制特效prefab的腳本 從B階段到C階段 邏輯處理就是靠這個腳本,
		//想要不同的處理,可以做成基類,寫個初始化的方法,通過繼承基類,在update中作出不同的處理,可以達到不同的效果(自己的想法)
        if (tempo.GetComponent<AttackBullteS>() == null) tempo.AddComponent<AttackBullteS>();
        tempo.GetComponent<AttackBullteS>().initialize(targetObjList, this, skillIndex, damageIndex, skillproperty);
        Destroy(tempo, 15f);
    }

3 子彈(廣義)生成好了,下面就是讓它攻擊到目標,來看看控制子彈的腳本 


using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class AttackBullteS : MonoBehaviour { 
	//
    public float speed = 0.1f;
    public bool multiTarget = false;
    public GameObject ecFXObj;
    public List<GameObject> targetObj;
    public GameRoleAnimator bullteOwner;  
    private GameRoleAnimator targetAnimator;
    Transform targetPart;
    public int skillIndex, damageIndex;
    public SkillProperty skillData;
    public List<SAOBuff> buff = null;//攻擊附帶buff
    public int bullteNature = 0;
	
	void Start () {

	}
    public void initialize(List<GameObject> targetobj, GameRoleAnimator bullteowner, int skillindex, int damageindex,SkillProperty skilldata )
    {
        targetObj = targetobj;
        bullteOwner = bullteowner;
        skillIndex = skillindex;
        damageIndex = damageindex;
        skillData = skilldata;
        if (skillData.damageList[damageindex].ecFX != null) ecFXObj = skillData.damageList[damageindex].ecFX.objInstance;
        buff = skillData.damageList[damageindex].buff;
        if (targetobj.Count == 0) { targetPart = null; transform.forward = bullteowner.transform.forward; return; }
        if (targetobj[0] == null) { targetPart = null; transform.forward = bullteowner.transform.forward; return; }
        targetAnimator = targetobj[0].GetComponent<GameRoleAnimator>();
        if (targetAnimator != null)
        {
            if (targetAnimator.bodyPart != null)
            {
                if (targetAnimator.bodyPart.bodypartBody != null) targetPart = targetAnimator.bodyPart.bodypartBody.transform;
            }
            
        }
		//C階段特效出現的部位在身體上
        if (targetPart == null)
        {
            RoleBodyPart body1 = targetObj[0].GetComponent<RoleBodyPart>();
            if (body1 != null) targetPart = body1.bodypartBody.transform;
            else targetPart = targetObj[0].transform;
        }
    }
    void Update()
    {
        if (targetPart == null) {
		
            transform.position += transform.forward * speed * Time.deltaTime * 60;
            if ((transform.position - bullteOwner.transform.position).magnitude > skillData.skillRange)
            {
                BullteExplode(true);
                if (ecFXObj != null)
                {
                    GameObject tempo = Instantiate(ecFXObj, transform.position, transform.rotation) as GameObject;
                    Destroy(tempo, 2);
                }
                else
                {
                    GameObject tempo = Instantiate(SAOResources.SAOFXObj("FX_EC_ci" + Random.Range(0, 3)), transform.position, transform.rotation) as GameObject;
                    Destroy(tempo, 2);
                }
            }
            return; 
        }
		//讓子彈朝物體移動
        Vector3 tempdir = targetPart.position - transform.position  ;
        transform.forward = tempdir.normalized;
		//到達攻擊位置
        if (tempdir.magnitude < speed * Time.deltaTime * 60) BullteExplode(true);
        transform.position += tempdir.normalized * speed * Time.deltaTime * 60; 
    }
	
    public void BullteExplode(bool isend)
    {
		//創建C階段特效
        for (int i = 0; i < targetObj.Count; i++)
        {	
			//通知被攻擊的目標 執行BeHit方法
            if (targetObj[i] != null) targetObj[i].SendMessage("BeHit", this, SendMessageOptions.DontRequireReceiver);
            if (targetPart != null) transform.position = targetPart.position;
            if (ecFXObj != null)
            {
				//生成特效
                GameObject tempo = Instantiate(ecFXObj,transform.position,transform.rotation) as GameObject;
                Destroy(tempo, 2); 
                tempo.transform.rotation = Quaternion.identity;
                FXAttachRoleBodyPart[] fs = tempo.GetComponentsInChildren<FXAttachRoleBodyPart>(true);
                foreach (FXAttachRoleBodyPart f1 in fs) f1.AttachBodyPart(targetObj[i].gameObject);
            }
            else
            {
                GameObject tempo = Instantiate( SAOResources.SAOFXObj("FX_EC_ci" + Random.Range(0, 3)),transform.position,transform.rotation)as GameObject;// Instantiate(ecFXObj, transform.position, transform.rotation) as GameObject;
                Destroy(tempo, 2);
            }
        } 
        if (particleSystem != null) particleSystem.Play();
		//銷燬子彈
        if (isend)
        {
            if (renderer != null) renderer.enabled = false;
            Destroy(gameObject, 0.1f);
            this.enabled = false;
        }
    }

}

總結


技能從釋放到攻擊到目標,流程走完了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章