|
using vnxbqy.UI;
|
using UnityEngine;
|
using UnityEngine.Events;
|
|
public abstract class GActorFight : GActor
|
{
|
public UnityAction OnDie;
|
public UnityAction<int> OnSkillCompelete;
|
|
/// <summary>
|
/// 被动选择的对象
|
/// 主角自动选怪目标,
|
/// 其他玩家确定主攻击目标
|
/// </summary>
|
private GActor selectTarget;
|
public virtual GActor SelectTarget
|
{
|
get { return selectTarget; }
|
set
|
{
|
selectTarget = value;
|
// if (selectTarget != null)
|
// {
|
// if (this is GA_Hero)
|
// {
|
// Debug.Log("更换了SelectTarget.......:" + selectTarget.ServerInstID);
|
// }
|
// }
|
// else
|
// {
|
// if (this is GA_Hero)
|
// {
|
// Debug.Log("更换了SelectTarget.......: null");
|
// }
|
// }
|
}
|
}
|
|
/// <summary>
|
/// 如果有,杀死这个npc使用的死亡飞行配置
|
/// </summary>
|
public int DeadFlyID { get; set; }
|
public Vector3 KillerPos { get; set; }
|
/// <summary>
|
/// 被击死亡的时候攻击者的位置
|
/// </summary>
|
public Vector3 KillPosWhenKilled { get; set; }
|
|
protected AudioSource m_AudioSource = null;
|
|
protected SkinnedMeshRenderer m_SMRenderer;
|
protected Material m_Material;
|
|
protected SkillManager m_SkillManager;
|
public SkillManager SkillMgr
|
{
|
get { return m_SkillManager; }
|
set { throw new System.NotImplementedException(); }
|
}
|
|
protected override void OnInit(GameNetPackBasic package)
|
{
|
ActorInfo.OnHpChange += RefreshLifeBar;
|
m_SkillManager = new SkillManager(ServerInstID);
|
|
// 创建音源
|
GameObject _audioSourceNode = Object.Instantiate(BuiltInLoader.LoadPrefab("AudioSource3D")) as GameObject;
|
#if UNITY_EDITOR
|
_audioSourceNode.name = "AudioSource";
|
#endif
|
_audioSourceNode.transform.SetParent(m_Root);
|
_audioSourceNode.transform.localPosition = new Vector3(0, 0.5f, 0);
|
m_AudioSource = _audioSourceNode.GetComponent<AudioSource>();
|
|
m_AudioSource.playOnAwake = false;
|
m_AudioSource.spatialBlend = 1;
|
}
|
|
protected override void OnUnit()
|
{
|
HideEffect();
|
|
m_StartedFlash = false;
|
m_FlashLastTime = 0;
|
SelectTarget = null;
|
if (m_Material)
|
{
|
m_Material.SetFloat(m_FlashWhiteParamID, 0);
|
}
|
|
if (m_AudioSource)
|
{
|
Object.Destroy(m_AudioSource.gameObject);
|
m_AudioSource = null;
|
}
|
|
selectTarget = null;
|
ActorInfo.OnHpChange -= RefreshLifeBar;
|
m_SkillManager = null;
|
m_Material = null;
|
m_SMRenderer = null;
|
m_BeatCurve = null;
|
OnDie = null;
|
OnSkillCompelete = null;
|
|
|
// 这里在npc卸载的时候对当前选中对象进行清除逻辑
|
GA_Hero _hero = PlayerDatas.Instance.hero;
|
if (_hero != null)
|
{
|
if (_hero.LockTarget == this)
|
{
|
_hero.LockTarget = null;
|
}
|
|
if (_hero.SelectTarget == this)
|
{
|
_hero.SelectTarget = null;
|
}
|
}
|
}
|
|
public override void ShowEffect() { }
|
|
public abstract override void Destroy();
|
|
/// <summary>
|
/// 初始化出生点坐标
|
/// </summary>
|
/// <param name="sPosX">服务端坐标X</param>
|
/// <param name="sPosY">服务端坐标Y</param>
|
public void InitBornPos(ushort sPosX, ushort sPosY)
|
{
|
AdjustPos(sPosX, sPosY);
|
PrevPos = Pos;
|
}
|
|
protected override void OnUpdate()
|
{
|
if (m_SkillManager != null)
|
{
|
m_SkillManager.Update();
|
}
|
}
|
|
protected override void OnFixedUpdate()
|
{
|
UpdateFlashWhite();
|
UpdateFlashRed();
|
UpdateBeatBack();
|
}
|
|
public abstract bool CanPushedBack();
|
public abstract bool CanHurted();
|
public abstract bool CanDieFly();
|
public abstract bool CanAtked();
|
public abstract bool CanAtkedRotate();
|
|
public abstract void RefreshLifeBar(ulong value);
|
|
public void Die(uint killerServerInstID, int configID = 0, byte hurtType = (byte)HurtAttackType.Normal)
|
{
|
KillerServerInstID = killerServerInstID;
|
DeadFlyID = configID;
|
killHurtType = hurtType;
|
|
Die();
|
}
|
|
#region 击退
|
|
private float m_BeatTime;
|
private AnimationCurve m_BeatCurve;
|
private Vector3 m_StartBeatPos;
|
private float m_Factor;
|
private float m_BeatStartTime;
|
public bool BeBeating { get; protected set; }
|
private Vector3 m_BeatDirection;
|
private bool m_PushOrPull;
|
private uint m_AttackerSID;
|
private float m_LimitDistance;
|
private float m_AddPer;
|
|
public void StartBeatBack(uint attacker, int configID, Vector3 direction, HurtAttackType atkType = HurtAttackType.Normal, float ExtDis = 0f)
|
{
|
SoBodyControl _config = ScriptableObjectLoader.LoadSoBodyControl(configID);
|
|
if (_config == null || _config.curve == null)
|
{
|
return;
|
}
|
|
m_AttackerSID = attacker;
|
m_LimitDistance = _config.limitDistance + ExtDis;
|
m_PushOrPull = _config.pushOrPull;
|
|
if (!m_PushOrPull)
|
{
|
direction = -direction;
|
}
|
|
m_BeatDirection = direction;
|
m_BeatCurve = _config.curve;
|
m_BeatTime = _config.duration;
|
|
if (GeneralDefine.AtkTypeIncreasePushDis.ContainsKey((int)atkType))
|
{
|
m_AddPer = GeneralDefine.AtkTypeIncreasePushDis[(int)atkType];
|
}
|
else
|
{
|
m_AddPer = 1f;
|
}
|
|
m_Factor = m_BeatCurve.keys[m_BeatCurve.length - 1].time * m_AddPer;
|
m_Factor = m_Factor / m_BeatTime;
|
|
if (ActorType == GameObjType.gotNPC)
|
{
|
GActorNpcFight _npcBase = this as GActorNpcFight;
|
if (_npcBase != null)
|
{
|
if (_npcBase.NpcConfig.weight != 0)
|
{
|
m_Factor = m_Factor / _npcBase.NpcConfig.weight;
|
}
|
}
|
}
|
|
m_StartBeatPos = Pos;
|
m_BeatStartTime = Time.time;
|
BeBeating = true;
|
needSyncGroundHeight = false;
|
}
|
|
private void UpdateBeatBack()
|
{
|
if (!BeBeating)
|
{
|
return;
|
}
|
|
if (NextAction == GAStaticDefine.Act_Dead
|
|| m_BeatCurve == null
|
|| ActorInfo.serverDie)
|
{
|
BeBeating = false;
|
return;
|
}
|
|
float _delta = (Time.time - m_BeatStartTime) * m_Factor;
|
|
Vector3 _h = m_BeatDirection * _delta;
|
Vector3 _v = new Vector3(0, m_BeatCurve.Evaluate(_delta), 0);
|
Vector3 _pos = m_StartBeatPos + _h + _v;
|
Vector3 _end = _pos;
|
|
GActor _attacker = GAMgr.Instance.GetBySID(m_AttackerSID);
|
|
if (_attacker == null)
|
{
|
BeBeating = false;
|
return;
|
}
|
|
float _dis = MathUtility.DistanceSqrtXZ(m_StartBeatPos, _end);
|
|
if (m_PushOrPull)
|
{
|
if (MathUtility.DistanceSqrtXZ(m_StartBeatPos, _end) > m_LimitDistance * m_LimitDistance)
|
{
|
_end = m_StartBeatPos + m_BeatDirection * m_LimitDistance;
|
}
|
}
|
else
|
{
|
Vector3 _limPos = _attacker.Pos;
|
_limPos.y = 0;
|
_limPos = _limPos - m_BeatDirection * m_LimitDistance;
|
Vector3 _dir2 = (_end - _limPos).normalized;
|
|
bool _isOp = MathUtility.OppositeDir(-m_BeatDirection, _dir2);
|
bool _isLimDis = MathUtility.DistanceSqrtXZ(_attacker.Pos, _end) < m_LimitDistance * m_LimitDistance;
|
|
if (_isOp
|
|| _isLimDis)
|
{
|
_end = _attacker.Pos - m_BeatDirection * m_LimitDistance;
|
needSyncGroundHeight = true;
|
BeBeating = false;
|
}
|
}
|
|
Vector3 _position = m_StartBeatPos;
|
_position.y = 0;
|
_end.y = 0;
|
|
UnityEngine.AI.NavMeshHit _hit;
|
if (UnityEngine.AI.NavMesh.Raycast(_position, _end, out _hit, -1))
|
{
|
_end = _hit.position;
|
}
|
if (this is GActorNpcFight)
|
{
|
TryGetValidPos(_end, ref _end);
|
}
|
PrevPos = Pos = new Vector3(_end.x, _pos.y, _end.z);
|
|
if (Time.time - m_BeatStartTime > m_BeatTime)
|
{
|
needSyncGroundHeight = true;
|
BeBeating = false;
|
}
|
}
|
|
#endregion
|
|
#region 闪白, 闪红
|
private int m_FlashWhiteParamID = Shader.PropertyToID("_Hit");
|
private int m_FlashRedParamID = Shader.PropertyToID("_BaTi");
|
private bool m_StartedRed = false;
|
private float m_FlashRedCurTime = 0;
|
private float m_FlashRedTotablTime = 0;
|
|
private bool m_StartedFlash = false;
|
private float m_FlashLastTime;
|
private float m_FlashLimitTime = 0.3f;
|
|
public void DoFlashRed(float remainTime, float duration)
|
{
|
if (m_StartedRed)
|
{
|
return;
|
}
|
|
if (GetMaterial())
|
{
|
GetMaterial().SetFloat(m_FlashRedParamID, 6);
|
}
|
|
m_FlashRedCurTime = duration - remainTime;
|
m_FlashRedTotablTime = duration;
|
|
m_StartedRed = true;
|
}
|
|
private void UpdateFlashRed()
|
{
|
if (m_StartedRed)
|
{
|
if (GetMaterial())
|
{
|
m_FlashRedCurTime += Time.deltaTime;
|
|
if (m_FlashRedCurTime > m_FlashRedTotablTime)
|
{
|
GetMaterial().SetFloat(m_FlashRedParamID, 0);
|
m_StartedRed = false;
|
}
|
}
|
else
|
{
|
m_StartedRed = false;
|
}
|
|
}
|
}
|
|
public void DoFlashWhite()
|
{
|
if (ServerInstID == PlayerDatas.Instance.PlayerId)
|
{
|
return;
|
}
|
|
m_StartedFlash = true;
|
m_FlashLastTime = 0;
|
}
|
|
private void UpdateFlashWhite()
|
{
|
if (m_StartedFlash)
|
{
|
m_FlashLastTime += Time.deltaTime;
|
float _flashValue = Constants.hurtAniCurve.animationCurve.Evaluate(2 * m_FlashLastTime);
|
if (GetMaterial())
|
{
|
GetMaterial().SetFloat(m_FlashWhiteParamID, _flashValue);
|
|
if (m_FlashLastTime > m_FlashLimitTime)
|
{
|
m_StartedFlash = false;
|
GetMaterial().SetFloat(m_FlashWhiteParamID, 0);
|
}
|
}
|
}
|
}
|
|
#endregion
|
|
protected Material GetMaterial()
|
{
|
return m_Material;
|
}
|
|
public SkinnedMeshRenderer GetSMRenderer()
|
{
|
return m_SMRenderer;
|
}
|
|
public void PlaySkillAudio(int id)
|
{
|
if (m_AudioSource)
|
{
|
SoundPlayer.Instance.PlayAudio(m_AudioSource, id);
|
if (this is GA_Hero)
|
{
|
SoundUtility.PlayFightRoar(m_AudioSource, PlayerDatas.Instance.baseData.Job);
|
}
|
}
|
}
|
|
public virtual void PlayHurtAudio(GActorFight attacker)
|
{
|
SoundUtility.PlayHitAudio(attacker.m_AudioSource);
|
}
|
|
public bool IsPolyMorph { get; protected set; }
|
protected GameObject m_SheepModel;
|
protected bool m_SheepIsDefaultNpc;
|
public virtual void Polymorph(bool doOrNo, int npcID = 0) { }
|
protected virtual void ChangeBinderToRoot() { }
|
protected virtual void ChangeBinderToClothes() { }
|
}
|