Real-world aiming, just like in combat simulators, works a little differently from the widely-used automatic aiming in almost every game. Imagine that you need to implement an agent controlling a tank turret or a humanized sniper; that's when this recipe comes in handy.
We need to make some modifications to our AgentBehaviour
class:
public float maxSpeed; public float maxAccel; public float maxRotation; public float maxAngularAccel;
MapToRange
. This function helps in finding the actual direction of rotation after two orientation values are subtracted:public float MapToRange (float rotation) { rotation %= 360.0f; if (Mathf.Abs(rotation) > 180.0f) { if (rotation < 0.0f) rotation += 360.0f; else rotation -= 360.0f; } return rotation; }
Align
that is the stepping stone for the facing algorithm. It uses the same principle as Arrive
, but only in terms of rotation:using UnityEngine; using System.Collections; public class Align : AgentBehaviour { public float targetRadius; public float slowRadius; public float timeToTarget = 0.1f; public override Steering GetSteering() { Steering steering = new Steering(); float targetOrientation = target.GetComponent<Agent>().orientation; float rotation = targetOrientation - agent.orientation; rotation = MapToRange(rotation); float rotationSize = Mathf.Abs(rotation); if (rotationSize < targetRadius) return steering; float targetRotation; if (rotationSize > slowRadius) targetRotation = agent.maxRotation; else targetRotation = agent.maxRotation * rotationSize / slowRadius; targetRotation *= rotation / rotationSize; steering.angular = targetRotation - agent.rotation; steering.angular /= timeToTarget; float angularAccel = Mathf.Abs(steering.angular); if (angularAccel > agent.maxAngularAccel) { steering.angular /= angularAccel; steering.angular *= agent.maxAngularAccel; } return steering; } }
We now proceed to implement our facing algorithm that derives from Align
:
Face
class along with a private auxiliary target member variable:using UnityEngine; using System.Collections; public class Face : Align { protected GameObject targetAux; }
Awake
function to set up everything and swap references:public override void Awake() { base.Awake(); targetAux = target; target = new GameObject(); target.AddComponent<Agent>(); }
OnDestroy
function to handle references and avoid memory issues:void OnDestroy () { Destroy(target); }
GetSteering
function:public override Steering GetSteering()
{
Vector3 direction = targetAux.transform.position - transform.position;
if (direction.magnitude > 0.0f)
{
float targetOrientation = Mathf.Atan2(direction.x, direction.z);
targetOrientation *= Mathf.Rad2Deg;
target.GetComponent<Agent>().orientation = targetOrientation;
}
return base.GetSteering();
}