Files
Main/Assets/Code/Logic/_Required/Entity/Character/Skill/Skill.cs
2025-01-25 04:38:09 +08:00

749 lines
27 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Thousandto.Cfg.Data;
using Thousandto.Code.Center;
using Thousandto.Code.Global;
using Thousandto.Code.Logic;
using Thousandto.Code.Logic.WarningField;
using Thousandto.Core.Asset;
using Thousandto.Core.Base;
using Thousandto.Core.PostEffect;
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace Thousandto.Code.Logic
{
public class Skill : BaseSystem
{
#region//常量
public const float OneFrameTime = 1f / 30f;
//private readonly string SkillWarpName = "skillwarp";//特效扭曲的查找名字
#endregion
#region//属性
public int Serial { get; private set; }
public Character Owner { get; private set; }
public DeclareSkill SkillCfg { get; private set; }
public SkillVisualInfo SkillVisualCfg { get; private set; }
public List<SkillBaseEvent> EventList { get; private set; }
public int CurFrame { get; private set; }
public bool IsFinish { get; private set; }
public SkillSelectFiledType UseSelectType { get; set; }
public Vector2 UseSelectPos { get; set; }
public Vector2 UseSelectDir { get; set; }
public bool CanMove { get; set; }
public bool CanChangeDir { get; set; }
public bool ServerResult { get; set; }
#endregion
#region//私有变量
private float _frameTimer = 0f;
private float _waitResultTime = 0f;
private FGameObjectVFXBox _vfxBox = new FGameObjectVFXBox();
private List<int> _playedAudioList = new List<int>();
private List<int> _playedShakeList = new List<int>();
private static Dictionary<int, List<SkillBaseEvent>> _chcheEvent = null;
private bool _isSync = true;
#endregion
#region//构造函数
public Skill(int serial, Character owner, DeclareSkill skillCfg, bool isSync)
{
Serial = serial;
Owner = owner;
SkillCfg = skillCfg;
CanMove = true;
CanChangeDir = true;
SkillVisualCfg = GameCenter.SkillVisualManager.Find(SkillCfg.VisualDef);
_isSync = isSync;
if (SkillVisualCfg != null)
{
IsFinish = false;
EventList = new List<SkillBaseEvent>(SkillVisualCfg.DataList.Count);
for (int i = 0; i < SkillVisualCfg.DataList.Count; ++i)
{
var eventInfo = SkillVisualCfg.DataList[i];
var newevent = CreateEvent(eventInfo);
if (newevent != null)
{
newevent.Init(this, eventInfo);
if (eventInfo.EventType == SkillEventDefine.DisableMove || eventInfo.EventType == SkillEventDefine.DisableChangeDir)
{
//禁止移动和禁止转向优先执行
EventList.Insert(0, newevent);
}
else
{
EventList.Add(newevent);
}
}
}
}
else
{
IsFinish = true;
}
}
#endregion
#region//公有函数
public List<SkillBaseEvent> FindEvents(SkillEventDefine type)
{
List<SkillBaseEvent> result = new List<SkillBaseEvent>();
for (int i = 0; i < EventList.Count; ++i)
{
if (EventList[i].EventInfo.EventType == type)
{
result.Add(EventList[i]);
}
}
return result;
}
public FGameObjectVFX PlayVFX(ModelTypeCode code, int modeID, bool notLoop)
{
if (modeID > 0)
{
if (GameObjectLimit.CanPlayVfx(Owner, code))
{
if (Owner != null && Owner.Skin != null)
{
var lod = 0;
if (!Owner.IsLocalPlayer() && !Owner.IsLocalFlySword())
{//只针对其他玩家
//这里因为GameSettingKeyCode.OtherPlayerSkillVfxLevel的值是:0屏蔽全部,1弱,2中,3强.
//而lod是0最强,往下最弱.
lod = FGameObjectVFXRoot.CN_VFX_LEVEL_MAX - GameCenter.GameSetting[GameSettingKeyCode.OtherPlayerSkillVfxLevel]; ;
}
var vfx = Owner.Skin.PlayVFX(code, modeID, null, FSkinPartCode.Body, false, 1, true, false, null, false, false, lod);
if (vfx == null) return null;
//SetSkillWarpLayer(vfx, vfx.RootTransform);
//10倍技能帧数
var vfxLifeTime = SkillVisualCfg.FrameCount * OneFrameTime * 10;
if (vfxLifeTime < 5f)
{
vfxLifeTime = 5f;
}
vfx.LiftTime = vfxLifeTime;
vfx.IsNotLoop = notLoop;
_vfxBox.Add(vfx);
return vfx;
}
}
}
return null;
}
/*
public void SetSkillWarpLayer(FGameObjectVFX vfx, Transform trs)
{
for (int i = 0; i < trs.childCount; ++i)
{
if (trs.GetChild(i).name.Contains(SkillWarpName))
{
vfx.SetLayerEx(trs.GetChild(i), LayerUtils.SkillWarp);
}
else
{
SetSkillWarpLayer(vfx, trs.GetChild(i));
}
}
}
*/
public void PlayVFX(ModelTypeCode code, int modeID, Slot slot, Vector2 worldDir, bool notLoop)
{
if (modeID > 0)
{
if (GameObjectLimit.CanPlayVfx(Owner, code))
{
if (Owner != null && Owner.Skin != null)
{
var vfx = Owner.Skin.PlayVFX(code, modeID, SlotUtils.GetSlotName(slot), FSkinPartCode.Body, false, 1, true, true);
vfx.SetForward(new Vector3(worldDir.x, 0f, worldDir.y));
vfx.IsNotLoop = notLoop;
_vfxBox.Add(vfx);
}
}
}
}
public void PlaySfx(string sfxName)
{
var setCode = GameCenter.GameSetting.GetSetting(GameSettingKeyCode.SkillSFX);
if (setCode > 0 || Owner.IsLocalPlayer() || Owner.IsLocalFlySword() || Owner.IsLocalPet())
{
_playedAudioList.Add(AudioPlayer.PlaySfx(null, sfxName, true));
}
}
public void PlayCameraShake(AnimationCurve curve, float totalTime, VFXCameraShakerType shakeType, float power)
{
_playedShakeList.Add(PostEffectManager.Instance.PlayCameraShake(curve, totalTime, shakeType, power));
}
private void DoEvent(int frame)
{
for (int i = 0; i < EventList.Count; ++i)
{
EventList[i].FrameUpdate(frame);
if (frame == EventList[i].EventInfo.EventFrame)
{
EventList[i].Enter();
}
}
}
public void Start()
{
_playedAudioList.Clear();
_playedShakeList.Clear();
if (Owner is LocalPlayer)
{
var lp = Owner as LocalPlayer;
lp.MountDown();
CreateAtkInfo();
SendMessage();
if(!_isSync)
{
//不需要同步的技能直接开始CD
GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_BEGIN_SKILLCD, SkillCfg.Id);
GameCenter.PushFixEvent(Global.LogicEventDefine.EID_EVENT_ON_LP_USE_SKILL, SkillCfg.Id);
}
}
if (Owner is LocalPet)
{
CreatePetAtkInfo();
SendPetMessage();
}
if (Owner is LocalFlySword)
{
CreateFlySwordAtkInfo();
SendFlySwordMessage();
}
_waitResultTime = 0f;
ServerStart();
}
public void ServerStart()
{
if (_isSync && SkillVisualCfg.WaitServerResult && !ServerResult)
return;
CurFrame = 0;
_frameTimer = 0f;
if (Owner.IsLocalPlayer())
{
GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_ON_USED_SKILL, SkillCfg.Id);
}
DoEvent(CurFrame);
//展示警示圈
CombatUtil.ShowWarningFiled(SkillVisualCfg, Owner);
//展示boss技能提示
CombatUtil.ShowBossSkillWarning(SkillCfg, Owner);
}
public void Stop(bool clearEffect = false)
{
try
{
if (EventList != null)
{
for (int i = 0; i < EventList.Count; ++i)
{
EventList[i].Stop();
}
}
if (_vfxBox != null)
{
_vfxBox.Clear(SkillVisualCfg.EndClearVfx || clearEffect);
}
if (clearEffect)
{
if (_playedAudioList != null)
{
for (int i = 0; i < _playedAudioList.Count; ++i)
{
AudioPlayer.Stop(_playedAudioList[i]);
}
}
if (_playedShakeList != null)
{
for (int i = 0; i < _playedShakeList.Count; ++i)
{
PostEffectManager.Instance.StopCameraShake(_playedShakeList[i]);
}
}
}
if (_playedAudioList != null)
{
_playedAudioList.Clear();
}
if (_playedShakeList != null)
{
_playedShakeList.Clear();
}
Destory();
}
catch(Exception ex)
{
Debug.LogErrorFormat("Skill.Stop {0}", ex.ToString());
}
}
public void Destory()
{
if (EventList != null)
{
for (int i = 0; i < EventList.Count; ++i)
{
//归还事件资源
FreeEvent(EventList[i]);
}
EventList.Clear();
}
}
protected override bool OnUpdate(float dt)
{
if (IsFinish)
return true;
if (SkillVisualCfg.WaitServerResult && !ServerResult)
{
_waitResultTime += Time.deltaTime;
if (_waitResultTime >= 1f)
{
//技能结束
IsFinish = true;
}
return true;
}
_frameTimer += dt;
while (_frameTimer >= OneFrameTime)
{
_frameTimer -= OneFrameTime;
++CurFrame;
DoEvent(CurFrame);
}
if (CurFrame > SkillVisualCfg.FrameCount)
{
//技能结束
IsFinish = true;
}
else
{
for (int i = 0; i < EventList.Count; ++i)
{
EventList[i].Update(dt);
}
}
if (!CanMove && CanChangeDir && Owner.IsLocalPlayer())
{
var newDir = Vector2.zero;
if (GameCenter.InputSystem.JoystickHandler.Draging)
{
var lp = Owner as LocalPlayer;
var curTarget = lp.GetCurSelectedTarget();
newDir = GameCenter.InputSystem.JoystickHandler.CurWorldJoystickDir2d.normalized;
if (!CombatUtil.CanAttackTarget(lp, curTarget, false) || !(curTarget is RemotePlayer))
{
var mainTarget = CombatUtil.FindSkillMainTarget(lp, newDir, SkillVisualCfg.UseNeedDis);
if (mainTarget != null)
{
lp.SetCurSelectedTargetId(mainTarget.ID);
}
}
}
else
{
var lp = Owner as LocalPlayer;
var mainTarget = lp.GetCurSelectedTarget();
if (mainTarget != null)
{
newDir = (mainTarget.Position2d - lp.Position2d).normalized;
}
else
{
mainTarget = CombatUtil.FindSkillMainTarget(lp, lp.GetFacingDirection2d(), SkillVisualCfg.UseNeedDis);
if (mainTarget != null)
{
lp.SetCurSelectedTargetId(mainTarget.ID);
newDir = (mainTarget.Position2d - lp.Position2d).normalized;
}
}
}
if (newDir != Vector2.zero)
{
Owner.SetDirection2d(newDir, true, true);
}
}
_vfxBox.Update(0);
return true;
}
#endregion
#region//静态函数
private static SkillBaseEvent GetEvent(Character owner, SkillEventDefine eventType)
{
SkillBaseEvent result = null;
if (_chcheEvent == null)
{
_chcheEvent = new Dictionary<int, List<SkillBaseEvent>>();
}
List<SkillBaseEvent> cacheList = null;
if (owner.IsLocalPlayer())
{
if (_chcheEvent.TryGetValue((int)eventType, out cacheList) && cacheList.Count > 0)
{
result = cacheList[cacheList.Count - 1];
cacheList.RemoveAt(cacheList.Count - 1);
}
}
else if (eventType == SkillEventDefine.PlayAnimation || eventType == SkillEventDefine.PlayVfx || eventType == SkillEventDefine.PlaySfx)
{
if (_chcheEvent.TryGetValue((int)eventType, out cacheList) && cacheList.Count > 0)
{
result = cacheList[cacheList.Count - 1];
cacheList.RemoveAt(cacheList.Count - 1);
}
}
if (result == null)
{
switch (eventType)
{
case SkillEventDefine.PlayAnimation:
result = new PlayAnimationEvent();
break;
case SkillEventDefine.PlayVfx:
result = new PlayVFXEvent();
break;
case SkillEventDefine.PlaySfx:
result = new PlaySFXEvent();
break;
case SkillEventDefine.PlayCameraShake:
if (owner.IsLocalPlayer() || owner.IsLocalFlySword())
{
result = new PlayCameraShakeEvent();
}
break;
case SkillEventDefine.PlayBlur:
if (owner.IsLocalPlayer() || owner.IsLocalFlySword())
{
result = new PlayBlurEvent();
}
break;
case SkillEventDefine.PlaySlow:
if (owner.IsLocalPlayer() || owner.IsLocalFlySword())
{
result = new PlaySlowEvent();
}
break;
case SkillEventDefine.DisableMove:
if (owner.IsLocalPlayer())
{
result = new DisableMoveEvent();
}
break;
case SkillEventDefine.DisableChangeDir:
if (owner.IsLocalPlayer())
{
result = new DisableChangeDirEvent();
}
break;
}
}
return result;
}
private static void FreeEvent(SkillBaseEvent baseEvent)
{
List<SkillBaseEvent> cacheList = null;
if (!_chcheEvent.TryGetValue((int)baseEvent.EventInfo.EventType, out cacheList))
{
cacheList = new List<SkillBaseEvent>();
_chcheEvent.Add((int)baseEvent.EventInfo.EventType, cacheList);
}
if (!cacheList.Contains(baseEvent))
{
cacheList.Add(baseEvent);
}
else
{
UnityEngine.Debug.LogError("代码写错啦,有重复的技能事件缓存,请找杨全福解决问题!!!");
}
}
//清理掉缓存数据
public static void ClearCacheData()
{
if (_chcheEvent != null)
{
_chcheEvent.Clear();
}
}
#endregion
#region//私有函数
private SkillBaseEvent FindEvent(int eventID)
{
for (int i = 0; i < EventList.Count; ++i)
{
if (EventList[i].EventInfo.EventID == eventID)
{
return EventList[i];
}
}
return null;
}
private SkillBaseEvent CreateEvent(SkillBaseEventInfo info)
{
return GetEvent(Owner, info.EventType);
}
//计算攻击信息
private void CreateAtkInfo()
{
var localPlayer = Owner as LocalPlayer;
if (localPlayer == null)
return;
//当前是否按住摇杆
var isHandleJoy = GameCenter.InputSystem.JoystickHandler.Draging;
//当前摇杆指定的方向
var dragDir = GameCenter.InputSystem.JoystickHandler.CurWorldJoystickDir2d;
switch (UseSelectType)
{
case SkillSelectFiledType.None:
{
if (SkillVisualCfg.UseNeedType == SkillUseNeedType.None)
{
UseSelectPos = Owner.Position2d;
UseSelectDir = Owner.GetFacingDirection2d();
}
else
{
//主目标不满足需求才查找最优目标
var mainTarget = localPlayer.GetCurSelectedTarget();
if (mainTarget == null || localPlayer.GetSqrDistance2d(mainTarget.Position2d) > (SkillVisualCfg.UseNeedDis * SkillVisualCfg.UseNeedDis))
{
mainTarget = CombatUtil.FindSkillMainTarget(localPlayer, localPlayer.GetFacingDirection2d(), SkillVisualCfg.UseNeedDis);
}
UseSelectPos = Owner.Position2d;
if (mainTarget != null && !mainTarget.IsDead())
{
localPlayer.SetCurSelectedTargetId(mainTarget.ID);
UseSelectDir = (mainTarget.Position2d - Owner.Position2d).normalized;
if (SkillVisualCfg.UseNeedType == SkillUseNeedType.Pos)
{
UseSelectPos = mainTarget.Position2d;
}
}
else
{
localPlayer.SetCurSelectedTargetId(0);
UseSelectDir = localPlayer.GetFacingDirection2d();
if (SkillVisualCfg.UseNeedType == SkillUseNeedType.Pos)
{
UseSelectPos = localPlayer.Position2d + UseSelectDir * SkillVisualCfg.UseNeedDis;
Vector2 outHit = Vector2.zero;
if (localPlayer.Scene.navigator.Raycast2d(localPlayer.Position2d, UseSelectPos, out outHit))
{
UseSelectPos = outHit;
}
}
}
}
}
break;
case SkillSelectFiledType.SelectDir:
{
UseSelectPos = localPlayer.Position2d;
}
break;
case SkillSelectFiledType.SelectPos:
{
UseSelectDir = (UseSelectPos - Owner.Position2d).normalized;
}
break;
}
localPlayer.SetDirection2d(UseSelectDir, true, true);
}
//发送技能使用消息
private void SendMessage()
{
if (!_isSync)
return;
var localPlayer = Owner as LocalPlayer;
if (localPlayer == null)
return;
var mainTarget = localPlayer.GetCurSelectedTarget();
MSG_Fight.ReqUseSkill msg = new MSG_Fight.ReqUseSkill();
msg.curTargetId = mainTarget != null ? mainTarget.ID : 0;
msg.info = new MSG_Fight.SkillBaseInfo();
msg.info.userID = Owner.ID;
msg.info.skillID = SkillCfg.Id;
msg.info.serial = Serial;
msg.info.dirX = UseSelectDir.x;
msg.info.dirY = UseSelectDir.y;
msg.usePosX = UseSelectPos.x;
msg.usePosY = UseSelectPos.y;
msg.Send();
}
//计算攻击信息
private void CreatePetAtkInfo()
{
var localPet = Owner as LocalPet;
if (localPet == null)
return;
var mainTarget = localPet.GetCurSelectedTarget();
if (SkillVisualCfg.UseNeedType == SkillUseNeedType.None)
{
UseSelectPos = Owner.Position2d;
UseSelectDir = Owner.GetFacingDirection2d();
}
else
{
UseSelectPos = Owner.Position2d;
if (mainTarget != null && !mainTarget.IsDead())
{
localPet.SetCurSelectedTargetId(mainTarget.ID);
UseSelectDir = (mainTarget.Position2d - Owner.Position2d).normalized;
if (SkillVisualCfg.UseNeedType == SkillUseNeedType.Pos)
{
UseSelectPos = mainTarget.Position2d;
}
}
else
{
localPet.SetCurSelectedTargetId(0);
UseSelectDir = localPet.GetFacingDirection2d();
if (SkillVisualCfg.UseNeedType == SkillUseNeedType.Pos)
{
UseSelectPos = localPet.Position2d + UseSelectDir * SkillVisualCfg.UseNeedDis;
Vector2 outHit = Vector2.zero;
if (localPet.Scene.navigator.Raycast2d(localPet.Position2d, UseSelectPos, out outHit))
{
UseSelectPos = outHit;
}
}
}
}
localPet.SetDirection2d(UseSelectDir, true, true);
}
//发送技能使用消息
private void SendPetMessage()
{
if (!_isSync)
return;
var localPet = Owner as LocalPet;
if (localPet == null)
return;
var mainTarget = localPet.GetCurSelectedTarget();
MSG_Fight.ReqUseSkill msg = new MSG_Fight.ReqUseSkill();
msg.curTargetId = mainTarget != null ? mainTarget.ID : 0;
msg.info = new MSG_Fight.SkillBaseInfo();
msg.info.userID = Owner.ID;
msg.info.skillID = SkillCfg.Id;
msg.info.serial = Serial;
msg.info.dirX = UseSelectDir.x;
msg.info.dirY = UseSelectDir.y;
msg.usePosX = UseSelectPos.x;
msg.usePosY = UseSelectPos.y;
msg.Send();
}
//计算攻击信息
private void CreateFlySwordAtkInfo()
{
var localFlySword = Owner as LocalFlySword;
if (localFlySword == null)
return;
var lp = GameCenter.GameSceneSystem.GetLocalPlayer();
if (lp == null)
return;
var mainTarget = localFlySword.GetCurSelectedTarget();
if (SkillVisualCfg.UseNeedType == SkillUseNeedType.None)
{
UseSelectPos = Owner.Position2d;
UseSelectDir = lp.GetFacingDirection2d();
}
else
{
UseSelectPos = Owner.Position2d;
if (mainTarget != null && !mainTarget.IsDead())
{
localFlySword.SetCurSelectedTargetId(mainTarget.ID);
UseSelectDir = (mainTarget.Position2d - Owner.Position2d).normalized;
if (SkillVisualCfg.UseNeedType == SkillUseNeedType.Pos)
{
UseSelectPos = mainTarget.Position2d;
}
}
else
{
localFlySword.SetCurSelectedTargetId(0);
UseSelectDir = lp.GetFacingDirection2d();
if (SkillVisualCfg.UseNeedType == SkillUseNeedType.Pos)
{
UseSelectPos = localFlySword.Position2d + UseSelectDir * SkillVisualCfg.UseNeedDis;
Vector2 outHit = Vector2.zero;
if (localFlySword.Scene.navigator.Raycast2d(localFlySword.Position2d, UseSelectPos, out outHit))
{
UseSelectPos = outHit;
}
}
}
}
localFlySword.SetDirection2d(UseSelectDir, false, true);
}
//发送技能使用消息
private void SendFlySwordMessage()
{
if (!_isSync)
return;
var localFlySword = Owner as LocalFlySword;
if (localFlySword == null)
return;
var mainTarget = localFlySword.GetCurSelectedTarget();
MSG_Fight.ReqUseSkill msg = new MSG_Fight.ReqUseSkill();
msg.curTargetId = mainTarget != null ? mainTarget.ID : 0;
msg.info = new MSG_Fight.SkillBaseInfo();
msg.info.userID = Owner.ID;
msg.info.skillID = SkillCfg.Id;
msg.info.serial = Serial;
msg.info.dirX = UseSelectDir.x;
msg.info.dirY = UseSelectDir.y;
msg.usePosX = UseSelectPos.x;
msg.usePosY = UseSelectPos.y;
msg.Send();
}
#endregion
}
}