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;
        }
    }

}

总结


技能从释放到攻击到目标,流程走完了。

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