Files
XMen/Assets/Scripts/Agent.cs
2025-07-10 14:49:53 +08:00

401 lines
8.9 KiB
C#

using DragonLi.Core;
using DragonLi.Frame;
using Mirror;
using System;
using UnityEngine;
using UnityEngine.AI;
// IAgent
public class Agent : Entity, IDamagable, IRecordable
{
/// <summary>
/// Default value of spawnable
/// </summary>
public class AgentDefault : Default
{
/// <summary>
/// Animator of this entity
/// </summary>
public const string kAnimatorKey = "animator";
/// <summary>
/// Speed per second.
/// </summary>
public const float kSpeed = 10f;
public const string kSpeedKey = "speed";
/// <summary>
/// Acc per second.
/// </summary>
public const float kAcc = 30f;
public const string kAccKey = "acc";
/// <summary>
/// Health
/// </summary>
public const float kHealth = 100f;
public const string kHealthKey = "health";
/// <summary>
/// These values are key string in animator controller
/// We will calculate these values for you
/// speed: the mag of velocity vector3.
/// speed_f: the mag of velocity projects on transform.forword
/// speed_r: the mag of velocity projects on transform.right
/// </summary>
public const string kAnimatorKeySpeed = "speed";
public const string kAniamtorKeySpeedForword = "speedf";
public const string kAniamtorKeySpeedRight = "speedr";
public static readonly int AnimtorSpeedKeyHash = Animator.StringToHash("speed");
public static readonly int AnimtorSpeedFkeyHash = Animator.StringToHash("speedf");
public static readonly int AnimtorSpeedRkeyHash = Animator.StringToHash("speedr");
}
[NonSerialized]
[SyncVar]
public float health = 0f;
private DragonLiCamera mainCamera;
/// <summary>
/// All DamageParts belong to this agent
/// </summary>
protected DragonLiDamagePart[] DamageProxies;
private bool updateAniamtorSpeedvalue = false;
private bool updateAniamtorSpeedFvalue = false;
private bool updateAniamtorSpeedRvalue = false;
/// <summary>
/// Entity type using for world recording
/// </summary>
public string EntityType
{
get
{
return Data["entity_type"].StringValue;
}
set
{
this.LogEditorOnly("You can't set entity type in runtime.");
}
}
/// <summary>
/// Health of this entity
/// </summary>
public float Health
{
get
{
return health;
}
set
{
health = value;
health = Mathf.Clamp(health, 0f, Data["health"].FloatValue);
OnHeathChanged(health);
}
}
[NonSerialized]
public float OriginHealth = 0f;
/// <summary>
/// Is agent alive?
/// </summary>
public bool IsAlive => Health > 0f;
/// <summary>
/// Is agent full health?
/// </summary>
public bool IsHealthy => Health == Data["health"].FloatValue;
/// <summary>
/// Get main camera currently in task system
/// </summary>
/// <returns></returns>
public DragonLiCamera MainCamera
{
get
{
if (mainCamera == null)
{
mainCamera = GetMainCamera();
}
if (mainCamera == null)
{
this.LogEditorOnly("RainCamera you want to get is null.");
}
return mainCamera;
}
}
private NavMeshAgent agent;
/// <summary>
/// NavMesh Agent of this Agent
/// </summary>
public NavMeshAgent NavAgent
{
get
{
if (agent == null)
{
agent = GetComponent<NavMeshAgent>();
}
return agent;
}
}
/// <summary>
/// Add damage
/// </summary>
/// <param name="value">How much</param>
/// <param name="info">Some information about this damage you want to tell damage receiver</param>
/// <param name="_sender">Who take this damage</param>
[Server]
public virtual void ApplyDamage(float value, object info, Transform _sender)
{
// Debug.Log("造成伤害1" + IsAlive + " " + !Data["partdamage"].BooleanValue + " " + IsProxyDamage(info));
if (IsAlive && (!Data["partdamage"].BooleanValue || IsProxyDamage(info)))
{
Health -= OnReceiveDamage(value, info, _sender);
if (!IsAlive)
{
Die(info, _sender);
}
}
}
/// <summary>
/// Let this entity die, and tell task system.
/// </summary>
public virtual void Die(object info, Transform _sender)
{
// MonoSingleton<CoroutineTaskManager>.Instance.WaitFrameEnd(delegate
// {
// World.RemoveEntity(EntityType, this);
// });
OnDeath(info, _sender);
}
/// <summary>
/// On entity enable, this will be called when entity was being spawned.
/// </summary>
public virtual void OnSpawn()
{
Health = Data["health"].FloatValue;
OriginHealth = Health;
ResetDamageProxies();
OnBorn();
}
/// <summary>
/// On spawn event this entity belonged reset, this function will be called.
/// </summary>
public virtual void OnSpawnerReset()
{
}
/// <summary>
/// On entity die, this will be called, you can write despawn functions here.
/// </summary>
public virtual void OnDeath(object info, Transform _sender)
{
}
/// <summary>
/// When agent receives damage this function will be called
/// If you want to re calculate damage you can do it here.
/// </summary>
/// <param name="value">How much</param>
/// <param name="info">Some information about this damage you want to tell damage receiver</param>
/// <param name="_sender">Who take this damage</param>
/// <returns></returns>
protected virtual float OnReceiveDamage(float value, object info, Transform _sender)
{
return value;
}
/// <summary>
/// When health changed this function will be called
/// </summary>
/// <param name="currentHealth">current health</param>
public virtual void OnHeathChanged(float currentHealth)
{
}
/// <summary>
/// When this entity has been born
/// </summary>
protected virtual void OnBorn()
{
}
/// <summary>
/// On task system boradcast message, this function will be called.
/// </summary>
/// <param name="msg">Message</param>
/// <param name="sender">Message sender</param>
public virtual void OnReceiveBroadcast(string msg, object sender)
{
}
public override void InitData()
{
Data.Add("entity_type", new DataRow(SupportDataType.String)
{
Name = "entity_type"
});
Data.Add("speed", new DataRow(SupportDataType.Float)
{
Name = "speed",
FloatValue = 10f
});
Data.Add("acc", new DataRow(SupportDataType.Float)
{
Name = "acc",
FloatValue = 30f
});
Data.Add("health", new DataRow(SupportDataType.Float)
{
Name = "health",
FloatValue = 100f
});
Data.Add("partdamage", new DataRow(SupportDataType.Boolean)
{
Name = "partdamage",
BooleanValue = false
});
}
internal override void Update()
{
if (IsAlive && updateSelf && DragonLiEntity.ShouldUpdate)
{
if (base.RigidbodyComponent != null)
{
UpdateAniamtorValues(base.RigidbodyComponent.velocity);
}
base.Update();
}
}
public override void OnEnable()
{
DamageProxies = GetComponentsInChildren<DragonLiDamagePart>();
base.OnEnable();
}
public override void Awake()
{
InitAnimator();
base.Awake();
}
/// <summary>
/// Update animator value for you.
/// </summary>
/// <param name="vel">Velocity of this entity</param>
[Server]
protected void UpdateAniamtorValues(Vector3 vel)
{
if (base.AnimatorComponent != null)
{
if (updateAniamtorSpeedvalue)
{
base.AnimatorComponent.SetFloat(AgentDefault.AnimtorSpeedKeyHash, vel.magnitude);
}
Vector3 val;
if (updateAniamtorSpeedFvalue)
{
val = Vector3.Project(vel, transform.forward);
float num = (val.magnitude / (vel.magnitude * (float)((!(Vector3.Angle(vel, transform.forward) > 90f)) ? 1 : (-1))));
base.AnimatorComponent.SetFloat(AgentDefault.AnimtorSpeedFkeyHash, num);
}
if (updateAniamtorSpeedRvalue)
{
val = Vector3.Project(vel, transform.right);
float num2 = (val.magnitude / (vel.magnitude * (float)((!(Vector3.Angle(vel, transform.right) > 90f)) ? 1 : (-1))));
base.AnimatorComponent.SetFloat(AgentDefault.AnimtorSpeedRkeyHash, num2);
}
}
}
/// <summary>
/// Init animator
/// </summary>
private void InitAnimator()
{
if (base.AnimatorComponent == null)
{
return;
}
AnimatorControllerParameter[] parameters = base.AnimatorComponent.parameters;
foreach (AnimatorControllerParameter val in parameters)
{
if ((int)val.type == 1)
{
switch (val.name)
{
case "speed":
updateAniamtorSpeedvalue = true;
break;
case "speedr":
updateAniamtorSpeedRvalue = true;
break;
case "speedf":
updateAniamtorSpeedFvalue = true;
break;
}
}
}
}
private DragonLiCamera GetMainCamera()
{
Transform val = World.GetMainCamera();
if (val == null)
{
this.LogEditorOnly("Failed to get main camera.");
return null;
}
DragonLiCamera component = val.GetComponent<DragonLiCamera>();
if (component == null)
{
this.LogEditorOnly("There is no RainCamera on MainCamera.");
}
return component;
}
private void ResetDamageProxies()
{
if (DamageProxies != null)
{
DragonLiDamagePart[] damageProxies = DamageProxies;
foreach (DragonLiDamagePart dragonLiDamagePart in damageProxies)
{
dragonLiDamagePart.ResetDamagePart();
}
}
}
private bool IsProxyDamage(object info)
{
DragonLiDamagePart dragonLiDamagePart = info as DragonLiDamagePart;
return dragonLiDamagePart == null;
}
}