| | |
| | | using System; |
| | | using System.Collections; |
| | | using System.ComponentModel; |
| | | using ActionGameFramework.Health; |
| | | using Core.Health; |
| | | using Core.Utilities; |
| | | using DG.Tweening; |
| | | using KTGMGemClient; |
| | | using TMPro.Examples; |
| | | using TowerDefense.Affectors; |
| | | using TowerDefense.Agents.Data; |
| | | using TowerDefense.Economy; |
| | | using TowerDefense.Level; |
| | | using TowerDefense.Nodes; |
| | | using TowerDefense.UI.HUD; |
| | | using UnityEngine; |
| | | using UnityEngine.AI; |
| | | |
| | |
| | | /// An agent will follow a path of nodes |
| | | /// NavMeshAgent和AttackAffector是必须得加入的EntityNode. |
| | | /// </summary> |
| | | [RequireComponent(typeof(NavMeshAgent)), RequireComponent(typeof(AttackAffector))] |
| | | [RequireComponent(typeof(NavMeshAgent))] |
| | | public abstract class Agent : Targetable |
| | | { |
| | | /// <summary> |
| | |
| | | public ParticleSystem spawnParticle; |
| | | |
| | | public AgentSetData mAgentData; |
| | | |
| | | |
| | | |
| | | //public Textur |
| | | |
| | | |
| | | /// <summary> |
| | | /// The NavMeshAgent component attached to this |
| | |
| | | /// <summary> |
| | | /// 动画器. |
| | | /// </summary> |
| | | protected Animator mAnim; |
| | | public Animator ActionAnimator; |
| | | |
| | | protected AnimationClip[] clips; |
| | | |
| | | protected bool bInDeathAct = false; |
| | | |
| | | /// <summary> |
| | | /// 原地罚站 |
| | | /// </summary> |
| | | /// <param name="can"></param> |
| | | public bool CanMove { get; set; } = true; |
| | | |
| | | /// <summary> |
| | | /// 分别对应三种不同的纹理. |
| | | /// </summary> |
| | | public Texture poisonTex; |
| | | |
| | | public Texture frozenTex; |
| | | |
| | | public Texture commonTex; |
| | | |
| | | /// <summary> |
| | | /// 速度降低值. |
| | | /// </summary> |
| | | protected float speedSlowRate = 0.0f; |
| | | |
| | | // 中毒相关的数据 |
| | | protected int poisonTimes = 0; |
| | | protected float poisonHurt = 0.0f; |
| | | protected int poisonAttid = 0; |
| | | protected float timeToPoisonHurt = 0.0f; |
| | | |
| | | /// <summary> |
| | | /// 是否处于 中毒状态 |
| | | /// </summary> |
| | | protected bool isPoison; |
| | | |
| | | /// <summary> |
| | | /// 是否处于减速状态 |
| | | /// </summary> |
| | | protected bool isSlowDown; |
| | | |
| | | private bool isFrost; |
| | | |
| | | /// <summary> |
| | | /// 是否处于冰冻状态 |
| | | /// </summary> |
| | | /// <value></value> |
| | | public bool IsFrost |
| | | { |
| | | get { return isFrost; } |
| | | set |
| | | { |
| | | if (!isFrost) |
| | | { |
| | | if (value) |
| | | { |
| | | EndlessGameUI.instance.FloatFrostWord(transform.position); |
| | | PlaySlowDownEffect(); |
| | | CanMove = false; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (!value) |
| | | { |
| | | StopSlowDownEffect(); |
| | | CanMove = true; |
| | | } |
| | | } |
| | | |
| | | isFrost = value; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 冰冻剩余时间,< 0时解除冰冻,冰冻期间不会被再次冰冻 |
| | | /// </summary> |
| | | public float FrostRemainTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 中毒粒子特效 |
| | | /// </summary> |
| | | public ParticleSystem PoisonParticle; |
| | | |
| | | /// <summary> |
| | | /// 中毒结束播放的粒子特效 |
| | | /// </summary> |
| | | public ParticleSystem PoisonEndParticle; |
| | | |
| | | /// <summary> |
| | | /// 减速粒子特效 |
| | | /// </summary> |
| | | public ParticleSystem SlowDownParticle; |
| | | |
| | | /// <summary> |
| | | /// 被火技能攻击特效 |
| | | /// </summary> |
| | | public ParticleSystem FireSkillParticle; |
| | | |
| | | /// <summary> |
| | | /// 降低移动速度. |
| | | /// </summary> |
| | | /// <param name="rate"></param> |
| | | public void addSpeedSlowRate(float rate) |
| | | { |
| | | speedSlowRate += rate; |
| | | if (speedSlowRate >= 0.5f) |
| | | speedSlowRate = 0.5f; |
| | | } |
| | | |
| | | private bool _HasSlowDownText; |
| | | public bool HasSlowDownText |
| | | { |
| | | set |
| | | { |
| | | _HasSlowDownText = value; |
| | | } |
| | | get |
| | | { |
| | | return _HasSlowDownText; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 怪物中毒. |
| | | /// </summary> |
| | | /// <param name="damage"></param> |
| | | public void poisonAgent(float damage, int attid) |
| | | { |
| | | if (poisonTimes >= 1) return; |
| | | |
| | | if (!isPoison) |
| | | { |
| | | isPoison = true; |
| | | |
| | | if (PoisonParticle != null) |
| | | PoisonParticle.Play(); |
| | | } |
| | | |
| | | poisonTimes++; |
| | | poisonAttid = attid; |
| | | poisonHurt = (float)Math.Floor(configuration.maxHealth / 20.0f); |
| | | timeToPoisonHurt = 1.0f; |
| | | } |
| | | |
| | | public bool bInPoison { get { return poisonHurt > 0; } } |
| | | |
| | | /// <summary> |
| | | /// 处理中毒相关的数据 |
| | | /// </summary> |
| | | /// <param name="time"></param> |
| | | protected void updatePoison(float time) |
| | | { |
| | | timeToPoisonHurt -= time; |
| | | if (timeToPoisonHurt <= 0) |
| | | { |
| | | Vector3 backPos = transform.position; |
| | | TakeDamage(poisonHurt, transform.position, null, poisonAttid); |
| | | // if ((poisonHurt > 0) && (!opponentAgent)) |
| | | // { |
| | | // if (GameUI.instanceExists) |
| | | // GameUI.instance.generateBloodText(backPos, poisonHurt, false, true); |
| | | // else if (EndlessGameUI.instanceExists) |
| | | // EndlessGameUI.instance.generateBloodText(backPos, poisonHurt, false, true); |
| | | // } |
| | | |
| | | if (poisonHurt > 0) |
| | | timeToPoisonHurt = 1.0f; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Gets the attached nav mesh agent velocity |
| | |
| | | |
| | | public bool bInDeathState |
| | | { |
| | | get { return this.bInDeathAct; } |
| | | get { return bInDeathAct; } |
| | | set { bInDeathAct = value; } |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | |
| | | public NavMeshAgent navMeshAgent |
| | | { |
| | | get { return this.m_NavMeshAgent; } |
| | | get { return m_NavMeshAgent; } |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 是否显示目标位置信息 |
| | | /// </summary> |
| | | public bool bShowDebugNode = false; |
| | | |
| | | |
| | | /// <summary> |
| | | /// 持续寻路,起到寻路成功 |
| | | /// </summary> |
| | | protected bool nodeMoveUpdate = false; |
| | | |
| | | /// <summary> |
| | | /// 代理的类型 |
| | | /// </summary> |
| | | public SpawnAgentType AgentType { get; set; } = SpawnAgentType.Normal; |
| | | |
| | | |
| | | /// <summary> |
| | | /// 无尽模式小怪对应 endless_enemy表中数据 |
| | | /// </summary> |
| | | public endless_enemy EnemyData { get; set; } |
| | | |
| | | /// <summary> |
| | | /// Accessor to <see cref="m_NavMeshAgent"/> |
| | |
| | | |
| | | public float distanceToDest |
| | | { |
| | | get { return this.m_DisToDestination; } |
| | | get { return m_DisToDestination; } |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | public float originalMovementSpeed { get; protected set; } |
| | | |
| | | /// <summary> |
| | | /// 小怪的动作状态 |
| | | /// </summary> |
| | | public AgentActionState ActionState { get; protected set; } |
| | | |
| | | private string paramName = "AgentActionState"; |
| | | |
| | | /// <summary> |
| | | /// 外部赋值,唯一标识一个代理 |
| | | /// </summary> |
| | | public int Id { get; set; } |
| | | |
| | | private Tween repelTween; |
| | | |
| | | /// <summary> |
| | | /// 击退距离 |
| | | /// </summary> |
| | | protected float repelDistance { get; set; } = 7f; |
| | | |
| | | /// <summary> |
| | | /// 击退时间间隔 |
| | | /// </summary> |
| | | protected float repelTime { get; set; } = 0.5f; |
| | | |
| | | /// <summary> |
| | | /// 是否受到木属性强化子弹攻击 |
| | | /// </summary> |
| | | public bool IsEnhancedBulletAttack { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 木属性精灵瞄准小怪特效 |
| | | /// </summary> |
| | | public ParticleSystem WoodAimEffect; |
| | | |
| | | /// <summary> |
| | | /// 有几个木属性精灵瞄准了Agent |
| | | /// </summary> |
| | | public int WoodAimCount { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 血条的引用 |
| | | /// </summary> |
| | | public AgentBlood BloodBar { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 更新怪物的移动速度。 |
| | |
| | | /// <param name="coinDrop"></param> 设置当前小怪的金币掉落数据 |
| | | public void SetAgentData(float health, float moveSpeed = -1, int coinDrop = 0) |
| | | { |
| | | this.configuration.maxHealth = health; |
| | | this.configuration.startingHealth = health; |
| | | this.configuration.Init(); |
| | | this.configuration.SetHealth(health); |
| | | SpawnBlood(); |
| | | BloodBar.SetCurrentBlood(1f, false); |
| | | configuration.maxHealth = health; |
| | | configuration.startingHealth = health; |
| | | configuration.SetMaxHealth(health); |
| | | configuration.Init(); |
| | | configuration.SetHealth(health); |
| | | |
| | | // 只有在速度大于零的情况下才会设置. |
| | | if (moveSpeed > 0) |
| | | fMoveSpeed = moveSpeed; |
| | | |
| | | // 金币掉落大于零. |
| | | if (coinDrop > 0) |
| | | mLootDrop.lootDropped = coinDrop; |
| | | mLootDrop.lootDropped = coinDrop; |
| | | |
| | | mAgentData.speed = fMoveSpeed; |
| | | mAgentData.hp = this.configuration.maxHealth; |
| | | mAgentData.hp = configuration.maxHealth; |
| | | |
| | | // |
| | | mStartYVal = this.transform.position.y; |
| | | mStartZVal = this.transform.position.z; |
| | | |
| | | // 确保设置成默认白色纹理: |
| | | this.SetTargetableMatColor(Color.white, true); |
| | | mStartYVal = transform.position.y; |
| | | mStartZVal = transform.position.z; |
| | | |
| | | speedSlowRate = 0.0f; |
| | | poisonHurt = 0; |
| | | poisonAttid = 0; |
| | | poisonTimes = 0; |
| | | timeToPoisonHurt = 0; |
| | | bShieldBreak = false; |
| | | CanMove = true; |
| | | } |
| | | |
| | | /*// 如果对应的粒子不为空,则播放 |
| | | if( spawnParticle) |
| | | /// <summary> |
| | | /// 生成血条 |
| | | /// </summary> |
| | | /// <param name="agent"></param> |
| | | private void SpawnBlood() |
| | | { |
| | | if (BloodBar == null) |
| | | { |
| | | ParticleSystem tpar = Instantiate<ParticleSystem>(spawnParticle); |
| | | tpar.transform.localScale = new Vector3(1.5f, 1.5f, 1.5f); |
| | | tpar.transform.position = this.transform.position; |
| | | tpar.Simulate(0.0f); |
| | | tpar.Play(); |
| | | }*/ |
| | | // if (healthBar) |
| | | // healthBar.bOpponent = opponentAgent; |
| | | GameObject prefab = Resources.Load<GameObject>("Prefabs/AgentBlood"); |
| | | GameObject obj = Instantiate(prefab); |
| | | BloodBar = obj.GetComponent<AgentBlood>(); |
| | | GameObject bloodUI = GameObject.Find("MainUI/BloodUI"); |
| | | obj.transform.SetParent(bloodUI.transform, false); |
| | | AgentBlood agentBlood = obj.GetComponent<AgentBlood>(); |
| | | agentBlood.Target = this; |
| | | |
| | | configuration.died += agentBlood.OnDied; |
| | | configuration.healthChanged += agentBlood.OnHealthChanged; |
| | | } |
| | | BloodBar.Hide(); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | // 需要设置移动的目标Node. |
| | | m_NextNode = m_CurrentNode.GetNextNode(); |
| | | |
| | | |
| | | this.MoveToNode(); |
| | | MoveToNode(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 处理Agent的锁定Buf,播放特效,设置速度为零,并时间到达后重设数据。 |
| | | /// </summary> |
| | | /// <param name="binfo"></param> |
| | | protected void SetAgentStopBuff(buffinfo binfo) |
| | | protected virtual void SetAgentStopBuff(buffinfo binfo) |
| | | { |
| | | MoveStopTime = binfo.last / 1000; |
| | | |
| | | if (WaveLineSelMgr.instanceExists) |
| | | { |
| | | // 播放特效: |
| | | if (WaveLineSelMgr.instance.bufStopMovePrefab == null) return; |
| | | |
| | | // 正在播放的话,直接返回. |
| | | if (MoveStopEffect) |
| | | return; |
| | | |
| | | MoveStopEffect = Instantiate(WaveLineSelMgr.instance.bufStopMovePrefab); |
| | | MoveStopEffect.transform.position = this.position; |
| | | MoveStopEffect.Play(); |
| | | } |
| | | else if (EndlessWaveLineManager.instanceExists) |
| | | { |
| | | // 播放特效: |
| | | if (EndlessWaveLineManager.instance.bufStopMovePrefab == null) return; |
| | | |
| | | // 正在播放的话,直接返回. |
| | | if (MoveStopEffect) |
| | | return; |
| | | |
| | | MoveStopEffect = Instantiate(EndlessWaveLineManager.instance.bufStopMovePrefab); |
| | | MoveStopEffect.transform.position = this.position; |
| | | MoveStopEffect.Play(); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | return true; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Agent被击退 |
| | | /// </summary> |
| | | public void AgentBeRepelled() |
| | | { |
| | | CanMove = false; |
| | | |
| | | if (repelTween != null) |
| | | repelTween.Kill(); |
| | | |
| | | Node StartingNodeList = EndlessLevelManager.instance.StartingNodeList[waveLineID]; |
| | | repelTween = transform.DOMoveZ(Mathf.Min(StartingNodeList.transform.position.z, transform.position.z + repelDistance), repelTime); |
| | | repelTween.onComplete = RepelCompleted; |
| | | } |
| | | |
| | | private void RepelCompleted() |
| | | { |
| | | CanMove = true; |
| | | repelTween = null; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 播放木属性瞄准特效 |
| | | /// </summary> |
| | | public void PlayWoodAimEffect() |
| | | { |
| | | if (WoodAimEffect == null) return; |
| | | |
| | | WoodAimEffect.Play(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 停止木属性瞄准特效 |
| | | /// </summary> |
| | | public void StopWoodAimEffect() |
| | | { |
| | | if (WoodAimEffect == null) return; |
| | | |
| | | WoodAimEffect.Stop(); |
| | | WoodAimEffect.Clear(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Stops the navMeshAgent and attempts to return to pool |
| | | /// </summary> |
| | | public override void Remove() |
| | | { |
| | | GameObject prefab = Resources.Load<GameObject>("Prefabs/Endless/AgentDeathEffect"); |
| | | if (prefab != null) |
| | | { |
| | | GameObject obj = Poolable.TryGetPoolable(prefab); |
| | | obj.transform.position = transform.position; |
| | | ParticleSystem ps = obj.transform.GetChild(0).GetComponent<ParticleSystem>(); |
| | | ps?.Play(); |
| | | } |
| | | |
| | | if (BloodBar) |
| | | Destroy(BloodBar.gameObject); |
| | | // 统一管理器内删除当前的Agent: |
| | | AgentInsManager.instance.removeAgent(this); |
| | | |
| | | if (EnemyData != null) |
| | | EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.EndlessAgentDead, EnemyData.point); |
| | | base.Remove(); |
| | | |
| | | if (m_LevelManager) m_LevelManager.DecrementNumberOfEnemies(); |
| | |
| | | m_NavMeshAgent.enabled = false; |
| | | |
| | | // 必须要重置数据,不然会有一系列的小Bug. |
| | | this.m_CurrentNode = null; |
| | | m_CurrentNode = null; |
| | | m_NextNode = null; |
| | | |
| | | this.liveID = this.liveID + 1; |
| | | liveID = liveID + 1; |
| | | |
| | | speedSlowRate = 0.0f; |
| | | poisonHurt = 0; |
| | | poisonAttid = 0; |
| | | poisonTimes = 0; |
| | | timeToPoisonHurt = 0; |
| | | bShieldBreak = false; |
| | | IsFrost = false; |
| | | bInDeathAct = false; |
| | | //this.SetTargetableMatColor(Color.white); |
| | | ChangeState(AgentActionState.Move); |
| | | configuration.ClearShieldWall(); |
| | | |
| | | if (WoodAimCount > 0) |
| | | WoodAimCount = 0; |
| | | StopWoodAimEffect(); |
| | | //SetTargetableMatColor(Color.white); |
| | | |
| | | // 删除当前停止特效和状态. |
| | | if (MoveStopTime > 0) |
| | | { |
| | | if (MoveStopEffect) |
| | | { |
| | | MoveStopEffect.Stop(); |
| | | Destroy(MoveStopEffect); |
| | | MoveStopEffect = null; |
| | | } |
| | | |
| | | MoveStopTime = 0.0f; |
| | | |
| | | if (repelTween != null) |
| | | { |
| | | repelTween.Kill(); |
| | | repelTween = null; |
| | | } |
| | | |
| | | |
| | | // 停止DoTween动画. |
| | | this.transform.DOKill(); |
| | | |
| | | Poolable.TryPool(gameObject); |
| | | transform.DOKill(); |
| | | Destroy(gameObject); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | public virtual void Initialize() |
| | | { |
| | | Id = GameUtils.GetId(); |
| | | ResetPositionData(); |
| | | LazyLoad(); |
| | | configuration.SetHealth(configuration.maxHealth); |
| | |
| | | |
| | | // |
| | | // 设置一个DOTween队列,让场景内刷出来的Agent有一个变大淡出的效果,此时是无敌效果加持. |
| | | this.configuration.bInvincible = true; |
| | | mDefaultScale = this.transform.localScale; |
| | | configuration.bInvincible = true; |
| | | mDefaultScale = transform.localScale; |
| | | Sequence agentTweenSeq = DOTween.Sequence(); |
| | | var ss = mDefaultScale * 0.3f; |
| | | this.transform.localScale = this.transform.localScale * 0.3f; |
| | | Tweener agScale = this.transform.DOScale(mDefaultScale, 0.3f); |
| | | transform.localScale = transform.localScale * 0.3f; |
| | | Tweener agScale = transform.DOScale(mDefaultScale, 0.3f); |
| | | agentTweenSeq.Append(agScale); |
| | | agentTweenSeq.AppendCallback(beDamageStart); |
| | | |
| | | this.nodeMoveUpdate = false; |
| | | nodeMoveUpdate = false; |
| | | |
| | | // 获取移动速度 |
| | | fMoveSpeed = this.m_NavMeshAgent.speed / 2.0f; |
| | | fMoveSpeed = m_NavMeshAgent.speed / 2.0f; |
| | | _HasSlowDownText = false; |
| | | } |
| | | |
| | | protected void beDamageStart() |
| | | { |
| | | this.configuration.bInvincible = false; |
| | | configuration.bInvincible = false; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | public void ResetAgentToInitialPos() |
| | | { |
| | | if (!this.initNode) return; |
| | | if (!initNode) return; |
| | | |
| | | Vector3 initPos = this.initNode.GetRandomPointInNodeArea(); |
| | | Vector3 initPos = initNode.GetRandomPointInNodeArea(); |
| | | transform.position = initPos; |
| | | ResetPositionData(); |
| | | |
| | | this.SetNode(initNode, -1); |
| | | SetNode(initNode, -1); |
| | | |
| | | // 更新AgentMgr,确保不再攻击回到原点的Agent. |
| | | AgentInsManager.instance.updateInsMgrPos(this.opponentAgent); |
| | | AgentInsManager.instance.updateInsMgrPos(opponentAgent); |
| | | |
| | | } |
| | | |
| | |
| | | if (configuration.bInvincible) return; |
| | | |
| | | // 只有处于非PosEffect状态才可以有这个状态. |
| | | var posResetEff = this.GetComponent<AgentResetPosEffect>(); |
| | | var posResetEff = GetComponent<AgentResetPosEffect>(); |
| | | if (posResetEff == null) |
| | | { |
| | | posResetEff = this.gameObject.AddComponent<AgentResetPosEffect>(); |
| | | posResetEff = gameObject.AddComponent<AgentResetPosEffect>(); |
| | | |
| | | // 初始化当前的PosResetEffect |
| | | posResetEff.Initialize(3, AgentInsManager.instance.posResetFx); |
| | |
| | | if (!m_CurrentNode) return; |
| | | Node nextNode = m_CurrentNode.GetNextNode(); |
| | | if (!nextNode) return; |
| | | |
| | | /* if (m_CurrentNode.transform.position.z > nextNode.transform.position.z) |
| | | this.m_PositiveZ = false; |
| | | else |
| | | this.m_PositiveZ = true; |
| | | m_ZMaxValue = nextNode.transform.position.z; |
| | | |
| | | Node thirdNode = nextNode.GetNextNode(); |
| | | if (!thirdNode) return; |
| | | if (thirdNode.transform.position.x > nextNode.transform.position.x) |
| | | this.m_PositiveX = true; |
| | | else |
| | | { |
| | | this.m_PositiveX = false; |
| | | } |
| | | m_XMaxValue = thirdNode.transform.position.x;*/ |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | protected override void Awake() |
| | | { |
| | | //Debug.Log("哪里生成的?"); |
| | | base.Awake(); |
| | | LazyLoad(); |
| | | m_NavMeshAgent.enabled = false; |
| | | MoveStopTime = 0.0f; |
| | | } |
| | | |
| | | private void PlaySlowDownEffect() |
| | | { |
| | | if (SlowDownParticle != null) |
| | | SlowDownParticle.Play(); |
| | | } |
| | | |
| | | private void StopSlowDownEffect() |
| | | { |
| | | if (SlowDownParticle != null && !isSlowDown && !IsFrost) |
| | | { |
| | | SlowDownParticle.Stop(); |
| | | SlowDownParticle.Clear(); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// <param name="deltaTime"></param> |
| | | protected void updateAgentPos(float deltaTime) |
| | | { |
| | | if ((!m_CurrentNode) || (!m_NextNode)) |
| | | return; |
| | | |
| | | // 是否处于停止状态. |
| | | if (MoveStopTime > 0) |
| | | { |
| | | MoveStopTime -= Time.deltaTime; |
| | | if (MoveStopTime <= 0) |
| | | { |
| | | if (MoveStopEffect) |
| | | { |
| | | MoveStopEffect.Stop(); |
| | | Destroy(MoveStopEffect); |
| | | MoveStopEffect = null; |
| | | } |
| | | MoveStopTime = 0; |
| | | } |
| | | else |
| | | return; |
| | | } |
| | | |
| | | if (this.fMoveSpeed == 0) |
| | | { |
| | | Debug.Log("当前的移动为零:" + fMoveSpeed); |
| | | return; |
| | | } |
| | | if (!m_CurrentNode || !m_NextNode || fMoveSpeed <= 0.0001f) return; |
| | | |
| | | float finalSpeed = fMoveSpeed * (1 - speedSlowRate); |
| | | |
| | | if (speedSlowRate > 0 && !isSlowDown) |
| | | { |
| | | isSlowDown = true; |
| | | PlaySlowDownEffect(); |
| | | } |
| | | else if (speedSlowRate == 0 && isSlowDown) |
| | | { |
| | | isSlowDown = false; |
| | | StopSlowDownEffect(); |
| | | } |
| | | |
| | | Vector3 curPos = m_NavMeshAgent.transform.position; |
| | | bool swithNode = false; |
| | |
| | | // 根据是否到达一个结点来进行不同的处理 |
| | | if (swithNode) |
| | | { |
| | | this.MoveToNextNode(m_NextNode); |
| | | MoveToNextNode(m_NextNode); |
| | | } |
| | | else |
| | | { |
| | | // Y值插值. |
| | | float lerpVal = (curPos.z - mStartZVal) / (m_Destination.transform.position.z - mStartZVal); |
| | | if (!this.opponentAgent) |
| | | if (!opponentAgent) |
| | | // curPos.y = mStartYVal + lerpVal * 60f; |
| | | curPos.y = mStartYVal; |
| | | m_NavMeshAgent.transform.position = curPos; |
| | |
| | | /// <returns></returns> |
| | | protected void UpdateAction() |
| | | { |
| | | if (!mAnim) return; |
| | | if (ActionAnimator == null) return; |
| | | |
| | | AnimatorStateInfo stateinfo = mAnim.GetCurrentAnimatorStateInfo(0); |
| | | AnimatorStateInfo stateInfo = ActionAnimator.GetCurrentAnimatorStateInfo(0); |
| | | |
| | | if (stateinfo.IsName("Die") && (stateinfo.normalizedTime >= 0.7f)) |
| | | switch (ActionState) |
| | | { |
| | | this.Remove(); |
| | | return; |
| | | case AgentActionState.Move: |
| | | break; |
| | | case AgentActionState.GetHit: |
| | | if (stateInfo.normalizedTime >= 1f) |
| | | ChangeState(AgentActionState.Move); |
| | | break; |
| | | case AgentActionState.Attack: |
| | | if (stateInfo.normalizedTime >= 1f) |
| | | { |
| | | if (isDead) |
| | | { |
| | | AgentInsManager.instance.removeAgent(this); |
| | | Remove(); |
| | | } |
| | | } |
| | | break; |
| | | case AgentActionState.Death: |
| | | if (stateInfo.normalizedTime >= 1f) |
| | | Remove(); |
| | | break; |
| | | } |
| | | else if (stateinfo.IsName("GetHit") && (stateinfo.normalizedTime >= 0.7f)) |
| | | { |
| | | mAnim.SetBool("GetHit", false); |
| | | } |
| | | else if (stateinfo.IsName("Attack") && (stateinfo.normalizedTime >= 0.9f)) |
| | | { |
| | | if (this.healthVal <= 0.1) |
| | | { |
| | | // 统一管理器内删除当前的Agent: |
| | | AgentInsManager.instance.removeAgent(this); |
| | | this.Remove(); |
| | | Debug.Log("删除多余的攻击Agent."); |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return; |
| | | private void ChangeState(AgentActionState state) |
| | | { |
| | | if (state == ActionState) return; |
| | | |
| | | ActionState = state; |
| | | if (ActionAnimator != null) |
| | | ActionAnimator.SetInteger(paramName, (int)state); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// Reset destination when path is stale |
| | | /// River: 更新的时候,加入离最终目标的距离数据. |
| | | /// </summary> |
| | | protected virtual void Update() |
| | | protected virtual void LateUpdate() |
| | | { |
| | | this.UpdateAction(); |
| | | UpdateAction(); |
| | | HandleShieldWall(); |
| | | HandleFrost(); |
| | | |
| | | // 处理死亡状态了,不必再移动: |
| | | if (bInDeathAct) return; |
| | | if (bInDeathAct || !CanMove) return; |
| | | |
| | | m_Destination = initNode.GetNextNode(); |
| | | updateAgentPos(Time.deltaTime); |
| | | |
| | | // 计算离目标的距离,非最终距离,只用于比较大小 |
| | | this.m_DisToDestination = this.GetDisToDestination(); |
| | | m_DisToDestination = GetDisToDestination(); |
| | | |
| | | // 计算中毒相关. |
| | | if ((poisonTimes > 0) && (poisonHurt > 0)) |
| | | updatePoison(Time.deltaTime); |
| | | } |
| | | |
| | | private void HandleFrost() |
| | | { |
| | | if (IsFrost) |
| | | { |
| | | if (FrostRemainTime > 0f) |
| | | { |
| | | FrostRemainTime -= Time.deltaTime; |
| | | |
| | | if (FrostRemainTime <= 0f) |
| | | IsFrost = false; |
| | | } |
| | | else |
| | | IsFrost = false; |
| | | } |
| | | } |
| | | |
| | | protected virtual void Update() |
| | | { |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 处理魔法护盾血量值 |
| | | /// </summary> |
| | | protected void HandleShieldWall() |
| | | { |
| | | if (configuration.IsExistShieldWall) |
| | | { |
| | | if (configuration.ShieldWallCurrentHealth <= 0.00001f) |
| | | configuration.IsExistShieldWall = false; |
| | | else if (configuration.ShieldWallEffectiveTime > 0.00001f) |
| | | { |
| | | if (configuration.ShieldWallRemainTime <= 0.00001f) |
| | | configuration.IsExistShieldWall = false; |
| | | else |
| | | configuration.ShieldWallRemainTime -= Time.deltaTime; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | { |
| | | /* // 设置最大的Z值,确保按路线移动 |
| | | Vector3 pos = m_NavMeshAgent.transform.position; |
| | | if (this.m_PositiveZ) |
| | | if (m_PositiveZ) |
| | | { |
| | | if (pos.z > m_ZMaxValue) |
| | | { |
| | |
| | | } |
| | | } |
| | | // 设置X值的限制,确保按路线移动 |
| | | if(this.m_PositiveX) |
| | | if(m_PositiveX) |
| | | { |
| | | if( pos.x > m_XMaxValue) |
| | | { |
| | |
| | | tmpDis += NODE_DIS; |
| | | tmpNode = tmpNode.GetNextNode(); |
| | | } |
| | | Vector3 tpos = this.position; |
| | | Vector3 tpos = position; |
| | | tpos.y = mStartYVal; |
| | | tmpDis += Vector3.Distance(tpos, this.m_Destination.transform.position); |
| | | tmpDis += Vector3.Distance(tpos, m_Destination.transform.position); |
| | | |
| | | return tmpDis; |
| | | } |
| | | |
| | | protected ChangeMat changeMat; |
| | | /// <summary> |
| | | /// This is a lazy way of caching several components utilised by the Agent |
| | | /// </summary> |
| | |
| | | } |
| | | if (!endlessLevelManager) |
| | | endlessLevelManager = EndlessLevelManager.instance; |
| | | |
| | | if (mAnim == null) |
| | | { |
| | | foreach (Transform t in transform.GetComponentsInChildren<Transform>()) |
| | | { |
| | | if (t.name == "Model") |
| | | mAnim = t.GetComponent<Animator>(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | public void PlayOnHit() |
| | | { |
| | | if (mAnim) |
| | | mAnim.SetBool("GetHit", true); |
| | | ChangeState(AgentActionState.GetHit); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 播放受击动画,直接从头开始播放 |
| | | /// </summary> |
| | | public void PlayOnHitImmediately() |
| | | { |
| | | ChangeState(AgentActionState.GetHit); |
| | | if (ActionAnimator) |
| | | { |
| | | ActionAnimator.Play("GetHit", 0, 0); |
| | | ActionAnimator.Update(0); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 播放火技能打击动画 |
| | | /// </summary> |
| | | public void PlayFireSkillHit() |
| | | { |
| | | if (FireSkillParticle != null) |
| | | FireSkillParticle.Play(); |
| | | } |
| | | |
| | | public void PlayAttack() |
| | | { |
| | | if (mAnim) |
| | | mAnim.SetBool("Attack", true); |
| | | AudioSourceManager.Ins.Play(AudioEnum.AttackTower); |
| | | ChangeState(AgentActionState.Attack); |
| | | } |
| | | |
| | | public override void PlayDeath() |
| | | { |
| | | if (mAnim) |
| | | { |
| | | mAnim.SetBool("Die", true); |
| | | // 统一管理器内删除当前的Agent: |
| | | AgentInsManager.instance.removeAgent(this); |
| | | bInDeathAct = true; |
| | | } |
| | | else |
| | | { |
| | | this.Remove(); |
| | | } |
| | | } |
| | | if (bInDeathAct) return; |
| | | |
| | | IEnumerator WaitDeathStop() |
| | | { |
| | | yield return null; |
| | | AnimatorStateInfo stateinfo = mAnim.GetCurrentAnimatorStateInfo(0); |
| | | |
| | | if (stateinfo.IsName("Die") && (stateinfo.normalizedTime >= 1.0f)) |
| | | if (isPoison) |
| | | { |
| | | Debug.Log("死亡动画播放完成,开始处理."); |
| | | this.Remove(); |
| | | isPoison = false; |
| | | // 移除Agent身上的中毒特效,并播放一个中毒效果消失的特效 |
| | | if (PoisonParticle != null) |
| | | { |
| | | PoisonParticle.Stop(); |
| | | PoisonParticle.Clear(); |
| | | if (PoisonEndParticle != null) |
| | | PoisonEndParticle.Play(); |
| | | } |
| | | } |
| | | |
| | | if (isSlowDown) |
| | | { |
| | | isSlowDown = false; |
| | | |
| | | if (SlowDownParticle != null) |
| | | { |
| | | SlowDownParticle.Stop(); |
| | | SlowDownParticle.Clear(); |
| | | } |
| | | } |
| | | |
| | | bInDeathAct = true; |
| | | |
| | | if (EnemyData != null && EndlessGameUI.instance.state != EndlessGameUI.State.GameOver) |
| | | { |
| | | // Debug.Log("小怪被杀死了,增加能量" + EnemyData.energy); |
| | | EventCenter.Ins.BroadCast((int)KTGMGemClient.EventType.EnergyUp, EnemyData.energy); |
| | | } |
| | | |
| | | Remove(); |
| | | } |
| | | |
| | | /// <summary> |