using UnityEngine; using CommonAI.Zone; using System.Collections.Generic; using System; using CommonLang; using CommonAI.Zone.Helper; using CommonAI.ZoneClient; namespace CommonAIClient.Unity.Battle { public partial class ComAIUnit { private HashMap mActionStatus = new HashMap(); private ActionStatus mCurrentActionStatus; private ActionStatus mLockActionStatus; protected ActionStatus CurrentActionStatus { get { return mCurrentActionStatus; } } //注册动作控制对象// protected virtual void InitActionStatus() { // RegistAction(UnitActionStatus.Pause, new ActionStatus("f_idle", true, WrapMode.Loop)); // RegistAction(UnitActionStatus.Idle, new ActionStatus("f_idle", true, WrapMode.Loop)); // RegistAction(UnitActionStatus.Move, new ActionStatus("f_run", true, WrapMode.Loop)); // RegistAction(UnitActionStatus.Skill, new SkillActionStatus("f_skill_01")); // RegistAction(UnitActionStatus.Damage, new ActionStatus("f_hurt")); // RegistAction(UnitActionStatus.Dead, new ActionStatus("f_death", true)); // RegistAction(UnitActionStatus.Stun, new ActionStatus("f_stun")); // RegistAction(UnitActionStatus.Pick, new ActionStatus("f_pick")); // RegistAction(UnitActionStatus.Chaos, new ActionStatus("f_chaos")); // RegistAction(UnitActionStatus.Escape, new ActionStatus("f_escape")); // RegistAction(UnitActionStatus.Spawn, new ActionStatus("f_spawn")); // RegistAction(UnitActionStatus.Rebirth, new ActionStatus("f_rebirth")); //从配置表初始化动作列表// foreach (UnitActionStatus st in Enum.GetValues(typeof(UnitActionStatus))) { var action = ZUnit.Templates.GetDefinedUnitAction(st); if (action != null) { RegistAction(st, new DefinedActionStatus(st.ToString(), action)); } } RegistAction(UnitActionStatus.Skill, new SkillActionStatus("f_skill_01")); } /// /// /// /// /// If return True , break public bool ForeachAction(UnitActionStatus st, Predicate action) { ActionStack stack; if (mActionStatus.TryGetValue(st, out stack)) { return stack.Foreach(action); } return false; } public ActionStatus ReplaceAction(UnitActionStatus st, ActionStatus dst) { ActionStack stack; if (mActionStatus.TryGetValue(st, out stack)) { var ret = stack.Remove(dst.Key); if (ret != null) { stack.Add(dst); ChangeAction(ZUnit.CurrentState); } return ret; } return null; } public ActionStatus RegistAction(UnitActionStatus st, ActionStatus status) { ActionStack stack; if (mActionStatus.TryGetValue(st, out stack) == false) { stack = new ActionStack(); mActionStatus.Add(st, stack); } stack.Add(status); ChangeAction(ZUnit.CurrentState); return status; } public ActionStatus RemoveAction(UnitActionStatus st, string key) { ActionStack stack; if (mActionStatus.TryGetValue(st, out stack)) { var status = stack.Remove(key); if (status != null) { ChangeAction(ZUnit.CurrentState); } return status; } return null; } public ActionStatus GetTopActionStatus(CommonAI.Zone.Helper.UnitActionStatus st) { ActionStack stack; if (mActionStatus.TryGetValue(st, out stack)) { return stack.Top; } return null; } public void SetLockActionStatus(ActionStatus status) { if (status != null) { mLockActionStatus = status; if (status != mCurrentActionStatus) { if (mCurrentActionStatus != null) { mCurrentActionStatus.OnStop(this); } mCurrentActionStatus = status; if (mCurrentActionStatus != null) { mCurrentActionStatus.OnStart(this); } } } else { mLockActionStatus = null; ChangeAction(ZUnit.CurrentState); } } protected virtual void ChangeAction(UnitActionStatus st) { if (mLockActionStatus == null) { var newAction = GetTopActionStatus(st); if (newAction != null) { if (mCurrentActionStatus != null) { mCurrentActionStatus.OnStop(this); } mCurrentActionStatus = newAction; if (mCurrentActionStatus != null) { mCurrentActionStatus.OnStart(this); } } } } protected virtual void UpdateAction(float deltaTime) { if (mCurrentActionStatus != null) { mCurrentActionStatus.OnUpdate(this, deltaTime); } } internal class ActionStack { readonly HashMap Map = new HashMap(); readonly List List = new List(); public ActionStatus Top { get { if (List.Count > 0) return List[0]; return null; } } internal ActionStack() { } public bool Foreach(Predicate action) { using (var list = ListObjectPool.AllocAutoRelease(List)) { foreach (var a in list) { if (action(a)) { return true; } } } return false; } public void Add(ActionStatus status) { Map.Add(status.Key, status); List.Add(status); List.Sort(); } public ActionStatus Remove(string key) { var ret = Map.RemoveByKey(key); if (ret != null) { List.Remove(ret); } return ret; } } public class ActionStatus : IComparable { private readonly string mKey; public string Key { get { return mKey; } } public int Priority { get; set; } public string ActionName { get; set; } public bool CrossFade { get; set; } public WrapMode WrapMode { get; set; } public float Speed { get; set; } public ActionStatus(string key, bool crossFade = false, WrapMode wrapMode = WrapMode.Once, float speed = 1f) { this.mKey = key; this.ActionName = key; this.WrapMode = wrapMode; this.CrossFade = crossFade; this.Speed = speed; } public virtual void OnStart(ComAIUnit owner) { owner.PlayAnim(ActionName, CrossFade, WrapMode, Speed); } public virtual void OnStop(ComAIUnit owner) { } public virtual void OnUpdate(ComAIUnit owner, float deltaTime) { } public virtual int CompareTo(ActionStatus other) { return this.Priority - other.Priority; } } public class DefinedActionStatus : ActionStatus { protected UnitActionDefinitionMap.UnitAction mData; protected Queue mActionQueue = new Queue(); protected UnitActionDefinitionMap.UnitActionKeyFrame mCurrentAction; protected int mCurrentPassTime; public DefinedActionStatus(string key, UnitActionDefinitionMap.UnitAction data) : base(key) { this.mData = data; if (data.ActionQueue.Count > 0) { var a = data.ActionQueue[0]; this.ActionName = a.ActionName; this.WrapMode = a.Cycle ? WrapMode.Loop : WrapMode.Once; this.CrossFade = a.CrossFade; this.Speed = a.Speed; } } public override void OnStart(ComAIUnit owner) { mActionQueue.Clear(); for (int i = 0; i < mData.ActionQueue.Count; i++) { this.mActionQueue.Enqueue(mData.ActionQueue[i]); } NextAction(owner); } public override void OnUpdate(ComAIUnit owner, float deltaTime) { this.mCurrentPassTime += (int)(owner.ZUnit.Parent.CurrentIntervalMS); if (mActionQueue.Count > 0 && mCurrentAction != null) { if (mCurrentPassTime >= mCurrentAction.TimeMS) { NextAction(owner); } } } protected virtual void NextAction(ComAIUnit owner) { if (mActionQueue.Count > 0) { mCurrentAction = mActionQueue.Dequeue(); if (mCurrentAction != null) { this.ActionName = mCurrentAction.ActionName; this.WrapMode = mCurrentAction.Cycle ? WrapMode.Loop : WrapMode.Once; this.CrossFade = mCurrentAction.CrossFade; this.Speed = mCurrentAction.Speed; owner.PlayAnim(this.ActionName, this.CrossFade, this.WrapMode, this.Speed); } } mCurrentPassTime = 0; } } public class SkillActionStatus : ActionStatus { private ZoneUnit.SkillState mSkill; private Queue mActionQueue = new Queue(); private UnitActionData mCurrentAction; private int mCurrentPassTime; public SkillActionStatus(string key) : base(key) { } protected void NextAction(ComAIUnit owner) { if (mActionQueue.Count > 0) { mCurrentAction = mActionQueue.Dequeue(); if (mCurrentAction != null) { ActionName = mCurrentAction.ActionName; WrapMode = mCurrentAction.IsCycAction ? WrapMode.Loop : WrapMode.Once; owner.PlayAnim(ActionName, false, WrapMode, Speed); } } else { mCurrentAction = null; } mCurrentPassTime = 0; } public override void OnUpdate(ComAIUnit owner, float delteTime) { if (mSkill != null && !mSkill.Data.IsSingleAction) { this.mCurrentPassTime += (int)(owner.ZUnit.Parent.CurrentIntervalMS); if (mCurrentAction != null) { if (mCurrentPassTime >= mCurrentAction.TotalTimeMS) { // 下段动作 // NextAction(owner); } } } } public virtual void ZUnit_OnLaunchSkill(ComAIUnit unit, ZoneUnit.SkillState skill, CommonAI.Zone.UnitLaunchSkillEvent evt) { mSkill = skill; Speed = mSkill.ActionSpeed; mActionQueue.Clear(); if (skill.Data.IsSingleAction) { this.mActionQueue.Enqueue(skill.Data.ActionQueue[evt.action_index]); } else { for (int i = evt.action_index; i < skill.Data.ActionQueue.Count; i++) { this.mActionQueue.Enqueue(skill.Data.ActionQueue[i]); } } NextAction(unit); } public virtual void ZUnit_OnSkillActionChanged(ComAIUnit owner, byte index) { var skill = mSkill.Data.ActionQueue[index]; if (skill != null) { while (mActionQueue.Count > 0) { var sk = mActionQueue.Peek(); if (sk == skill) { NextAction(owner); break; } else { mActionQueue.Dequeue(); } } } } } } }