using UnityEngine; namespace BehaviorDesigner.Runtime.Tactical { /// /// The TacticalAgent class contains component references and variables for each TacticalAgent. /// public abstract class TacticalAgent { private static int ignoreRaycast = ~(1 << LayerMask.NameToLayer("Ignore Raycast")); protected Transform transform; private IAttackAgent attackAgent; private Transform targetTransform = null; private IDamageable targetDamagable = null; private bool attackPosition = false; private Vector3 attackOffset; private Vector3 targetOffset; public IAttackAgent AttackAgent { get { return attackAgent; } } public Transform TargetTransform { get { return targetTransform; } set { targetTransform = value; } } public IDamageable TargetDamagable { get { return targetDamagable; } set { targetDamagable = value; } } public bool AttackPosition { get { return attackPosition; } set { attackPosition = value; } } public Vector3 AttackOffset { set { attackOffset = value; } } public Vector3 TargetOffset { set { targetOffset = value; } } /// /// Caches the component referneces. /// public TacticalAgent(Transform agent) { transform = agent; attackAgent = agent.GetComponent(typeof(IAttackAgent)) as IAttackAgent; } /// /// Sets the destination. /// public abstract void SetDestination(Vector3 destination); /// /// Has the agent arrived at its destination? /// public abstract bool HasArrived(); /// /// Rotates towards the target rotation. /// public abstract bool RotateTowards(Quaternion targetRotation); /// /// Returns the radius of the agent. /// public abstract float Radius(); /// /// Starts or stops the rotation from updating. Not all implementations will use this. /// public abstract void UpdateRotation(bool update); /// /// Stops the agent from moving. /// public abstract void Stop(); /// /// The task has ended. Perform any cleanup. /// public abstract void End(); /// /// Looks at position parameter. /// public bool RotateTowardsPosition(Vector3 position) { var targetRotation = Quaternion.LookRotation(position - transform.position); return RotateTowards(targetRotation); } /// /// Can the agent see the target transform? /// public bool CanSeeTarget() { var distance = (transform.position - targetTransform.position).magnitude; if (distance >= attackAgent.AttackDistance()) { return false; } RaycastHit hit; if (Physics.Linecast(transform.TransformPoint(attackOffset), targetTransform.TransformPoint(targetOffset), out hit, ignoreRaycast)) { if (ContainsTransform(targetTransform, hit.transform)) { return true; // return the target object meaning it is within sight } } else if (targetTransform.GetComponent() == null || targetTransform.GetComponent() != null) { // If the linecast doesn't hit anything then that the target object doesn't have a collider and there is nothing in the way if (targetTransform.gameObject.activeSelf) { return true; } } return false; } /// /// Attacks the target. /// public bool TryAttack() { if (attackAgent.CanAttack()) { attackAgent.Attack(targetTransform.position); return true; } return false; } /// /// Returns true if the target transform is a child of the parent transform /// private static bool ContainsTransform(Transform target, Transform parent) { if (target == null) { return false; } if (target.Equals(parent)) { return true; } return ContainsTransform(target.parent, parent); } } }