using DragonLi.Core; using DragonLi.Frame; using Mirror; using System; using UnityEngine; using UnityEngine.AI; // IAgent public class Agent : Entity, IDamagable, IRecordable { /// /// Default value of spawnable /// public class AgentDefault : Default { /// /// Animator of this entity /// public const string kAnimatorKey = "animator"; /// /// Speed per second. /// public const float kSpeed = 10f; public const string kSpeedKey = "speed"; /// /// Acc per second. /// public const float kAcc = 30f; public const string kAccKey = "acc"; /// /// Health /// public const float kHealth = 100f; public const string kHealthKey = "health"; /// /// 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 /// 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; /// /// All DamageParts belong to this agent /// protected DragonLiDamagePart[] DamageProxies; private bool updateAniamtorSpeedvalue = false; private bool updateAniamtorSpeedFvalue = false; private bool updateAniamtorSpeedRvalue = false; /// /// Entity type using for world recording /// public string EntityType { get { return Data["entity_type"].StringValue; } set { this.LogEditorOnly("You can't set entity type in runtime."); } } /// /// Health of this entity /// public float Health { get { return health; } set { health = value; health = Mathf.Clamp(health, 0f, Data["health"].FloatValue); OnHeathChanged(health); } } [NonSerialized] public float OriginHealth = 0f; /// /// Is agent alive? /// public bool IsAlive => Health > 0f; /// /// Is agent full health? /// public bool IsHealthy => Health == Data["health"].FloatValue; /// /// Get main camera currently in task system /// /// 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; /// /// NavMesh Agent of this Agent /// public NavMeshAgent NavAgent { get { if (agent == null) { agent = GetComponent(); } return agent; } } /// /// Add damage /// /// How much /// Some information about this damage you want to tell damage receiver /// Who take this damage [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); } } } /// /// Let this entity die, and tell task system. /// public virtual void Die(object info, Transform _sender) { // MonoSingleton.Instance.WaitFrameEnd(delegate // { // World.RemoveEntity(EntityType, this); // }); OnDeath(info, _sender); } /// /// On entity enable, this will be called when entity was being spawned. /// public virtual void OnSpawn() { Health = Data["health"].FloatValue; OriginHealth = Health; ResetDamageProxies(); OnBorn(); } /// /// On spawn event this entity belonged reset, this function will be called. /// public virtual void OnSpawnerReset() { } /// /// On entity die, this will be called, you can write despawn functions here. /// public virtual void OnDeath(object info, Transform _sender) { } /// /// When agent receives damage this function will be called /// If you want to re calculate damage you can do it here. /// /// How much /// Some information about this damage you want to tell damage receiver /// Who take this damage /// protected virtual float OnReceiveDamage(float value, object info, Transform _sender) { return value; } /// /// When health changed this function will be called /// /// current health public virtual void OnHeathChanged(float currentHealth) { } /// /// When this entity has been born /// protected virtual void OnBorn() { } /// /// On task system boradcast message, this function will be called. /// /// Message /// Message sender 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(); base.OnEnable(); } public override void Awake() { InitAnimator(); base.Awake(); } /// /// Update animator value for you. /// /// Velocity of this entity [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); } } } /// /// Init animator /// 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(); 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; } }