I am trying to make fly pathfinding.
When the target root have a collider, it works as shown in video. The fighter can pick destination
near target as shown in the pink line. (no terrain check yet)
However, when i use the encapsulate code, the destination will be very far away as shown in picture.
Bounds bounds = new Bounds();
public Transform Target
{
get { return target; }
set
{
target = value;
Collider[] colliders = GetComponentsInChildren<Collider>();
bounds = new Bounds(target.position, Vector3.one);
foreach (Collider c in colliders)
{
bounds.Encapsulate(c.bounds);
}
Debug.Log(bounds);
targetRadius = Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z);
// bounds = target.GetComponent<Collider>().bounds;
// targetRadius = Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z);
stopDistanceSqrt = targetRadius + attackRange;
returnDistanceSqrt = targetRadius + funnelRadius * 20;
stopDistanceSqrt *= stopDistanceSqrt;
returnDistanceSqrt *= returnDistanceSqrt;
contactPoint = target.position;
}
}
public bool ContactPoint
{
get { return contactPointDisable; }
set { contactPointDisable = value; }
}
private void Awake()
{
rigidbody = GetComponent<Rigidbody>();
Vector3 b = GetComponent<Collider>().bounds.size;
funnelRadius = Mathf.Max(b.x, b.y, b.z);
if (debug)
Target = target;
}
private void FixedUpdate()
{
if (target != null)
Move();
}
void Move()
{
// fly to target until distance
// pick a non block direction to keep flying
// return to target until a specific distance
float distanceSqrt = (target.position - transform.position).sqrMagnitude;
switch (mode)
{
case Mode.MoveToTarget:
if (distanceSqrt > stopDistanceSqrt)
{
if (contactPointDisable)
contactPoint = target.position;
else
contactPoint = PickContactPointOnTarget();
Rotate();
rigidbody.MovePosition(transform.position + transform.forward * speed * Time.fixedDeltaTime);
}
else
mode = Mode.MoveFromTarget;
break;
case Mode.MoveFromTarget:
if (distanceSqrt < returnDistanceSqrt)
{
rigidbody.MovePosition(transform.position + transform.forward * speed * Time.fixedDeltaTime);
}
else
mode = Mode.MoveToTarget;
break;
}
}
Vector3 PickContactPointOnTarget()
{
int DefaultLayer = 0;
int TerrainLayer = 9;
int LayerMask = 1 << DefaultLayer | 1 << TerrainLayer;
// should not move directly to target position.
// should move to a attack point near target
Vector3 d = contactPoint - transform.position;
RaycastHit hit;
// check if the current contact point valid
// if (!Physics.SphereCast(transform.position, funnelRadius, d, out hit, d.magnitude + targetRadius * 2))
// return contactPoint;
d = target.position - transform.position;
Vector3 fwdOriginal = d.normalized;
Vector3 fwd = fwdOriginal;
for (int i = 1; i <= 180; i+=5)
{
float distance = Mathf.Tan(i * Mathf.Deg2Rad) * d.magnitude;
fwd = fwdOriginal;
// only consider ray that is far enough from target
if (distance >= targetRadius + contactDistance)
{
// Left, Right
fwd = fwdOriginal;
fwd = Quaternion.Euler(i, 0, 0) * fwd;
if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
break;
fwd = fwdOriginal;
fwd = Quaternion.Euler(-i, 0, 0) * fwd;
if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
break;
// Up, Down
fwd = fwdOriginal;
fwd = Quaternion.Euler(0, i, 0) * fwd;
if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
break;
fwd = fwdOriginal;
fwd = Quaternion.Euler(0, -i, 0) * fwd;
if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
break;
// Slope
fwd = fwdOriginal;
fwd = Quaternion.Euler(i, i, 0) * fwd;
if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
break;
fwd = fwdOriginal;
fwd = Quaternion.Euler(-i,i, 0) * fwd;
if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
break;
fwd = fwdOriginal;
fwd = Quaternion.Euler(i, -i, 0) * fwd;
if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
break;
fwd = fwdOriginal;
fwd = Quaternion.Euler(-i, -i, 0) * fwd;
if (!Physics.SphereCast(transform.position, funnelRadius, fwd, out hit, d.magnitude + targetRadius * 2))
break;
}
}
line.SetPosition(0, transform.position);
line.SetPosition(1, transform.position + fwd * (d.magnitude));
return transform.position + fwd * (d.magnitude);
}
void Rotate()
{
Vector3 d = contactPoint - transform.position;
Quaternion rot = Quaternion.LookRotation(d, Vector3.up);
rot = Quaternion.RotateTowards(transform.rotation, rot, Time.fixedDeltaTime * 50);
rigidbody.MoveRotation(rot);
}
private void OnDrawGizmos()
{
Debug.DrawLine(bounds.center + bounds.extents, bounds.center, Color.red);
Debug.DrawLine(target.position, contactPoint, Color.red);
Debug.DrawLine(transform.position, contactPoint);
}
}