前言
這篇,主要分析角色接收到技能釋放的信號,執行技能釋放的動作
步驟
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;
}
}
}
總結
技能從釋放到攻擊到目標,流程走完了。