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);
}
}
}