| | |
| | | using Core.Health; |
| | | using TowerDefense.Affectors; |
| | | using TowerDefense.Towers; |
| | | using UnityEngine; |
| | | |
| | | namespace TowerDefense.Agents |
| | | namespace TowerDefense.Agents |
| | | { |
| | | /// <summary> |
| | | /// An implementation of Agent that will attack |
| | | /// any Towers that block its path |
| | | /// </summary> |
| | | public class AttackingAgent : Agent |
| | | { |
| | | /// <summary> |
| | | /// Tower to target |
| | | /// </summary> |
| | | protected Tower m_TargetTower; |
| | | /// <summary> |
| | | /// An implementation of Agent that will attack |
| | | /// any Towers that block its path |
| | | /// </summary> |
| | | public class AttackingAgent : Agent |
| | | { |
| | | public override void Initialize() |
| | | { |
| | | base.Initialize(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// The attached attack affector |
| | | /// </summary> |
| | | protected AttackAffector m_AttackAffector; |
| | | |
| | | /// <summary> |
| | | /// Is this agent currently engaging a tower? |
| | | /// </summary> |
| | | protected bool m_IsAttacking; |
| | | /// <summary> |
| | | /// Unsubscribes from tracked towers removed event |
| | | /// and disables the attached attack affector |
| | | /// </summary> |
| | | public override void Remove() |
| | | { |
| | | base.Remove(); |
| | | } |
| | | |
| | | public override void Initialize() |
| | | { |
| | | base.Initialize(); |
| | | |
| | | // Attack affector |
| | | m_AttackAffector.Initialize(configuration.alignmentProvider); |
| | | |
| | | // We don't want agents to attack towers until their path is blocked, |
| | | // so disable m_AttackAffector until it is needed |
| | | m_AttackAffector.enabled = false; |
| | | } |
| | | /// <summary> |
| | | /// Peforms the relevant path update for the states <see cref="Agent.State.OnCompletePath"/>, |
| | | /// <see cref="Agent.State.OnPartialPath"/> and <see cref="Agent.State.Attacking"/> |
| | | /// </summary> |
| | | protected override void PathUpdate() |
| | | { |
| | | |
| | | /// <summary> |
| | | /// Unsubscribes from tracked towers removed event |
| | | /// and disables the attached attack affector |
| | | /// </summary> |
| | | public override void Remove() |
| | | { |
| | | base.Remove(); |
| | | if (m_TargetTower != null) |
| | | { |
| | | m_TargetTower.removed -= OnTargetTowerDestroyed; |
| | | } |
| | | m_AttackAffector.enabled = false; |
| | | m_TargetTower = null; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Gets the closest tower to the agent |
| | | /// </summary> |
| | | /// <returns>The closest tower</returns> |
| | | protected Tower GetClosestTower() |
| | | { |
| | | var towerController = m_AttackAffector.towerTargetter.GetTarget( -1 ) as Tower; |
| | | return towerController; |
| | | } |
| | | /// <summary> |
| | | /// Change to <see cref="Agent.State.OnCompletePath" /> when path is no longer blocked or to |
| | | /// <see cref="Agent.State.Attacking" /> when the agent reaches <see cref="AttackingAgent.m_TargetTower" /> |
| | | /// </summary> |
| | | protected override void OnPartialPathUpdate() |
| | | { |
| | | |
| | | /// <summary> |
| | | /// Caches the Attack Affector if necessary |
| | | /// </summary> |
| | | protected override void LazyLoad() |
| | | { |
| | | base.LazyLoad(); |
| | | if (m_AttackAffector == null) |
| | | { |
| | | m_AttackAffector = GetComponent<AttackAffector>(); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// If the tower is destroyed while other agents attack it, ensure it becomes null |
| | | /// </summary> |
| | | /// <param name="tower">The tower that has been destroyed</param> |
| | | protected virtual void OnTargetTowerDestroyed(DamageableBehaviour tower) |
| | | { |
| | | if (m_TargetTower == tower) |
| | | { |
| | | m_TargetTower.removed -= OnTargetTowerDestroyed; |
| | | m_TargetTower = null; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Peforms the relevant path update for the states <see cref="Agent.State.OnCompletePath"/>, |
| | | /// <see cref="Agent.State.OnPartialPath"/> and <see cref="Agent.State.Attacking"/> |
| | | /// </summary> |
| | | protected override void PathUpdate() |
| | | { |
| | | switch (state) |
| | | { |
| | | case State.OnCompletePath: |
| | | OnCompletePathUpdate(); |
| | | break; |
| | | case State.OnPartialPath: |
| | | OnPartialPathUpdate(); |
| | | break; |
| | | case State.Attacking: |
| | | AttackingUpdate(); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// Change to <see cref="Agent.State.OnCompletePath" /> when path is no longer blocked or to |
| | | /// <see cref="Agent.State.Attacking" /> when the agent reaches <see cref="AttackingAgent.m_TargetTower" /> |
| | | /// </summary> |
| | | protected override void OnPartialPathUpdate() |
| | | { |
| | | if (!isPathBlocked) |
| | | { |
| | | state = State.OnCompletePath; |
| | | return; |
| | | } |
| | | |
| | | // Check for closest tower at the end of the partial path |
| | | m_AttackAffector.towerTargetter.transform.position = m_NavMeshAgent.pathEndPosition; |
| | | Tower tower = GetClosestTower(); |
| | | if (tower != m_TargetTower) |
| | | { |
| | | // if the current target is to be replaced, unsubscribe from removed event |
| | | if (m_TargetTower != null) |
| | | { |
| | | m_TargetTower.removed -= OnTargetTowerDestroyed; |
| | | } |
| | | |
| | | // assign target, can be null |
| | | m_TargetTower = tower; |
| | | |
| | | // if new target found subscribe to removed event |
| | | if (m_TargetTower != null) |
| | | { |
| | | m_TargetTower.removed += OnTargetTowerDestroyed; |
| | | } |
| | | } |
| | | if (m_TargetTower == null) |
| | | { |
| | | return; |
| | | } |
| | | float distanceToTower = Vector3.Distance(transform.position, m_TargetTower.transform.position); |
| | | if (!(distanceToTower < m_AttackAffector.towerTargetter.effectRadius)) |
| | | { |
| | | return; |
| | | } |
| | | if (!m_AttackAffector.enabled) |
| | | { |
| | | m_AttackAffector.towerTargetter.transform.position = transform.position; |
| | | m_AttackAffector.enabled = true; |
| | | } |
| | | state = State.Attacking; |
| | | m_NavMeshAgent.isStopped = true; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// The agent attacks until the path is available again or it has killed the target tower |
| | | /// </summary> |
| | | protected void AttackingUpdate() |
| | | { |
| | | if (m_TargetTower != null) |
| | | { |
| | | return; |
| | | } |
| | | // River mod: 修改了Agent的移动方式,这个函数的模式已修改. |
| | | //MoveToNode(); |
| | | |
| | | // Resume path once blocking has been cleared |
| | | m_IsAttacking = false; |
| | | m_NavMeshAgent.isStopped = false; |
| | | m_AttackAffector.enabled = false; |
| | | state = isPathBlocked ? State.OnPartialPath : State.OnCompletePath; |
| | | // Move the Targetter back to the agent's position |
| | | m_AttackAffector.towerTargetter.transform.position = transform.position; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |