A sphere cast sweeps a ball-shaped volume along a direction to find an obstacle.
dotnet add package RecursiveAI.OneGame.PhysicsRequires .NET 10 (net10.0); .NET 9 and earlier aren’t supported.
Fixed and FVec3 are onegame’s deterministic fixed-point number and vector types.
using OneGame.Core; using OneGame.Physics; var space = new PhysicsSpace3D(); space.AddSphere(Fixed.One, new FVec3(5, 0, 0)); bool found = space.SphereCast( FVec3.Zero, Fixed.One, new FVec3(1, 0, 0), Fixed.FromInt(10), out var hit); Console.WriteLine(found);
Prints whether the swept sphere hits a body.
TrueUnzip the example, then dotnet run.
The full program
The download creates a static sphere on layer 2 and sweeps a second sphere toward it. Both radii are one world unit. It reports the matching body and travel distance without advancing the simulation.
using OneGame.Core; using OneGame.Physics; var space = new PhysicsSpace3D(); var target = space.AddSphere( Fixed.One, new FVec3(5, 0, 0), new BodyOptions3D { Kind = BodyKind.Static, Layer = 2 }); bool found = space.SphereCast( FVec3.Zero, Fixed.One, new FVec3(1, 0, 0), Fixed.FromInt(10), out var hit, layers: 1u << 2); Console.WriteLine($"Hit: {found}"); if (found) { Console.WriteLine( $"Target: {hit.Body == target}"); Console.WriteLine( $"Distance: {hit.Distance}"); } Console.WriteLine($"Steps: {space.StepCount}");
dotnet run prints:
Hit: True Target: True Distance: 3 Steps: 0
A miss returns false and sets hit to its default value; read its fields only after a successful cast.
Variations
Use a different layer mask. Append this to the full program; it excludes the only target:
bool excluded = space.SphereCast( FVec3.Zero, Fixed.One, new FVec3(1, 0, 0), Fixed.FromInt(10), out _, layers: 1u << 1); Console.WriteLine($"Other layer: {excluded}");
Other layer: FalseRelated recipes
- Query a 3D sphere overlap in C#
- Fork 3D physics for prediction in C#
- Save and restore a 3D physics snapshot in C#
The short answer
Call PhysicsSpace3D.SphereCast with a local origin, a positive Fixed radius, a direction and a maximum distance. It returns a Boolean and one RayHit3D: the nearest matching body. The snippet at the top creates its own target, so it needs no game window, scene file or running host.
What is a sphere cast?
A sphere cast is a swept-volume query. The starting point is the sphere’s center, and the radius gives that moving volume thickness. In this example, the target’s center is five units along X. Each sphere has radius one, so the moving center travels three units before their surfaces meet. That is the distance printed by the full program, not the distance between their original centers.
The query does not add a body for the swept sphere. It asks a question of the space as it currently exists. The printed step count stays at zero because calling a query is not a simulation step. It is not a character controller: the query does not apply movement, slide along a wall or update an entity.
RayHit3D contains Body, Point, Normal and Distance. Use Body to associate the result with your game object. Keep the Boolean branch even when the sample always hits: changing the origin, direction, range or mask can produce a miss, and the default hit is not a valid substitute for a successful result.
What are the key differences between shapecast and raycast?
For this space, the choice is between a line query, Raycast, and a sphere sweep, SphereCast. Use a ray for a line of sight or a line-shaped probe. Use a sphere sweep when the query needs a radius, such as checking clearance for a ball-shaped volume. onegame’s API describes both as returning the nearest matching body. Neither method is an all-hits enumeration.
Use the dedicated Raycast method when you need a line rather than treating a zero-radius sphere as a portable raycast. onegame’s API exposes the two methods separately. Its sphere-cast signature takes a radius; the sample uses Fixed.One and a unit direction along X. It does not rely on undocumented behavior for degenerate shapes or an initially overlapping target.
The last argument is a bit mask, not a layer index. The full program places its target on layer 2 and uses 1u << 2 to select that layer. The variation selects layer 1 instead and returns false. Omitting the mask uses uint.MaxValue, selecting all layer bits. Keep this selection distinct from SetLayerCollision, which configures which body layers collide during simulation.
Positions are local to the space’s Origin. If your game rebases its world, convert the query’s starting point into that same local frame. The direction is a vector, not a second world-space point. See the 3D physics guide for the origin and fixed-point coordinate contract.