We want DebugOverlay.Cone and Gizmo.Draw.Cone!
Here is the code:
/// <summary>
/// Render a cone for a specific amount of time
/// </summary>
/// <param name="origin"></param>
/// <param name="radius"></param>
/// <param name="direction"></param>
/// <param name="angle"></param>
/// <param name="lines"></param>
/// <param name="color"></param>
/// <param name="time"></param>
public static void Cone(Vector3 origin, float radius, Vector3 direction, float angle, int lines = 12, Color? color = null, float time = 0f)
=> AddToQueue(() =>
{
Gizmo.Draw.Color = color ?? Color.White;
var halfAngle = angle / 2f;
var normalDir = direction.Normal;
var baseCenter = origin + normalDir * (radius * MathF.Cos(MathX.DegreeToRadian(halfAngle)));
var baseRadius = radius * MathF.Sin(MathX.DegreeToRadian(halfAngle));
var upDirection = Vector3.Cross(normalDir, Vector3.Up).Normal;
var rightDirection = Vector3.Cross(normalDir, upDirection).Normal;
Vector3? previousPoint = null;
var firstPoint = Vector3.Zero;
for (var edge = 0; edge < lines; edge++)
{
var edgeAngle = MathF.PI * edge * 2f / lines;
var edgeX = MathF.Cos(edgeAngle) * baseRadius;
var edgeY = MathF.Sin(edgeAngle) * baseRadius;
var edgePosition = baseCenter + rightDirection * edgeX + upDirection * edgeY;
Gizmo.Draw.Line(origin, edgePosition);
if (edge == 0)
firstPoint = edgePosition;
if (previousPoint != null)
Gizmo.Draw.Line(previousPoint.Value, edgePosition);
if (edge + 1 == lines)
Gizmo.Draw.Line(edgePosition, firstPoint);
previousPoint = edgePosition;
}
}, time);
}Just add it straight to s&box, free of charge, thank you.
And if you want to check if a bbox intersects with a cone here you go:
/// <summary>
/// Is the provided bbox hit by the cone
/// </summary>
/// <param name="bbox"></param>
/// <param name="origin"></param>
/// <param name="radius"></param>
/// <param name="direction"></param>
/// <param name="angle"></param>
/// <returns></returns>
public static bool IsBBoxHitByCone( BBox bbox, Vector3 origin, float radius, Vector3 direction, float angle )
{
var normalDir = direction.Normal * (angle > 180f ? -1f : 1f);
foreach ( var corner in bbox.Corners )
if ( IsPointInsideCone( origin, radius, direction, angle, corner ) )
return true; // Sometimes it's that easy!
var coneLine = new Line( origin, origin + normalDir * radius );
if ( bbox.Contains( coneLine.ClosestPoint( bbox.Center ) ) ) // Check if the cone's center intersects with the bbox
return true; // Hopefully we've got something by now!
// Now we panic
var baseCenter = origin + normalDir * radius;
var baseRadius = radius * MathF.Tan( MathX.DegreeToRadian( angle ) / 2f );
var upDirection = Vector3.Cross( normalDir, Vector3.Up ).Normal;
var rightDirection = Vector3.Cross( normalDir, upDirection ).Normal;
var outerEdges = 12;
for ( var edge = 0; edge < outerEdges; edge++ )
{
var edgeAngle = MathF.PI * edge * 2f / outerEdges;
var edgeX = MathF.Cos( edgeAngle ) * baseRadius;
var edgeY = MathF.Sin( edgeAngle ) * baseRadius;
var edgePosition = baseCenter + rightDirection * edgeX + upDirection * edgeY;
var edgeLine = new Line( origin, edgePosition );
if ( bbox.Contains( edgeLine.ClosestPoint( bbox.Center ) ) ) // Check if the cone's outer edge intersects with the bbox
return true;
}
return false;
}It's not perfect but it works, especially if you just need some AOE attacks