using Thousandto.Code.Logic; using Thousandto.Code.Logic.WarningField; using Thousandto.Core.Asset; using Thousandto.Core.Base; using Thousandto.SkillEditor; using Thousandto.SkillEditor.DIY; using Thousandto.SkillEditor.Support; using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; using Thousandto.Cfg.Data; using Thousandto.Launcher.ExternalLibs; namespace Thousandto.SkillEditor.DIY { public enum EditorEntityState { Idle, Move, Jump, HitStiff, //受击僵直 HitBack, //击退 HitFly, //击飞 Lie, //击飞后倒地 HitGrab, //抓取 } public class EditorEntity : EditorBaseObject { #region//私有变量 private AnimationPlayer _animPlayer = null; private EditorEntityState _curState = EditorEntityState.Idle; private Vector3 _moveDir = Vector3.forward; private ForwardRoter _roter = null; private float _scale = 1f; private float _moveSpeed = 6f; private Vector3 _jumpStart = Vector3.zero; private Vector3 _jumpCenter = Vector3.zero; private Vector3 _jumpTarget = Vector3.zero; private float _jumpTimer = 0f; private const float JumpTime = 1f; private float _hitStateTimer = 0f; private HitEffectInfo _hitEffectInfo = null; private Vector3 _hitBackOriPos = Vector3.zero; private Vector3 _hitBackTargetPos = Vector3.zero; private float _getUpAnimTime = 0f; private float _lieTime = 0f; private Vector3[] _hitFlyCurve = null; private Vector3 _grabOriPos = Vector3.zero; private Vector3 _grabTargetPos = Vector3.zero; private Material _mater = null; private float _blinkTimer = 0f; private float _blinkMaxTime = 0f; private float _blinkPower = 0f; private Color _blinkColor = Color.white; private AnimationCurve _blinkCurve = null; private AnimationPlayer _animPlayerRun = null; private GameObject _runGo = null; private bool _hideWeapon = false; private List _weaponList = new List(); #endregion #region//属性 public EditorEntityState CurState { get { return _curState; } } public bool DisableMove { get; set; } public bool DisableChangeDir { get; set; } public EditorSkillManager SkillManager { get; private set; } public bool IsPauseAnim { get; private set; } public bool HideWeapon { get { return _hideWeapon; } set { if (_hideWeapon != value) { _hideWeapon = value; for (int i = 0; i < _weaponList.Count; ++i) { _weaponList[i].SetActive(!_hideWeapon); } } } } public ForwardRoter Roter { get { return _roter; } } #endregion #region//构造函数 public EditorEntity(GameObject rootGo, EditorObjType objType, float scale, float moveSpeed) : base(rootGo, objType) { var anim = UnityUtils.RequireComponent(rootGo); anim.AddClips(AnimInfo.GetClips(anim.AnimAssetPathDic.Values)); _animPlayer = new AnimationPlayer(anim); _roter = new ForwardRoter(); _roter.CurForward = RootGo.transform.forward; _roter.CurSpeed = 0.7f; SkillManager = new EditorSkillManager(this); var render = RootTrans.GetComponentInChildren(); _mater = render.material; _runGo = (GameObject)GameObject.Instantiate(rootGo); anim = UnityUtils.RequireComponent(_runGo); anim.AddClips(AnimInfo.GetClips(anim.AnimAssetPathDic.Values)); _animPlayerRun = new AnimationPlayer(anim); _runGo.SetActive(false); _runGo.transform.parent = _runGo.transform; _scale = scale; _moveSpeed = moveSpeed; if(_moveSpeed < 1f) { _moveSpeed = 1f; } StopSate(); } #endregion #region// public void StopSate() { if (_curState == EditorEntityState.Jump) return; if (_curState != EditorEntityState.Idle || !_animPlayer.IsPlaying) { if (IsPauseAnim) { _animPlayer.Stop(); IsPauseAnim = false; _runGo.SetActive(false); } if(_animPlayer.UseHalfBody) { if (_animPlayer.UPPart.IsPlaying && FPlayerAnimRelation.GetLogicType(_animPlayer.UPPart.CurState.ParentAnimName) == FAnimLogicType.Skill && _animPlayer.LowerPart.IsPlaying && FPlayerAnimRelation.GetLogicType(_animPlayer.LowerPart.CurState.ParentAnimName) == FAnimLogicType.Skill) { //上下半身都是播放技能动作,不替换动作 } else if (_animPlayer.UPPart.IsPlaying && FPlayerAnimRelation.GetLogicType(_animPlayer.UPPart.CurState.ParentAnimName) == FAnimLogicType.Skill) { //如果只有上半身在播放技能动作 if (_animPlayer.UPPart.CurState.ClipLength * (1f - _animPlayer.UPPart.CurState.CurNormalizeTime) < 0.2f) { //如果上半身的时间已经不够融合了直接播放idle _animPlayer.Play(ObjType == EditorObjType.Player ? AnimClipNameDefine.FightIdle : AnimClipNameDefine.NormalIdle, AnimationPartType.AllBody, WrapMode.Loop); } else { //如果上半身在放技能动作,播放整体技能动作 string animName = FPlayerAnimRelation.SkillMoveToIdle(_animPlayer.UPPart.CurState.ParentAnimName); _animPlayer.Play(animName, AnimationPartType.AllBody, _animPlayer.UPPart.CurState.WrapMode, true, 0.2f, _animPlayer.UPPart.CurState.Speed, _animPlayer.UPPart.CurState.CurNormalizeTime); } } else if (!SkillManager.IsUsing) { _animPlayer.Play(ObjType == EditorObjType.Player ? AnimClipNameDefine.FightIdle : AnimClipNameDefine.NormalIdle, AnimationPartType.AllBody, WrapMode.Loop); } } else { if (!SkillManager.IsUsing) { _animPlayer.Play(AnimClipNameDefine.NormalIdle, AnimationPartType.AllBody, WrapMode.Loop); } } } _curState = EditorEntityState.Idle; } float VectorAngle(Vector2 from, Vector2 to) { float angle; Vector3 cross = Vector3.Cross(from, to); angle = Vector2.Angle(from, to); return cross.z > 0 ? -angle : angle; } public void MoveTo(Vector3 dir, EditorEntity target) { if (_curState == EditorEntityState.Jump) return; if (IsPauseAnim) { _animPlayer.Stop(); IsPauseAnim = false; _runGo.SetActive(false); } _moveDir = dir; _moveDir.y = 0f; _moveDir = _moveDir.normalized; if (DisableMove) { if (!DisableChangeDir) { _roter.DestForward = _moveDir; } return; } var modelDir = _moveDir; var animName = AnimClipNameDefine.FightRunFront; if (target != null && Vector3.SqrMagnitude(target.RootTrans.position - RootTrans.position) < 100f) { var tarDir = target.RootTrans.position - RootTrans.position; tarDir.y = 0f; tarDir = tarDir.normalized; var angle = VectorAngle(new Vector2(_moveDir.x, _moveDir.z), new Vector2(tarDir.x, tarDir.z)); //4方向 if ((angle >= 0 && angle <= 45f) || (angle <= 0 && angle >= -45f)) { modelDir = _moveDir; animName = AnimClipNameDefine.FightRunFront; } else if (angle >= 135f || angle <= -135) { modelDir = -_moveDir; animName = AnimClipNameDefine.FightRunBack; } else if (angle >= 0f) { modelDir = tarDir; animName = AnimClipNameDefine.FightRunLeft; } else if (angle < 0f) { modelDir = tarDir; animName = AnimClipNameDefine.FightRunRight; } } if (_curState != EditorEntityState.Move || !_animPlayer.IsPlaying || (_animPlayer.UseHalfBody && !_animPlayer.IsLowerPlayAnim(animName))) { if(_animPlayer.UseHalfBody) { float normalTime = 0f; if (_animPlayer.LowerPart.IsPlaying && FPlayerAnimRelation.GetLogicType(_animPlayer.LowerPart.CurState.ParentAnimName) == FAnimLogicType.Move) { normalTime = _animPlayer.LowerPart.CurState.CurNormalizeTime; } if (_animPlayer.UPPart.IsPlaying && FPlayerAnimRelation.GetLogicType(_animPlayer.UPPart.CurState.ParentAnimName) == FAnimLogicType.Skill && _animPlayer.LowerPart.IsPlaying && FPlayerAnimRelation.GetLogicType(_animPlayer.LowerPart.CurState.ParentAnimName) == FAnimLogicType.Skill) { //如果上下半身都在播放技能,尝试切换到移动技能动作 string moveSkill = FPlayerAnimRelation.SkillIdleToMove(_animPlayer.UPPart.CurState.ParentAnimName); if (_animPlayer.Play(moveSkill, AnimationPartType.UpBody, _animPlayer.UPPart.CurState.WrapMode, true, 0.2f, _animPlayer.UPPart.CurState.Speed, _animPlayer.UPPart.CurState.CurNormalizeTime)) { //如果可以切换到移动技能动作,下半身播放移动动作 if (!_animPlayer.LowerPart.IsPlaying || _animPlayer.LowerPart.CurState.ParentAnimName != animName) { _animPlayer.Play(animName, AnimationPartType.LowerBody, WrapMode.Loop, true, 0.2f, 1f, normalTime); } } else if (!SkillManager.IsUsing) { //如果正在播放技能收招动作,直接切换 _animPlayer.Play(animName, AnimationPartType.AllBody, WrapMode.Loop, true, 0.2f, 1f, normalTime); } } else if (_animPlayer.UPPart.IsPlaying && FPlayerAnimRelation.GetLogicType(_animPlayer.UPPart.CurState.ParentAnimName) == FAnimLogicType.Skill) { //上半身在播放技能,下半身播放跑步动作 if (!_animPlayer.LowerPart.IsPlaying || _animPlayer.LowerPart.CurState.ParentAnimName != animName) { _animPlayer.Play(animName, AnimationPartType.LowerBody, WrapMode.Loop, true, 0.2f, 1f, normalTime); } } else { if (!SkillManager.IsUsing) { _animPlayer.Play(animName, AnimationPartType.AllBody, WrapMode.Loop, true, 0.2f, 1f, normalTime); } } } else { if (!SkillManager.IsUsing) { _animPlayer.Play(AnimClipNameDefine.NormalRun, AnimationPartType.AllBody, WrapMode.Loop, true, 0.2f, 1f, 0f); } } } _roter.DestForward = modelDir; _curState = EditorEntityState.Move; } public void JumpTo(Vector3 dir) { if (_curState == EditorEntityState.Jump) return; if (DisableMove) return; if (IsPauseAnim) { _animPlayer.Stop(); IsPauseAnim = false; _runGo.SetActive(false); } dir.y = 0f; dir = dir.normalized; _jumpStart = RootTrans.position; _jumpTimer = 0f; if (dir == Vector3.zero) { //原地跳跃 _jumpTarget = RootTrans.position; _jumpCenter = RootTrans.position + Vector3.up * 5f; } else { //方向跳跃 _jumpTarget = dir * 6f + _jumpStart; _jumpCenter = Vector3.Lerp(_jumpTarget, _jumpStart, 0.5f); _jumpCenter += Vector3.up * 5f; } _animPlayer.Play("jump", AnimationPartType.AllBody, WrapMode.Once, true, 0.2f, 0.5f / JumpTime); _roter.DestForward = _moveDir; _curState = EditorEntityState.Jump; } public void DoHitEffect(EditorBaseObject user, Vector3 mainDir, HitEffectInfo hitInfo) { Vector3 dir = Vector3.zero; if (hitInfo.HitDirType == SkillHitDirType.RealDir) { dir = RootTrans.position - user.RootTrans.position; } else { dir = mainDir; } dir.y = 0; dir = dir.normalized; DoHitEffect(user.RootTrans.position, dir, hitInfo); } public void DoHitEffect(EditorLockFlyVfx flyVfx, HitEffectInfo hitInfo) { var dir = RootTrans.position - flyVfx.RootTrans.position; dir.y = 0; dir = dir.normalized; DoHitEffect(flyVfx.RootTrans.position, dir, hitInfo); } public SkillHitType HitTypeCheck(HitEffectInfo hitInfo) { switch (hitInfo.HitType) { case SkillHitType.HitStiff: case SkillHitType.HitBack: if (CurState == EditorEntityState.HitFly) { //追击击飞 return SkillHitType.HitFly; } break; } return hitInfo.HitType; } public void DoHitEffect(Vector3 userPos, Vector3 dir, HitEffectInfo hitInfo) { if (IsPauseAnim) { _animPlayer.Stop(); IsPauseAnim = false; _runGo.SetActive(false); } _hitEffectInfo = hitInfo; //播放受击特效 if(hitInfo.HitVfx > 0) { var hitTrans = SlotUtils.GetSlotTransform(RootTrans, hitInfo.HitSlot); var resPath = AssetUtils.GetModelAssetPath(ModelTypeCode.SkillVFX, hitInfo.HitVfx); EditorVFXPlayer.Instance.PlayVFX(resPath, hitTrans); } //播放闪烁效果 Blink(hitInfo.BlinkTime, hitInfo.BlinkPower, hitInfo.BlinkColor, hitInfo.BlinkCurve); //播放受击效果 var hitType = HitTypeCheck(hitInfo); switch (hitType) { case SkillHitType.None: { _roter.DestForward = -dir; PlayAnim(hitInfo.HitAnim, WrapMode.Once, 1f, 0f); } break; case SkillHitType.HitStiff: { _roter.DestForward = -dir; PlayAnim(hitInfo.HitAnim, WrapMode.Once, 1f, 0f); _curState = EditorEntityState.HitStiff; _hitStateTimer = 0f; } break; case SkillHitType.HitBack: { _roter.DestForward = -dir; PlayAnim(hitInfo.HitAnim, WrapMode.Once, 1f, 0f); _curState = EditorEntityState.HitBack; _hitStateTimer = 0f; _hitBackOriPos = RootTrans.position; _hitBackTargetPos = RootTrans.position + hitInfo.BackDis * dir; _hitBackTargetPos.y = 0f; } break; case SkillHitType.HitFly: { _roter.DestForward = -dir; var flyPoint = new Vector3[3]; var targetPos = RootTrans.position + dir * hitInfo.FlyDis; targetPos.y = 0f; PlayAnim(AnimClipNameDefine.HitFly, WrapMode.Once, 0.45f / _hitEffectInfo.FlyTime, 0f); List path = new List(hitInfo.HitFlyHeightCurve.keys.Length); float curveTime = hitInfo.HitFlyHeightCurve.keys[hitInfo.HitFlyHeightCurve.keys.Length - 1].time; for (int i = 0; i < hitInfo.HitFlyHeightCurve.keys.Length; ++i) { var key = hitInfo.HitFlyHeightCurve.keys[i]; var lerpValue = key.time / curveTime; var pos = Vector3.Lerp(RootTrans.position, targetPos, lerpValue); pos.y += key.value; path.Add(pos); } _hitFlyCurve = iTween.PathControlPointGenerator(path.ToArray()); _hitStateTimer = 0f; _lieTime = hitInfo.LieTime; _getUpAnimTime = _animPlayer.GetClipLength(AnimClipNameDefine.GetUp); _curState = EditorEntityState.HitFly; } break; case SkillHitType.HitGrab: { _hitStateTimer = 0f; _grabOriPos = RootTrans.position; var vtargetPos = userPos + dir * hitInfo.GrabPos; vtargetPos.y = 0f; var grabDir = _grabOriPos - vtargetPos; grabDir.y = 0f; grabDir = grabDir.normalized; if (Vector3.Distance(_grabOriPos, vtargetPos) > hitInfo.GrabDis) { _grabTargetPos = vtargetPos + grabDir * hitInfo.GrabPos; } else { _grabTargetPos = vtargetPos; } _animPlayer.Play(_hitEffectInfo.HitAnim, AnimationPartType.AllBody, WrapMode.Once); _curState = EditorEntityState.HitGrab; } break; } } public void Blink(float time, float power, Color color, AnimationCurve curve) { _blinkTimer = 0f; _blinkMaxTime = time; _blinkPower = power; _blinkColor = color; _blinkCurve = curve; _mater.shader = Shader.Find("Ares/EntityState/BeHit"); _mater.SetColor("_RimColor", _blinkColor); _mater.SetFloat("_RimPower", (1f - _blinkCurve.Evaluate(0f)) * _blinkPower); } public void PlayAnim(string animName, WrapMode wrapMode, float speed, float normalizedTime) { if (IsPauseAnim) { _animPlayer.Stop(); IsPauseAnim = false; _runGo.SetActive(false); } if (CurState != EditorEntityState.Idle) { var curLogicType = FPlayerAnimRelation.GetLogicType(animName); if (curLogicType == FAnimLogicType.Skill) { var runSkillName = FPlayerAnimRelation.SkillIdleToMove(animName); if (_animPlayer.Play(runSkillName, AnimationPartType.UpBody, wrapMode, true, 0.2f, speed, normalizedTime)) { return; } } } _animPlayer.Play(animName, AnimationPartType.AllBody, wrapMode, true, 0.2f, speed, normalizedTime); } public void StopAnim() { _animPlayer.Stop(); } public void Update(float dt) { _roter.Update(dt); RootTrans.forward = _roter.CurForward; _animPlayer.Update(dt); SkillManager.Update(dt); if (_blinkMaxTime > 0f && _blinkTimer < _blinkMaxTime) { _blinkTimer += dt; if (_blinkTimer >= _blinkMaxTime) { //结束闪烁 _blinkMaxTime = -1f; _mater.shader = Shader.Find("Ares/Entity/Monster"); _mater.SetColor("_Color", Color.white); _mater.SetFloat("_ColorMultiplier", 1f); } else { _mater.SetFloat("_RimPower", (1f - _blinkCurve.Evaluate(_blinkTimer / _blinkMaxTime)) * _blinkPower); } } switch (_curState) { case EditorEntityState.Idle: { if (!_animPlayer.IsPlaying && !SkillManager.IsUsing) { _animPlayer.Play(ObjType == EditorObjType.Player ? AnimClipNameDefine.FightIdle : AnimClipNameDefine.NormalIdle, AnimationPartType.AllBody, WrapMode.Loop); } } break; case EditorEntityState.Move: { if (!_animPlayer.IsPlaying) { //_animPlayer.Play(AnimClipNameDefine.FightRunFront, true, WrapMode.Loop); } RootTrans.position += _moveDir * dt * _moveSpeed; if (DisableMove) { StopSate(); } } break; case EditorEntityState.Jump: { _jumpTimer += dt; if (_jumpTimer <= JumpTime) { float lerpValue = _jumpTimer / JumpTime; RootTrans.position = (1 - lerpValue) * (1 - lerpValue) * _jumpStart + 2 * lerpValue * (1 - lerpValue) * _jumpCenter + lerpValue * lerpValue * _jumpTarget; } else { RootTrans.position = _jumpTarget; _curState = EditorEntityState.Idle; StopSate(); } } break; case EditorEntityState.HitStiff: { _hitStateTimer += dt; if (_hitStateTimer >= _hitEffectInfo.HitEffectTime) { StopSate(); } } break; case EditorEntityState.HitBack: { _hitStateTimer += dt; if (_hitStateTimer >= _hitEffectInfo.HitEffectTime) { StopSate(); RootTrans.position = _hitBackTargetPos; } else { var lerpValue = _hitEffectInfo.HitTimeCurve.Evaluate(_hitStateTimer / _hitEffectInfo.HitEffectTime); RootTrans.position = Vector3.Lerp(_hitBackOriPos, _hitBackTargetPos, lerpValue); } } break; case EditorEntityState.HitFly: { _hitStateTimer += dt; if (_hitStateTimer >= _hitEffectInfo.FlyTime) { _animPlayer.Play(AnimClipNameDefine.Lie, AnimationPartType.AllBody, WrapMode.Loop); RootTrans.position = iTween.Interp(_hitFlyCurve, 1f); _curState = EditorEntityState.Lie; _hitStateTimer = 0f; } else { var lerpValue = _hitStateTimer / _hitEffectInfo.FlyTime * _hitEffectInfo.HitTimeCurve.keys[_hitEffectInfo.HitTimeCurve.keys.Length - 1].time; lerpValue = Mathf.Clamp01(_hitEffectInfo.HitTimeCurve.Evaluate(lerpValue)); RootTrans.position = iTween.Interp(_hitFlyCurve, lerpValue); } } break; case EditorEntityState.Lie: { if (_lieTime > _getUpAnimTime) { float value = _lieTime - _getUpAnimTime; if (_hitStateTimer <= value) { _hitStateTimer += dt; if (_hitStateTimer > value) { _animPlayer.Play(AnimClipNameDefine.GetUp, AnimationPartType.AllBody, WrapMode.Once); } } else { _hitStateTimer += dt; if (_hitStateTimer > _lieTime) { StopSate(); } } } else { _hitStateTimer += dt; if (_hitStateTimer > _lieTime) { StopSate(); } } } break; case EditorEntityState.HitGrab: { _hitStateTimer += dt; if (_hitStateTimer <= _hitEffectInfo.HitEffectTime) { var lerpValue = _hitStateTimer / _hitEffectInfo.HitEffectTime; RootTrans.position = Vector3.Lerp(_grabOriPos, _grabTargetPos, _hitEffectInfo.HitTimeCurve.Evaluate(lerpValue)); } else { RootTrans.position = _grabTargetPos; StopSate(); } } break; } } public void UseSkill(SkillVisualInfo skill) { SkillManager.UseSkill(skill); } public void StopAllSkill() { SkillManager.StopAllSkill(); } public void DoPauseAnim(SkillVisualInfo skill, int frame, bool showPauseContrast) { if (SkillManager.IsUsing) return; if (CurState != EditorEntityState.Idle) return; String animName = String.Empty; int playFrame = 0; float startNor = 0f; bool isLoop = false; for (int i = skill.DataList.Count - 1; i >= 0; --i) { var eventInfo = skill.DataList[i]; if (eventInfo.IsEnable && eventInfo.EventType == SkillEventDefine.PlayAnimation && eventInfo.EventFrame <= frame) { var animEvent = eventInfo as PlayAnimEventInfo; animName = animEvent.AnimName; playFrame = frame - eventInfo.EventFrame; startNor = animEvent.NormalizedTime; isLoop = animEvent.Loop != 0; break; } } var animTime = _animPlayer.GetClipLength(animName); if (animTime > 0f) { var normalizedTime = (playFrame * EditorSkill.OneFrameTime) / animTime; _animPlayer.Play(animName, AnimationPartType.AllBody, WrapMode.Once, false, 0f, 0f, normalizedTime); IsPauseAnim = true; if (showPauseContrast) { _runGo.SetActive(true); _runGo.transform.position = RootTrans.position; _runGo.transform.forward = RootTrans.forward; var runAnimName = FPlayerAnimRelation.SkillIdleToMove(animName); if (!string.IsNullOrEmpty(runAnimName)) { _animPlayerRun.Play(runAnimName, AnimationPartType.UpBody, WrapMode.Once, false, 0f, 0f, normalizedTime); _animPlayerRun.Play(AnimClipNameDefine.FightRunFront, AnimationPartType.LowerBody, WrapMode.Once, false, 0f, 0f, normalizedTime); } } else { _runGo.SetActive(false); } } } public bool LoadWeapon(int modelID) { var resPath = AssetUtils.GetModelAssetPath(ModelTypeCode.GodWeapon, modelID); GameObject prefab = ResourcesEx.Load(resPath, typeof(GameObject)) as GameObject; if (prefab == null) return false; for (int i = 0; i < _weaponList.Count; ++i) { GameObject.DestroyImmediate(_weaponList[i], true); } _weaponList.Clear(); GameObject model = (GameObject)GameObject.Instantiate(prefab); var leftModel = model.transform.Find("left"); var rightModel = model.transform.Find("right"); if (leftModel != null && rightModel != null) { //双手武器 _weaponList.Add(leftModel.gameObject); _weaponList.Add(rightModel.gameObject); _weaponList.Add(model); var slotL = SlotUtils.GetSlotTransform(RootTrans, Slot.LeftWeapon); leftModel.parent = slotL; UnityUtils.Reset(leftModel); var slotR = SlotUtils.GetSlotTransform(RootTrans, Slot.RightWeapon); rightModel.parent = slotR; UnityUtils.Reset(rightModel); model.transform.parent = RootTrans; } else { //单手武器 _weaponList.Add(model); var slotR = SlotUtils.GetSlotTransform(RootTrans, Slot.RightWeapon); model.transform.parent = slotR; UnityUtils.Reset(model.transform); } return true; } #endregion } }