/******************************************************************************** * 文件名: SkillCore.cs * 全路径: \Script\GameManager\SkillCore.cs * 创建人: 罗勇 * 创建时间:2013-11-06 * 重构人: Blastom * 重构时间:2018-01-10 * * 功能说明:客户端技能逻辑核心,负责客户端技能逻辑处理 * 修改记录:重构,现SkillCore仅用于处理技能动画和特效等表现,技能判断 * 功能(仅主角需要)移动到Obj_MainPlayer中。更好的结构是把这块搞在 * 技能类本身,就可以让不同技能自己重载修改表现效果 - Blastom *********************************************************************************/ using Games.AnimationModule; using Games.GlobeDefine; using Games.LogicObj; using Games.Scene; using GCGame.Table; using UnityEngine; namespace Games.SkillModle { public class SkillCore { // 最大技能缓存时间,超过该时间会抛弃这个技能 private const float _maxSkillCacheTime = 1f; // SkillCore相当于Obj_Character的一个附件,肯定和Obj共存亡 private readonly Obj_Character _owner; private Vector2 _cachedFacePoint; private Tab_SkillEx _cachedSkill; // 模型加载前就在播放的技能 - 记录时间以判定是否超时 // 实际模型加载完成后,角色位置和面向可能有差错 private float _cachedSkillTime; private bool _cachedSkipWindup; private int _cachedTargetId; // 技能是否处于播放阶段 - CurrentSkill 等参数需要缓存,因此不能用参数判断是否播放 private bool _isPlaying; public SkillCore(Obj_Character owner) { _owner = owner; } // 当前正在使用的技能 public Tab_SkillEx CurrentSkill { get; private set; } // 当前正在使用的技能BaseInfo public Tab_SkillBase CurrentSkillBase { get; private set; } // 当前技能开始时间 public float CurrentSkillTime { get; private set; } // 是否播放技能效果 - 不作为是否能够使用技能的判定 // 其他组件无论先后顺序,都会在同一帧检测到技能释放结束 public bool IsUsingSkill { get { return _isPlaying && CurrentSkillTime + Obj_Character.SkillDuration(CurrentSkill, CurrentSkillBase) > Time.time; } } /// /// 释放一个技能 /// public bool UseSkill(Tab_SkillEx skillEx, Tab_SkillBase skillBase, int targetId, Vector3 facePoint, bool skipWindup = false) { var result = false; if (_isPlaying) EndSkillByBaseId(); // 按原来逻辑,使用动画机检查技能是否应该缓存 if (_owner.AnimLogic == null || !_owner.AnimLogic.AnimPlayable()) { _cachedSkillTime = Time.time; _cachedSkill = skillEx; _cachedTargetId = targetId; _cachedFacePoint = facePoint; _cachedSkipWindup = skipWindup; } else { result = true; _isPlaying = true; ClearCacheSkill(); var previousSkill = CurrentSkill; CurrentSkill = skillEx; CurrentSkillBase = skillBase; CurrentSkillTime = Time.time; // Hack:普攻跳过动画的情况,直接视为技能提前开始 var animSkipTime = skipWindup ? CurrentSkill.CradleTime.ToClientTime() : 0f; CurrentSkillTime -= animSkipTime; // 不允许移动的技能停止角色移动 if (CurrentSkillBase.IsMove < 1 || CurrentSkillBase.IsMoveBreak > 0) _owner.StopMove(); var targetObjCharacter = Singleton.GetInstance().FindObjCharacterInScene(targetId); if (!_owner.IsBindFace()) if (targetObjCharacter == null || targetObjCharacter == _owner) _owner.FaceTo(facePoint); else if (targetObjCharacter.ServerID != _owner.ServerID) _owner.FaceTo(targetObjCharacter.Position); // 开始播放动画 // 跳过其他人释放陷阱的动画,外加强制显示播放动画的人 var playAnim = true; if (_owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_OTHER_PLAYER) if (CurrentSkillBase.Id == (int) SKILLBASEID.HDWLID) playAnim = false; else ToggleShowBySkill(true); if (playAnim) { var transitionName = animSkipTime > 0 && previousSkill != null && previousSkill.NextSkillId == CurrentSkill.SkillExID ? AnimationLogic.GetTransitionName(previousSkill.SatrtMotionId, CurrentSkill.SatrtMotionId) : string.Empty; _owner.AnimLogic.Play(CurrentSkill.SatrtMotionId, transitionName); } //子弹播放 var bulletCount = CurrentSkill.getBulletEffectIDCount(); for (var i = 0; i < bulletCount; i++) { var bullectId = CurrentSkill.GetBulletEffectIDbyIndex(i); if (bullectId > -1) IndependentEffectManager.Instance.ShowBullet(bullectId, _owner.ServerID, targetId, _owner.gameObject.layer, _owner.ObjType); else break; } // 显示技能名称 if (CurrentSkillBase.IsShowSkillName > 0) DisplaySkillName(CurrentSkillBase, string.Empty); if (_owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_MAIN_PLAYER) if (skillBase.SkillClass.ContainFlag((int) SKILLCLASS.DUTIAO)) { //吟唱时间为当前动作的长度 var fYinChangTime = skillEx.YinChangTime.ToClientTime(); SkillProgressLogic.PlayProcess(SkillProgressLogic.ProgressModel.REVERSEDMODE, fYinChangTime, skillBase.Name, skillEx.SkillExID); } else if (skillBase.UseType.ContainFlag((int) SKILLUSETYPE.YINCHANG)) { //吟唱时间为当前动作的长度 var fYinChangTime = skillEx.YinChangTime.ToClientTime(); SkillProgressLogic.PlayProcess(SkillProgressLogic.ProgressModel.ORDERMODEL, fYinChangTime, skillBase.Name, skillEx.SkillExID); } // 被攻击者是主角时,主角宠物试图攻击攻击者 if (targetObjCharacter != null && targetObjCharacter.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_MAIN_PLAYER) { var mainPlayer = targetObjCharacter.TryCastToType(); if (mainPlayer != null) { int threadValue; if (_owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_OTHER_PLAYER) threadValue = 1000; else if (_owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_FELLOW) threadValue = 100; else threadValue = 1; mainPlayer.Controller.ThreadInfo.AddThreat(_owner, threadValue); } } // 摄像机效果 CameraOpt(true); _owner.OnSwithObjAnimState(GameDefine_Globe.OBJ_ANIMSTATE.STATE_SKILL); // 显示技能警告 if (skillEx.WarningText > 0) { var warningContent = TableManager.GetStrDictionaryByID(skillEx.WarningText, 0); var warningStart = Mathf.Max(0f, skillEx.WarningStart.ToClientTime()); var warningDuration = (skillEx.WarningDuration > 0f ? skillEx.WarningDuration : skillEx.SkillContinueTime).ToClientTime(); CentreNoticeLogic.ShowSkillWarning(warningContent.StrDictionary, warningStart, warningDuration); } } return result; } public void UserCacheSkill() { if (_cachedSkill != null) if (_cachedSkillTime + _maxSkillCacheTime > Time.time) { var skillBase = CommonUtility.TryGetTable(_cachedSkill.BaseId, a => TableManager.GetSkillBaseByID(a, 0)); if (skillBase != null) UseSkill(_cachedSkill, skillBase, _cachedTargetId, _cachedFacePoint, _cachedSkipWindup); else ClearCacheSkill(); } else { ClearCacheSkill(); } } private void ClearCacheSkill() { _cachedSkill = null; } public void UpdateSkill() { if (_isPlaying && !IsUsingSkill) EndSkillByBaseId(); } public void EndSkillByBaseId(int baseId = -1) { if (_isPlaying && (baseId < 0 || CurrentSkill.BaseId == baseId)) { ClearCacheSkill(); CameraOpt(false); _owner.EnableMovingRotation(true); // 如果技能动画是循环动画,需要切换到Idle动画 if (CurrentSkill.SatrtMotionId > -1) { var idleId = _owner.GetIdleAnimId(); if (_owner.AnimLogic != null) _owner.AnimLogic.SwitchLoopToIdle(CurrentSkill.SatrtMotionId, idleId); } if (_owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_MAIN_PLAYER || _owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_OTHER_PLAYER) { var player = _owner as Obj_OtherPlayer; if (null != player) player.UpdateVisualAfterSkill(); } //如果需要在技能结束的时候 停止对应的特效 则停止 if (CurrentSkillBase.IsNeedStopEffectId > -1) _owner.StopEffect(CurrentSkillBase.IsNeedStopEffectId); if (_owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_OTHER_PLAYER) ToggleShowBySkill(false); // 处理吟唱技能进度条 else if (_owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_MAIN_PLAYER) SkillProgressLogic.StopProcess(CurrentSkill.SkillExID); _isPlaying = false; } } // 控制摄像头 createInstance private void CameraOpt(bool isStart) { if (SceneLogic.CameraController != null) { if (CurrentSkill.CameraRockId > -1) if (isStart) { var priority = _owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_MAIN_PLAYER ? 1 : 0; if (CurrentSkill.CameraRockRate > Random.Range(0, 100)) SceneLogic.CameraController.StartCameraRock(CurrentSkill.CameraRockId, _owner, priority); } else { SceneLogic.CameraController.StopCameraRock(CurrentSkill.CameraRockId, _owner.ServerID); } //XP技能拉高摄像机视角 if (CurrentSkillBase.Id == (int) SKILLBASEID.YGSDID || CurrentSkillBase.SkillClass.ContainFlag((int) SKILLCLASS.XP)) SceneLogic.CameraController.FoVOverride = isStart ? 1.0f : -1.0f; } } // 动画机缓存无法解决特效问题,因此还是需要强制显示 private void ToggleShowBySkill(bool isStart) { if (!_owner.ModelInViewPort) if (isStart) _owner.BecameVisible(); else _owner.BecameInvisible(); } private void DisplaySkillName(Tab_SkillBase skillBase, string skillName) { if (string.IsNullOrEmpty(skillName)) { if (_owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_MAIN_PLAYER) _owner.ShowDamageBoard_SkillName(GameDefine_Globe.DAMAGEBOARD_TYPE.SKILL_NAME, skillBase.Name); else if (_owner.ObjType == GameDefine_Globe.OBJ_TYPE.OBJ_NPC) _owner.ShowDamageBoard_SkillName(GameDefine_Globe.DAMAGEBOARD_TYPE.SKILL_NAME_NPC, skillBase.Name, false); else if (_owner.ObjType != GameDefine_Globe.OBJ_TYPE.OBJ_OTHER_PLAYER) _owner.ShowDamageBoard_SkillName(GameDefine_Globe.DAMAGEBOARD_TYPE.SKILL_NAME, skillBase.Name, false); } else { _owner.ShowDamageBoard_SkillName(GameDefine_Globe.DAMAGEBOARD_TYPE.SKILL_NAME, skillName, false); } } //显示技能名字 public static void ShowSkillName(int skillId, int senderId, string skillName) { var skillSender = Singleton.GetInstance().FindObjCharacterInScene(senderId); if (skillSender != null) { var skillEx = TableManager.GetSkillExByID(skillId, 0); Tab_SkillBase skillBase = null; if (skillEx != null) skillBase = TableManager.GetSkillBaseByID(skillEx.BaseId, 0); if (skillBase != null && skillSender.SkillCore != null) skillSender.SkillCore.DisplaySkillName(skillBase, skillName); } } } }