Files
taptap2024_GJ_chidouren/Assets/Scripts/Game/Component/EnemyEntity.cs
2024-10-27 19:08:26 +08:00

337 lines
13 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 System;
using Framework.Audio;
using Framework.Timer;
using Framework.Utils.Extend;
using Pathfinding;
using UnityEngine;
using UnityEngine.Serialization;
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;
}
[SerializeField] protected FSMController _fsmController;
[SerializeField] protected AILerp _aiLerp;
public EnemyAnimState AnimState;
[Header ("攻击触发音效")] public string AttackTriggerAudioSound = "";
[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;
private float _expSpeedOffset; //额外速度系数
private TimeHandler _expTimeHandler; //额外速度计时器
private FsmData _fsmData;
private float _curAttackingTime;
private float _curAttackCDTime;
private float _curMoveSpeedOffset;
private TimeHandler _speedTimeHandler;
private bool _hasAtkState; //是否为攻击状态
//出生点
[HideInInspector] public Vector2 CreatePos;
#if UNITY_EDITOR
public bool IsDebugDraw = true;
private void OnDrawGizmos ()
{
this._aiLerp.speed = this.CurMoveSpeed;
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)
{
UnityEditor.Handles.color = new Color (0f, 1f, 0f, 0.35f);
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),
Color.white);
// 在圆顶部绘制文本“活动范围”
UnityEditor.Handles.Label (CreatePos + new Vector2 (0f, ActiveArea.y / 2), "活动范围");
}
if ( this.WalkArea.y != 0 && this.WalkArea.x != 0)
{
UnityEditor.Handles.color = new Color (0f, 0f, 1f, 0.35f);
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),
Color.white);
// 在圆顶部绘制文本“巡逻范围”
UnityEditor.Handles.Label (CreatePos + new Vector2 (0f, WalkArea.y / 2), "巡逻范围");
}
if (TriggerDistance > 0)
{
//绘制一个半径为TriggerDistance的圆形
UnityEditor.Handles.color = new Color (1f, 0f, 0f, 0.35f);
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
{
if (this.ActiveArea.x.Compare (-1) && this.ActiveArea.y.Compare (-1))
{
return true;
}
//特殊情况 ,如果值为-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;
}
//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;
}
return true;
}
//检测当前位置是否在活动范围内, 如果不在活动范围内直接返回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;
}
}
#if UNITY_EDITOR
public bool HasRunaway => MapContent.Instance?.IsRunaway ?? false;
public float CurMoveSpeed => (MapContent.Instance?.MoveGlobalOffset ?? 0) * this._curMoveSpeedOffset * (this.MaxMoveSpeed *
(1 +
( this._expTimeHandler?.IsPlaying ?? false
? (1 - this._expTimeHandler.CurProgress) * this._expSpeedOffset
: 0f)
)
);
#else
public bool HasRunaway => MapContent.Instance?.IsRunaway ?? false;
public float CurMoveSpeed => (MapContent.Instance.MoveGlobalOffset) * this._curMoveSpeedOffset * (this.MaxMoveSpeed *
(1 +
( this._expTimeHandler?.IsPlaying ?? false
? (1 - this._expTimeHandler.CurProgress) * this._expSpeedOffset
: 0f)
)
);
#endif
public void ResetState ()
{
this.transform.position = this.CreatePos;
this.AnimState.SetState (EnemyAnimStateType.Idle);
EndAttack ();
this.UpdateSpeedState (false , false);
_curAttackingTime = 0;
_curAttackCDTime = 0;
this._aiLerp.speed = this.CurMoveSpeed;
}
public void UpdateSpeedState (bool hasAtk , bool anim = true)
{
if (this._hasAtkState == false && hasAtk)
{
AudioManager.Instance.PlaySound (this.AttackTriggerAudioSound);
}
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;
}
}
#region
private void OnDisable ()
{
this._expTimeHandler?.Kill ();
GameUpdateMgr.Instance.RemoveUpdater (DoUpdate);
}
private void OnEnable ()
{
if (!this._fsmController.Initialized)
{
Init ();
}
GameUpdateMgr.Instance.AddUpdater (DoUpdate);
ResetState ();
}
private void DoUpdate ()
{
UpdateSpeedState (this._hasAtkState);
if (_curAttackingTime > 0)
{
this._curAttackingTime -= Time.deltaTime;
if (this._curAttackingTime <= 0)
{
EndAttack ();
}
}
if (this._curAttackCDTime > 0)
{
_curAttackCDTime -= Time.deltaTime;
}
AttackCheck ();
CheckUpdateFsmData ();
this._fsmController.DoUpdate ();
}
private void AttackCheck ()
{
//处于攻击cd时不作攻击检测
if (_curAttackCDTime > 0)
{
return;
}
var hasAttack = false;
if (this._curAttackingTime > 0)
{
//追逐中使用追逐半径检测
hasAttack = this.FollowDistance < 0 ||
Vector2.Distance ( MapContent.Instance.PlayerPosition , this.transform.position) < this.FollowDistance;
}
else
{
hasAttack = this.TriggerDistance < 0 ||
Vector2.Distance ( MapContent.Instance.PlayerPosition , this.transform.position) < this.TriggerDistance;
}
if (hasAttack)
{
this._curAttackingTime = this.AttackStateDuration;
}
}
public void CheckUpdateFsmData (bool isUpdate = false)
{
this._aiLerp.speed = this.CurMoveSpeed;
isUpdate |= _fsmData.HasAttack != this.HasAttack;
isUpdate |= _fsmData.HasSafeArea != this.HasSafeArea;
isUpdate |= _fsmData.HasRunaway != this.HasRunaway;
isUpdate |= _fsmData.HasActive != MapContent.Instance.IsActiveGame;
this._fsmData.HasAttack = HasAttack;
this._fsmData.HasSafeArea = HasSafeArea;
this._fsmData.HasRunaway = HasRunaway;
this._fsmData.HasActive = MapContent.Instance.IsActiveGame;
if (isUpdate)
{
this._fsmController.SetBool ("hasAttack", this._fsmData.HasAttack);
this._fsmController.SetBool ("hasSafeArea", this._fsmData.HasSafeArea);
this._fsmController.SetBool ("hasRunaway", this._fsmData.HasRunaway);
this._fsmController.SetBool ("hasActive", this._fsmData.HasActive);
}
}
#endregion
public void AddSpeedBuff (float duration , float offset)
{
this._expSpeedOffset = offset;
this._expTimeHandler?.Kill ();
this._expTimeHandler = GameUpdateMgr.Instance.CreateTimer (duration , null);
}
public void EndAttack ()
{
this._hasAtkState = false;
this._curAttackingTime = 0;
this._curAttackCDTime = this.AttackCDDuration;
}
private void Init ()
{
this._fsmData = new FsmData ()
{
HasActive = true
};
this.CreatePos = this.transform.position;
this._fsmController.Init (this);
}
}
}