I have a ship that will shoot targets, but cannons on the right side should never try to shot at targets on the left side of the ship. Thus I have created sectors using the SignedAngle
function, this works fine for testing, but its also kind of broken as you can see from the visualization below.
I have tried using boxcast
but alas it also doesnt work for this use case.
The above image visualizes what my script does, but this is not a solution to my problem. As targets close to the side and front of the ship will be outside the sector, for clarification what I mean, see picture 3.
This second image shows what happens when we increase the angle, we can now detect more targets, but we have 2 big incorrect sectors marked in red which shouldnt be there.
Finally, this is how I think it should look, its still a cone, but the big difference is that it starts with a wide bottom, thus it resolves the problem Im having with the current SignedAngle function which determines everything from a single point in the middle.
This is the script for assigning targets to the correct list according to which sector they are in:
foreach (Transform target in EnemyListManager.instance.enemyShips.ToArray())
{
if (Vector3.Distance(transform.position, target.position) > ship.mainGunCaliber.range)
continue;
Vector3 toTarget = target.position - transform.position;
print(Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up));
if (Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) >= bowMinAngle &&
Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) <= bowMaxAngle)
{
if (!bowTargets.Contains(target))
{
RemoveFromOthers(target);
bowTargets.Add(target);
print("added target to Bow");
}
continue;
}
if (Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) >= sbMinAngle &&
Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) <= sbMaxAngle)
{
if (!sbTargets.Contains(target))
{
RemoveFromOthers(target);
sbTargets.Add(target);
print("added target to SB");
}
continue;
}
if (Vector3.SignedAngle(-hullParent.forward, toTarget, Vector3.up) >= aftMinAngle &&
Vector3.SignedAngle(-hullParent.forward, toTarget, Vector3.up) <= aftMaxAngle)
{
if (!aftTargets.Contains(target))
{
RemoveFromOthers(target);
aftTargets.Add(target);
print("added target to Aft");
}
continue;
}
if (Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) >= psMinAngle &&
Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) <= psMaxAngle)
{
if (!psTargets.Contains(target))
{
RemoveFromOthers(target);
psTargets.Add(target);
print("added target to PS");
}
}
}
Any help would be appreciated on how to tackle this problem!
Thank you.
There are a couple options I can think of.
Your code, for the starboard side, would then be more like (I think, I'm nautically inclined so I may be wrong about the labelling lol):
if (Vector3.SignedAngle(markerBowStarboard.right, toTarget, Vector3.up) >= sbMinAngle &&
Vector3.SignedAngle(markerAftStarboard.right, toTarget, Vector3.up) <= sbMaxAngle)
{
if (!sbTargets.Contains(target))
{
RemoveFromOthers(target);
sbTargets.Add(target);
print("added target to SB");
}
continue;
}
But again, it's sort of just trading one calculation for another.
OnColliderEnter
, I think?) you can add them to that direction's list and remove when they exit (OnColliderExit
maybe?). You may need to do some more checking on when it is fully inside the conic cylinder though, because I think OnColliderExit
(or whatever it's called) is triggered when the model stops colliding with the actual mesh, regardless of whether it is inside or outside of the object.I'm not super sure I like any of those that much, but I'm surprised that there isn't a native "ConeCast" that can take near- and far-plane dimensions... but then I guess I'm just saying to Unity "I don't wanna do it, you do it" lol.