- Home /
Turret. Detect if target is inside horizontal and vertical arcs
Hi. I am trying to make a turret control for a spaceship (rts game). I have a coroutine that rotates the turret (a base horizontal axis, and a barrel vertical axis). It works fine, I have used Quaternion.Lookrotation and Quaternion.RotateTowards with a clamp to limit the minimum and maximum angle of both axes.
Then I have another coroutine that checks if there is a new target (the ship has two target lists: one holds ships added with right clicks (attack order), and the other adds ships when they are closer). If there is a target, it tells the first coroutine to target it.
To do this I need a function that returns a bool, depending on whether the target is within the turret arcs (both horizontal and vertical arcs). how can I do this? The arcs are relative to the ship and can go in all directions so it can tilt on all 3 axes.
The data I have is the transformation of the ship/horizontal turret, the position of the target, the minimum/maximum of both arcs.
I think it should make a projection of the target on the plane of the ship and? Can you guide me with this?
Answer by CodesCove · Jan 23, 2021 at 08:31 AM
I wrote this long time ago.. it's part of my sight sensor but should work for your case (no guarantee :) )
private bool IsInFOV(Transform fovTransform, UnityEngine.Vector3 targetPosition, float maxHorizontalDegrees, float maxVerticalDegrees)
{
//to local space
UnityEngine.Vector3 sourceDirectionForward = fovTransform.InverseTransformDirection(fovTransform.forward);
//to local space
UnityEngine.Vector3 targetLocalSpacePosition = fovTransform.InverseTransformPoint(targetPosition);
UnityEngine.Vector3 targetLocalSpaceXZDirection = new UnityEngine.Vector3(targetLocalSpacePosition.x, 0, targetLocalSpacePosition.z) - new UnityEngine.Vector3(0, 0, 0);
float targetLocalDistance = UnityEngine.Vector3.Distance(UnityEngine.Vector3.zero, targetLocalSpacePosition);
//this.distance = targetLocalDistance;
float targetAngleV = Mathf.Rad2Deg * (Mathf.Atan(Mathf.Abs(targetLocalSpacePosition.y) / Mathf.Abs(targetLocalDistance)));
float targetAngleH = UnityEngine.Vector3.Angle(targetLocalSpaceXZDirection, sourceDirectionForward);
if ((targetAngleV <= maxVerticalDegrees/2) && (targetAngleH <= maxHorizontalDegrees/2)) return true;
return false;
}
Hope you get it working,,
PS. here are parameter descriptions:
fovTransform = transform of the eye
targetPosition = position of the target
maxHorizontalDegrees = Maximum of horizontal (max 360) angle between eye and target in degrees
maxVerticalDegrees = Maximum of vertical (max 180) angle between eye and target in degrees
Thank you, it works perfect. Im only changed the final line, because i use a $$anonymous$$/max for horizontal and a $$anonymous$$/max for vertical. I used something like this:
return targetAngleH < maxHorizontalDegrees && targetAngleH > $$anonymous$$HorizontalDegrees && targetAngleV < maxVerticalDegrees && targetAngleV > $$anonymous$$VerticalDegrees;
Answer by diegonv · Jan 23, 2021 at 09:15 PM
If anyone is interested in how to rotate the turret, i use this (the objetive assignment is another topic).
turret_horizontal is the transform of the horizontal axis of the turret (the body).
turret_vertical is the transform of the vertical axis of the turret (the canon)
turret_vertical must be child of turret horizontal
void FixedUpdate() //or a coroutine with yield return new WaitForFixedUpdate { Quaternion _rot = Quaternion.LookRotation(targetTransform.position - turret_horizontal.position);
turret_horizontal.rotation = Quaternion.RotateTowards(turret_horizontal.rotation, _rot, _vel_horizontal * Time.fixedDeltaTime); turret_horizontal.localEulerAngles = new Vector3(0f, fClampAngle(turret_horizontal.localEulerAngles.y, _ang_min_horizontal, _ang_max_horizontal), 0f); turret_vertical.rotation = Quaternion.RotateTowards(turret_vertical.rotation, _rot, _vel_vertical * Time.fixedDeltaTime); turret_vertical.localEulerAngles = new Vector3(fClampAngle(turret_vertical.localEulerAngles.x, _ang_min_vertical, _ang_max_vertical), 0f, 0f); } public static float fClampAngle(float angulo, float min, float max) //it clamps an angle without euler angles errors { angulo = Mathf.Repeat(angulo, 360f); return (angulo > 180f) ? Mathf.Max(angulo, 360f+min) : Mathf.Min(angulo, max); }