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.
CodePudding user response:
There are a couple options I can think of.
- You can use 4 (or more, for up-down range as well) points to measure the angles from instead of the single point from the center that I'd previously suggested.
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;
}
- You could try to adapt something from
But again, it's sort of just trading one calculation for another.
- You could create a conic cylinder model, don't render it but give it a MeshCollider, and then when objects enter the object (
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 thinkOnColliderExit
(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.
CodePudding user response:
Some random ideas here. I would try discard the not desired sector with 2 sphere casts of different diameter. (
You can set the length of detection with
maxDistance
argument of the spheres cast. This will determine the length of the cone, so the Starboard Aim Sector length. The zone green lined is for the points that are detected by the beam2 but not beam1.What to do with those points? Some are inside the cone, and some are not. A cone is simply an infinite number of circles whose size is defined by a linear equation that takes the distance from the point. So with the distance from the rays origin in the beams direction, you know the circle size of that section of the cone. You should then easily be able to know if your point is in/out that circle, so in/out of the cone.
- You could create a conic cylinder model, don't render it but give it a MeshCollider, and then when objects enter the object (