Files
taptap2024_GJ_chidouren/Assets/Scripts/Game/Component/EnemyEntity.cs

316 lines
12 KiB
C#
Raw Normal View History

2024-10-16 00:03:41 +08:00
using System;
using Framework.Timer;
2024-10-17 00:46:27 +08:00
using Framework.Utils.Extend;
2024-10-16 00:03:41 +08:00
using Pathfinding;
using UnityEngine;
2024-10-17 00:46:27 +08:00
using UnityEngine.Serialization;
2024-10-16 00:03:41 +08:00
using XFFSM;
namespace Game.Component
{
public class EnemyEntity : MonoBehaviour
{
[Serializable]
public class FsmData
{
public bool HasAttack;
public bool HasSafeArea;
public bool HasRunaway;
public bool HasActive = true;
}
2024-10-18 00:23:04 +08:00
[SerializeField] protected FSMController _fsmController;
[SerializeField] protected AILerp _aiLerp;
public EnemyAnimState AnimState;
2024-10-16 00:03:41 +08:00
2024-10-17 00:46:27 +08:00
[Header ("最大活动区域")] public Vector2 ActiveArea = new Vector2 (10 , 5);
[Header ("随机巡逻区域")] public Vector2 WalkArea = new Vector2 (5 , 5);
[Header ("攻击检测半径")] public float TriggerDistance = -1f;
[Header ("追逐检测半径")] public float FollowDistance = -1f;
[Header ("攻击最小持续时间")] public float AttackStateDuration = 5f; //攻击状态最小持续时间
[Header ("仇恨丢失冷却时间")] public float AttackCDDuration = 2f;
[Header ("单位移动速度")] public float MaxMoveSpeed = 3;
[Header ("常规移动速度系数"), Range (0, 1)] public float WalkSpeedOffset = 1;
[Header ("攻击移动速度系数"), Range (0, 1)] public float AttackSpeedOffset = 1;
[Header ("速度变化系数&插值t")] public float SpeedChangeT = 0.5f;
2024-10-19 03:04:15 +08:00
private float _expSpeedOffset; //额外速度系数
private TimeHandler _expTimeHandler; //额外速度计时器
2024-10-17 00:46:27 +08:00
private FsmData _fsmData;
private float _curAttackingTime;
private float _curAttackCDTime;
private float _curMoveSpeedOffset;
private TimeHandler _speedTimeHandler;
private bool _hasAtkState; //是否为攻击状态
2024-10-16 00:03:41 +08:00
//出生点
[HideInInspector] public Vector2 CreatePos;
#if UNITY_EDITOR
public bool IsDebugDraw = true;
private void OnDrawGizmos ()
{
2024-10-17 00:46:27 +08:00
this._aiLerp.speed = this.CurMoveSpeed;
2024-10-16 00:03:41 +08:00
if (!IsDebugDraw)
{
return;
}
var enemyTransform = this.transform.position;
//基于CreatePos为中心点绘制一个矩形,宽高为ActiveArea 用于表示此单位的活动区域
if (!UnityEditor.EditorApplication.isPlaying)
{
this.CreatePos = enemyTransform;
}
if (this.ActiveArea.y != 0 && this.ActiveArea.x != 0)
{
2024-10-17 00:46:27 +08:00
UnityEditor.Handles.color = new Color (0f, 1f, 0f, 0.35f);
2024-10-16 00:03:41 +08:00
UnityEditor.Handles.DrawSolidRectangleWithOutline (
new Rect (CreatePos.x - ActiveArea.x / 2, CreatePos.y - ActiveArea.y / 2, ActiveArea.x, ActiveArea.y),
new Color (0f, 1f, 0f, 0.25f),
2024-10-17 00:46:27 +08:00
Color.white);
2024-10-16 00:03:41 +08:00
// 在圆顶部绘制文本“活动范围”
UnityEditor.Handles.Label (CreatePos + new Vector2 (0f, ActiveArea.y / 2), "活动范围");
}
if ( this.WalkArea.y != 0 && this.WalkArea.x != 0)
{
2024-10-17 00:46:27 +08:00
UnityEditor.Handles.color = new Color (0f, 0f, 1f, 0.35f);
2024-10-16 00:03:41 +08:00
UnityEditor.Handles.DrawSolidRectangleWithOutline (
new Rect (CreatePos.x - this.WalkArea.x / 2, CreatePos.y - WalkArea.y / 2, WalkArea.x, WalkArea.y), new Color (0f, 0f, 1f, 0.25f),
2024-10-17 00:46:27 +08:00
Color.white);
2024-10-16 00:03:41 +08:00
// 在圆顶部绘制文本“巡逻范围”
UnityEditor.Handles.Label (CreatePos + new Vector2 (0f, WalkArea.y / 2), "巡逻范围");
}
if (TriggerDistance > 0)
{
//绘制一个半径为TriggerDistance的圆形
2024-10-17 00:46:27 +08:00
UnityEditor.Handles.color = new Color (1f, 0f, 0f, 0.35f);
2024-10-16 00:03:41 +08:00
UnityEditor.Handles.DrawSolidDisc (enemyTransform, Vector3.back, TriggerDistance);
//在圆顶部绘制文本“攻击范围”
UnityEditor.Handles.Label (enemyTransform + new Vector3 (0f, TriggerDistance, 0f), "攻击范围");
}
if (this.FollowDistance > 0 && this._curAttackingTime > 0)
{
//绘制一个半径为FollowDistance的圆形
UnityEditor.Handles.color = new Color (0.62f, 0f, 1f, 0.25f);
UnityEditor.Handles.DrawSolidDisc (enemyTransform, Vector3.back, FollowDistance);
//在圆顶部绘制文本“追逐范围”
UnityEditor.Handles.Label (enemyTransform + new Vector3 (0f, FollowDistance, 0f), "追逐范围");
}
if (UnityEditor.EditorApplication.isPlaying && this._fsmController.Initialized)
{
var currentStateInfo = this._fsmController.GetCurrentStateInfo (0);
//绘制文本
var text = "行动状态: " + currentStateInfo.data.DisplayName;
UnityEditor.Handles.Label (enemyTransform, text);
}
}
#endif
public AILerp AiLerp => this._aiLerp;
public bool HasAttack => this._curAttackingTime > 0;
public bool HasSafeArea
{
get
{
2024-10-17 00:46:27 +08:00
if (this.ActiveArea.x.Compare (-1) && this.ActiveArea.y.Compare (-1))
{
return true;
}
2024-10-19 03:04:15 +08:00
2024-10-17 00:46:27 +08:00
//特殊情况 ,如果值为-1 ,表示不限制
//x如果为-1
if (this.ActiveArea.x.Compare (-1))
{
if (transform.position.y < this.CreatePos.y - this.ActiveArea.y / 2 ||
transform.position.y > this.CreatePos.y + this.ActiveArea.y / 2)
{
return false;
}
return true;
}
2024-10-19 03:04:15 +08:00
2024-10-17 00:46:27 +08:00
//y如果为-1
if (this.ActiveArea.y.Compare (-1))
{
if (transform.position.x < this.CreatePos.x - this.ActiveArea.x / 2 ||
transform.position.x > this.CreatePos.x + this.ActiveArea.x / 2)
{
return false;
}
2024-10-19 03:04:15 +08:00
2024-10-17 00:46:27 +08:00
return true;
}
2024-10-16 00:03:41 +08:00
//检测当前位置是否在活动范围内, 如果不在活动范围内直接返回false
if (transform.position.x < this.CreatePos.x - this.ActiveArea.x / 2 ||
transform.position.x > this.CreatePos.x + this.ActiveArea.x / 2 ||
transform.position.y < this.CreatePos.y - this.ActiveArea.y / 2 ||
transform.position.y > this.CreatePos.y + this.ActiveArea.y / 2)
{
return false;
}
return true;
}
}
public bool HasRunaway { get; private set; } = false;
2024-10-19 03:04:15 +08:00
public float CurMoveSpeed => this._curMoveSpeedOffset * (this.MaxMoveSpeed *
(1 +
( this._expTimeHandler?.IsPlaying ?? false
? (1 - this._expTimeHandler.CurProgress) * this._expSpeedOffset
: 0f)
)
);
2024-10-17 00:46:27 +08:00
2024-10-21 17:02:25 +08:00
public void ResetState ()
2024-10-16 00:03:41 +08:00
{
2024-10-18 00:23:04 +08:00
this.AnimState.SetState (EnemyAnimStateType.Idle);
2024-10-17 00:46:27 +08:00
this.UpdateSpeedState (false , false);
2024-10-16 00:03:41 +08:00
_curAttackingTime = 0;
_curAttackCDTime = 0;
2024-10-17 00:46:27 +08:00
this._aiLerp.speed = this.CurMoveSpeed;
}
public void UpdateSpeedState (bool hasAtk , bool anim = true)
{
this._hasAtkState = hasAtk;
var targetSpeedOffset = this._hasAtkState ? this.AttackSpeedOffset : this.WalkSpeedOffset;
if (anim)
{
this._curMoveSpeedOffset = Mathf.Lerp (this._curMoveSpeedOffset , targetSpeedOffset , this.SpeedChangeT);
}
else
{
this._curMoveSpeedOffset = targetSpeedOffset;
}
2024-10-16 00:03:41 +08:00
}
2024-10-17 00:46:27 +08:00
#region
2024-10-16 00:03:41 +08:00
private void OnDisable ()
{
2024-10-19 03:04:15 +08:00
this._expTimeHandler?.Kill ();
2024-10-16 00:03:41 +08:00
GameUpdateMgr.Instance.RemoveUpdater (DoUpdate);
}
private void OnEnable ()
{
if (!this._fsmController.Initialized)
{
Init ();
}
GameUpdateMgr.Instance.AddUpdater (DoUpdate);
ResetState ();
}
private void DoUpdate ()
{
2024-10-17 00:46:27 +08:00
UpdateSpeedState (this._hasAtkState);
2024-10-16 00:03:41 +08:00
if (_curAttackingTime > 0)
{
this._curAttackingTime -= Time.deltaTime;
if (this._curAttackingTime <= 0)
{
EndAttack ();
}
}
if (this._curAttackCDTime > 0)
{
_curAttackCDTime -= Time.deltaTime;
}
AttackCheck ();
CheckUpdateFsmData ();
}
private void AttackCheck ()
{
//处于攻击cd时不作攻击检测
if (_curAttackCDTime > 0)
{
return;
}
var hasAttack = false;
if (this._curAttackingTime > 0)
{
//追逐中使用追逐半径检测
2024-10-17 00:46:27 +08:00
hasAttack = this.FollowDistance < 0 ||
2024-10-16 00:03:41 +08:00
Vector2.Distance ( MapContent.Instance.PlayerPosition , this.transform.position) < this.FollowDistance;
}
else
{
hasAttack = this.TriggerDistance < 0 ||
2024-10-17 00:46:27 +08:00
Vector2.Distance ( MapContent.Instance.PlayerPosition , this.transform.position) < this.TriggerDistance;
2024-10-16 00:03:41 +08:00
}
if (hasAttack)
{
this._curAttackingTime = this.AttackStateDuration;
}
}
public void CheckUpdateFsmData (bool isUpdate = false)
{
isUpdate |= _fsmData.HasAttack != this.HasAttack;
isUpdate |= _fsmData.HasSafeArea != this.HasSafeArea;
isUpdate |= _fsmData.HasRunaway != this.HasRunaway;
2024-10-21 17:02:25 +08:00
isUpdate |= _fsmData.HasActive != MapContent.Instance.IsActiveGame;
2024-10-16 00:03:41 +08:00
this._fsmData.HasAttack = HasAttack;
this._fsmData.HasSafeArea = HasSafeArea;
this._fsmData.HasRunaway = HasRunaway;
2024-10-21 17:02:25 +08:00
this._fsmData.HasActive = MapContent.Instance.IsActiveGame;
2024-10-16 00:03:41 +08:00
if (isUpdate)
{
this._fsmController.SetBool ("hasAttack", this._fsmData.HasAttack);
this._fsmController.SetBool ("hasSafeArea", this._fsmData.HasSafeArea);
this._fsmController.SetBool ("hasRunaway", this._fsmData.HasRunaway);
2024-10-21 17:02:25 +08:00
this._fsmController.SetBool ("hasActive", this._fsmData.HasActive);
2024-10-16 00:03:41 +08:00
}
}
2024-10-17 00:46:27 +08:00
#endregion
2024-10-19 03:04:15 +08:00
public void AddSpeedBuff (float duration , float offset)
{
this._expSpeedOffset = offset;
this._expTimeHandler?.Kill ();
this._expTimeHandler = GameUpdateMgr.Instance.CreateTimer (duration , null);
}
2024-10-17 00:46:27 +08:00
public void EndAttack ()
{
this._hasAtkState = false;
this._curAttackingTime = 0;
this._curAttackCDTime = this.AttackCDDuration;
}
2024-10-16 00:03:41 +08:00
private void Init ()
{
this._fsmData = new FsmData ()
{
HasActive = true
};
this.CreatePos = this.transform.position;
this._fsmController.Init (this);
}
}
}