using System.Collections.Generic;
using vnxbqy.UI;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
public abstract class GActor
{
#region 角色基础模块(表现,基本朝向,坐标)
public Transform MP_Name { get; protected set; }
public Transform MP_Name1 { get; protected set; }
public Transform MP_Hit { get; protected set; }
public Transform MP_Down { get; protected set; }
public Transform MP_Stun { get; protected set; }
public Transform MP_Weapon { get; protected set; }
public Transform MP_FollowDown { get; protected set; }
public uint ClientInstID { get; protected set; }
public uint ServerInstID { get; protected set; }
protected Transform m_Root = null;
public Transform Root { get { return m_Root; } }
///
/// 如果有,杀死这个npc的角色服务器实例ID
///
private uint m_KillServerInstID;
public uint KillerServerInstID
{
get { return m_KillServerInstID; }
set { m_KillServerInstID = value; }
}
public byte killHurtType;
public int belongEventID = -1;
private Vector3 m_BornPos;
public virtual Vector3 BornPos
{
get { return m_BornPos; }
set { m_BornPos = value; }
}
private Vector3 m_Pos;
public Vector3 Pos
{
get { return m_Pos; }
set
{
#if UNITY_EDITOR
if (this is GA_NpcFunc)
{
string _content = string.Format("{0} / {1} => 设置了位置: {2}", ServerInstID, (this as GA_NpcFunc).NpcConfig.NPCID, value);
RuntimeLogUtility.AddLog(_content, ServerInstID, true);
if (value == Constants.Special_Hide_Position)
{
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
System.Diagnostics.StackFrame[] sfs = st.GetFrames();
for (int i = 0; i < sfs.Length && i < 2; ++i)
{
System.Reflection.MethodBase mb = sfs[i].GetMethod();
RuntimeLogUtility.AddLog(string.Format("{0} / {1} => └ {2}.{3}", ServerInstID, (this as GA_NpcFunc).NpcConfig.NPCID, mb.DeclaringType.FullName, mb.Name), ServerInstID, true);
}
}
}
#endif
m_Pos = value;
if (m_Root)
{
m_Root.position = m_Pos;
}
// #if UNITY_EDITOR
// if (this is GActorNpcFight)
// {
// if (ServerInstID == 4)
// {
// Debug.Log(ServerInstID + " => 坐标改变.....: " + value);
// }
// }
// #endif
}
}
private float m_EulerAngles;
public float EulerAngles
{
get { return m_EulerAngles; }
set
{
m_EulerAngles = value;
if (m_Root)
{
m_Root.eulerAngles = new Vector3(0, m_EulerAngles, 0);
m_Forward = m_Root.forward;
m_Rotation = Quaternion.LookRotation(m_Forward, Vector3.up);
}
}
}
private Vector3 m_Forward;
public Vector3 Forward
{
get
{
if (m_Forward == Vector3.zero)
{
m_Forward = m_Root.forward;
}
return m_Forward;
}
set
{
value.y = 0;
if (value != Vector3.zero)
{
m_Forward = value;
m_Rotation = Quaternion.LookRotation(m_Forward, Vector3.up);
if (m_Root)
{
m_Root.rotation = m_Rotation;
}
if (ServerInstID == PlayerDatas.Instance.PlayerId)
{
// System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
// System.Diagnostics.StackFrame[] sfs = st.GetFrames();
// string _content = "";
// for (int u = 0; u < sfs.Length; ++u)
// {
// System.Reflection.MethodBase mb = sfs[u].GetMethod();
// _content += string.Format("[CALL STACK][{0}]: {1}.{2}\r\n", u, mb.DeclaringType.FullName, mb.Name);
// }
// Debug.Log(_content);
// Debug.Log("转向了.......: " + m_Forward);
}
}
}
}
///
/// 目标朝向
/// 主要与当前比较, 做转身的缓动处理的一个方向
///
public Vector3 destForward;
private Quaternion m_Rotation;
public Quaternion Rotation
{
get { return m_Rotation; }
set
{
m_Rotation = value;
if (m_Root)
{
m_Root.rotation = m_Rotation;
}
m_Forward = m_Root.forward;
}
}
public GameObjType ActorType { get; protected set; }
public E_ActorGroup Group { get; protected set; }
public GActorInfo ActorInfo { get; protected set; }
private E_ActorState m_State;
public E_ActorState State
{
get { return m_State; }
set
{
m_State = value;
// if (ServerInstID == PlayerDatas.Instance.PlayerId)
// {
// Debug.Log("状态改变: " + value.ToString());
// }
}
}
public bool ShowOrHide { get; protected set; }
private bool m_NeedSyncGroundHeight = true;
public bool needSyncGroundHeight
{
get { return m_NeedSyncGroundHeight; }
set
{
m_NeedSyncGroundHeight = value;
}
}
protected Vector3 m_PrevPos;
public Vector3 PrevPos
{
get
{
return m_PrevPos;
}
set
{
if (m_PrevPos == value)
{
return;
}
m_PrevPos = value;
}
}
public abstract int NextAction { get; set; }
#endregion
#region 供外部调用基础接口(初始化, 卸载, 更新)
public void Init(uint serverInstID, uint clientInstID, E_ActorGroup group, GameNetPackBasic package)
{
ShowOrHide = true;
needSyncGroundHeight = true;
if (!m_Root)
{
m_Root = new GameObject().transform;
// 将被复用,不被销毁
Object.DontDestroyOnLoad(m_Root);
}
m_Root.localScale = Vector3.one;
Forward = m_Root.forward;
// 角色属性
if (ActorInfo == null)
{
ActorInfo = new GActorInfo();
}
ActorInfo.sid = serverInstID;
ActorInfo.ownerSID = 0;
ActorInfo.serverDie = false;
#if UNITY_EDITOR
m_Root.name = string.Format("{0}_{1}_{2}",
GetType().ToString(),
serverInstID,
clientInstID);
#endif
ServerInstID = serverInstID;
ClientInstID = clientInstID;
Group = group;
State = E_ActorState.Idle;
OnInit(package);
#if UNITY_EDITOR
if (ServerInstID == PlayerDatas.Instance.PlayerId)
{
SnxxzGame.Instance.AddOnDrawGizmosAction(OnDrawGizmos);
}
#endif
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawLine(Pos + new Vector3(0, .5f, 0),
Pos + new Vector3(0, .5f, 0) + destForward * 10);
Gizmos.DrawSphere(Pos, .3f);
if (State == E_ActorState.AutoRun)
{
if (GetCorners() != null && GetCorners().Length > 0)
{
Gizmos.color = Color.blue;
for (int i = 0; i < GetCorners().Length; ++i)
{
Gizmos.DrawSphere(new Vector3(GetCorners()[i].x, Pos.y, GetCorners()[i].z), 0.1f);
if (i < GetCorners().Length - 1)
{
Gizmos.DrawLine(new Vector3(GetCorners()[i].x, Pos.y, GetCorners()[i].z),
new Vector3(GetCorners()[i + 1].x, Pos.y, GetCorners()[i + 1].z));
}
}
}
}
}
#endif
public void UnInit()
{
#if UNITY_EDITOR
if (ServerInstID == PlayerDatas.Instance.PlayerId)
{
SnxxzGame.Instance.RemoveOnDrawGizmosAction(OnDrawGizmos);
}
#endif
OnUnit();
belongEventID = -1;
State = E_ActorState.Idle;
DestPos = Vector3.zero;
ActorInfo.serverDie = true;
ActorInfo.Clear();
}
public abstract void Destroy();
public void Update()
{
UpdatePathFinding();
OnUpdate();
}
public void LateUpdate()
{
OnLateUpdate();
}
private Vector3 recordSyncHeightPos;
public void FixedUpdate()
{
if (recordSyncHeightPos != Pos)
{
if (needSyncGroundHeight)
{
float _groundHeight = Pos.y;
if (CollisionUtility.TryGetGroundHeight(Pos, out _groundHeight))
{
Vector3 _pos = Pos;
_pos.y = _groundHeight;
Pos = _pos;
}
}
recordSyncHeightPos = Pos;
}
if (MP_Down)
{
if (MP_FollowDown)
{
MP_FollowDown.position = MP_Down.position;
}
}
OnFixedUpdate();
}
#endregion
#region 寻路模块
private NavMeshPath m_Path = new NavMeshPath();
private float m_KeepDist;
private E_SearchType m_SearchType;
private int m_CornerIndex;
public Vector3 DestPos { get; private set; }
public GActor TargetActor { get; private set; }
public E_PathFindStatus PathFindStatus { get; private set; }
public event UnityAction OnPathFindStart;
public event UnityAction OnPathFinding;
public event UnityAction OnPathFindStop;
public Vector3[] GetCorners()
{
return m_Path.corners;
}
public void MoveToTarget(GActor target, float keepDist = 0, bool force = false)
{
if (PathFindStatus == E_PathFindStatus.Moving
&& m_SearchType == E_SearchType.Dynamic
&& TargetActor == target
&& !force)
{
return;
}
Vector3 _validPos = Pos;
if (TryGetValidPos(target.Pos, ref _validPos))
{
m_SearchType = E_SearchType.Dynamic;
TargetActor = target;
// if (this is GA_Hero)
// {
// Debug.Log("开始寻路至目标: " + target);
// }
// 这里记录坐标的意义
// 在可能发生坐标动态变化的目标用以与之前记录坐标比较
// 判断是否在寻路过程中需要重新执行寻路
DestPos = _validPos;
MoveTo(_validPos, keepDist);
}
}
public void MoveToPosition(Vector3 destPos, float keepDist = 0, bool force = false)
{
if (PathFindStatus == E_PathFindStatus.Moving
&& m_SearchType == E_SearchType.Static
&& MathUtility.DistanceSqrtXZ(DestPos, destPos) < 0.01f
&& !force)
{
Run();
return;
}
DestPos = destPos;
Vector3 _validPos = Pos;
if (TryGetValidPos(destPos, ref _validPos))
{
DestPos = _validPos;
m_SearchType = E_SearchType.Static;
MoveTo(_validPos, keepDist);
}
}
public void ClearPathFindTarget()
{
TargetActor = null;
DestPos = Vector3.zero;
}
public void StopPathFind()
{
PathFindStatus = E_PathFindStatus.Stop;
if (State != E_ActorState.AutoRun)
{
return;
}
// if (this is GActorNpcFight
// && (ServerInstID == 133 || ServerInstID == 134 || ServerInstID == 112))
// {
// Debug.LogFormat("{0} 停止寻路至点: ", ServerInstID);
// }
TargetActor = null;
DestPos = Vector3.zero;
m_CornerIndex = 0;
if (NextAction != GAStaticDefine.Act_Dead
&& NextAction != 200
&& !(this is GA_Player))
{
Idle();
}
// 如果停止的时候未被其他状态打断, 则切换状态为站立
if (State == E_ActorState.AutoRun)
{
State = E_ActorState.Idle;
GA_Hero _hero = this as GA_Hero;
if (_hero != null)
{
if (!UserInputHandler.isTouched
&& !_hero.IsRushing
&& !GA_Hero.s_MapSwitching)
{
_hero.PrevPos = Pos;
UserInputHandler.Send_CB409_tagCMPyMove(0);
}
}
}
if (OnPathFindStop != null)
{
OnPathFindStop();
}
// if (ServerInstID == PlayerDatas.Instance.PlayerId)
// {
// Debug.Log("停止了移动");
// }
}
private void MoveTo(Vector3 position, float keepDist = 0)
{
Vector3 _curPos = Pos;
_curPos.y = 0;
if (NavMesh.CalculatePath(_curPos, position, NavMesh.AllAreas, m_Path))
{
m_CornerIndex = 0;
m_KeepDist = keepDist;
PathFindStatus = E_PathFindStatus.Moving;
if (OnPathFindStart != null)
{
OnPathFindStart();
}
Run();
State = E_ActorState.AutoRun;
// if (this is GActorNpcFight
// && (ServerInstID == 133 || ServerInstID == 134 || ServerInstID == 112))
// {
// Debug.LogFormat("{0} 开始寻路至点: {1}", ServerInstID, position);
// }
}
}
public static bool TryGetValidPos(Vector3 position, ref Vector3 validPosition)
{
bool _result = false;
position.y = 0;
NavMeshHit _hit;
if (NavMesh.SamplePosition(position, out _hit, 5, NavMesh.AllAreas))
{
_result = true;
validPosition = _hit.position;
}
return _result;
}
private void UpdatePathFinding()
{
if (State == E_ActorState.AutoRun
&& PathFindStatus == E_PathFindStatus.Moving
&& m_Path.corners != null && m_Path.corners.Length > 0
&& !ActorInfo.serverDie
&& PlayerDatas.Instance.IsTickVaild())
{
if (m_CornerIndex > m_Path.corners.Length - 1)
{
StopPathFind();
return;
}
Vector3 _curCorner = Pos;
// 获得当前点, 一般的寻路都会产生2个点
// 第一个点为寻路起点, 所以这里如果是第一次取
// 则直接取第二个点
if (m_CornerIndex == 0 && m_Path.corners.Length > 1)
{
m_CornerIndex = 1;
}
if (m_Path.corners != null && m_CornerIndex < m_Path.corners.Length)
{
_curCorner = m_Path.corners[m_CornerIndex];
}
// 计算坐标差
Vector3 _curPos = Pos;
_curPos.y = 0;
_curCorner.y = 0;
_curCorner.y = Pos.y;
Vector3 _dir = MathUtility.ForwardXZ(_curCorner, Pos);
if (_dir != Vector3.zero)
{
Quaternion _quaternion = Quaternion.LookRotation(_dir, Vector3.up);
Rotation = Quaternion.RotateTowards(Rotation, _quaternion, GeneralDefine.RotateSpeed);
destForward = _dir;
}
float _deltaDis = ActorInfo.moveSpeed * Time.deltaTime;
if (_deltaDis > .5f)
{
_deltaDis = .5f;
}
Vector3 _detalMove = _deltaDis * _dir;
var _next = _curPos + _detalMove;
var _vec1 = _curCorner - _curPos;
var _vec3 = _curCorner - _next;
if (!MathUtility.IsSameDir(_vec1, _vec3) || _curPos == _next)
{
Pos += _detalMove;
if (m_CornerIndex < m_Path.corners.Length - 1)
{
m_CornerIndex += 1;
}
}
else
{
Pos += _detalMove;
}
if (OnPathFinding != null)
{
OnPathFinding();
}
float _chkDistSqrt = 0;
// 寻找动态目标的时候
// 判断目标是否坐标发生了需要重新寻路的变化
if (m_SearchType == E_SearchType.Dynamic)
{
_chkDistSqrt = MathUtility.DistanceSqrtXZ(TargetActor.Pos, DestPos);
if (_chkDistSqrt > 1)
{
MoveToTarget(TargetActor, m_KeepDist);
}
}
// 判断和终点是否已经达到保持值得
_chkDistSqrt = MathUtility.DistanceSqrtXZ(DestPos, Pos);
//是主角冲锋
GA_Hero _hero = this as GA_Hero;
if (_hero != null && MapTransferUtility.tagetNPCforRush != 0)
{
// 判断是否需要冲锋
if (_hero.IsNeedRush(_chkDistSqrt))
{
_hero.StartRush();
}
}
if ((_chkDistSqrt - m_KeepDist * m_KeepDist) <= .05f)
{
StopPathFind();
}
}
}
private enum E_SearchType
{
Dynamic,
Static,
}
public enum E_PathFindStatus
{
Moving,
Stop,
}
#endregion
#region 派生类需实现接口部分
protected abstract void OnInit(GameNetPackBasic package);
protected abstract void OnUnit();
protected abstract void OnUpdate();
protected abstract void OnLateUpdate();
protected abstract void OnFixedUpdate();
public abstract void RequestName();
public abstract void ReleaseName();
public abstract void RequestLifeBar();
public abstract void ReleaseLifeBar();
public abstract void RequestShadow();
public abstract void ReleaseShadow();
#endregion
#region 表现层动画行为的接口
public abstract void SetAnimatorSpeed(float speed);
public abstract void Play(int stateNameHash, float normalizeTime = 0);
public abstract void Idle();
public abstract void IdleImmediate();
public abstract void Run();
public abstract void RunImmediate();
public abstract void Die();
public abstract void Hurt();
public abstract void HurtDown();
public abstract bool IsIdle();
public abstract bool IsRun();
public abstract bool IsHurt();
public abstract bool IsStun();
public abstract bool HasState(int stateHash);
#endregion
protected List m_EffectList = new List();
public abstract void ShowOrHideModel(bool showOrHide);
public abstract void ShowEffect();
public virtual void HideEffect()
{
foreach (var _ctrl in m_EffectList)
{
SFXPlayUtility.Instance.Release(_ctrl);
}
m_EffectList.Clear();
}
protected Vector3 MP_Name_Pos;
protected void SetupBindNode(Transform parent)
{
// 绑定点确定
MP_Stun = parent.GetChildTransformDeeply("A_Stun");
if (!MP_Stun)
{
MP_Stun = parent;
}
MP_Name = parent.GetChildTransformDeeply("A_Name");
if (!MP_Name)
{
MP_Name = parent;
}
MP_Name1 = parent.GetChildTransformDeeply("A_Name2");
if (!MP_Name1)
{
MP_Name1 = parent;
}
MP_Hit = parent.GetChildTransformDeeply("A_Hit");
if (!MP_Hit)
{
MP_Hit = parent;
}
MP_Down = parent.GetChildTransformDeeply("A_Down");
if (!MP_Down)
{
MP_Down = parent;
}
if (!MP_FollowDown)
{
MP_FollowDown = new GameObject("Follow_Down").transform;
MP_FollowDown.SetParent(Root);
}
}
public static void ForceCrossFade(Animator animator, int name, float transitionDuration, int layer = 0, float normalizedTime = float.NegativeInfinity)
{
animator.Update(0);
if (animator.GetNextAnimatorStateInfo(layer).fullPathHash == 0)
{
animator.CrossFade(name, transitionDuration, layer, normalizedTime);
}
else
{
animator.Play(animator.GetNextAnimatorStateInfo(layer).fullPathHash, layer);
animator.Update(0);
animator.CrossFade(name, transitionDuration, layer, normalizedTime);
}
}
///
/// 矫正服务端坐标至客户端坐标
///
/// 服务端坐标X
/// 服务端坐标Y
public void AdjustPos(ushort sPosX, ushort sPosY, bool chkNavmesh = true)
{
sPosX -= (ushort)GA_Hero.MapOffset.x;
sPosY -= (ushort)GA_Hero.MapOffset.z;
Vector3 _clntPos = new Vector3(sPosX * .5f, 0, sPosY * .5f);
Vector3 _adjustPos = Vector3.zero;
if (!chkNavmesh)
{
_adjustPos = _clntPos;
}
else
{
if (!TryGetValidPos(_clntPos, ref _adjustPos))
{
Debug.LogWarningFormat("对象: {3} : 服务端给定坐标: {0} 映射至客户端坐标: {1} 为客户端无法矫正的障碍点...当前地图: {2}",
new Vector2(sPosX, sPosY), new Vector2(_clntPos.x, _clntPos.z), PlayerDatas.Instance.baseData.MapID, ServerInstID);
return;
}
}
float _groundHeight = Pos.y;
if (!CollisionUtility.TryGetGroundHeight(_adjustPos, out _groundHeight))
{
Debug.LogErrorFormat("对象: {3} : 服务端给定坐标: {0} 映射至客户端坐标: {1} 并且矫正后: {2}客户端无法从此点计算出地板高度...",
new Vector2(sPosX, sPosY), new Vector2(_clntPos.x, _clntPos.y), new Vector2(_adjustPos.x, _adjustPos.z), ServerInstID);
}
_adjustPos.y = _groundHeight;
Pos = _adjustPos;
}
#if UNITY_EDITOR
#region 测试用模块
private static int m_NewCount = 0;
~GActor()
{
m_NewCount -= 1;
}
#endregion
#endif
}