namespace GodotHelpers.Raycasts; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Godot; using Godot.Collections; using SJK.Functional; /// /// Extensions for . /// Allows for an static way of casting an godot Raycast3D. /// public static class RaycastExtensions { // --- 3D --- public static RaycastResult3D? RaycastEx(this PhysicsDirectSpaceState3D space, Vector3 from, Vector3 to, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false) { var query = new PhysicsRayQueryParameters3D { From = from, To = to, CollisionMask = collisionMask, HitFromInside = hitFromInside, }; if (exclude != null) query.Exclude = new Array(exclude); var result = space.IntersectRay(query); if (result.Count == 0) return null; return new RaycastResult3D( Collider: result["collider"].AsGodotObject(), ColliderId: result["collider_id"].AsInt32(), Rid: (Rid)result["rid"], Shape: result["shape"].AsInt32(), Position: result["position"].AsVector3(), Normal: result["normal"].AsVector3() ); } public static bool RaycastHitEx(this PhysicsDirectSpaceState3D space, Vector3 from, Vector3 to, [NotNullWhen(true)] out RaycastResult3D hit, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false) { hit = space.RaycastEx(from, to, collisionMask, exclude, hitFromInside)!; return hit is not null; } // --- 2D --- /// /// Extensions for . /// Allows for an static way of casting an godot Raycast3D. /// public static RaycastResult2D? RaycastEx(this PhysicsDirectSpaceState2D space, Vector2 from, Vector2 to, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false) { var query = new PhysicsRayQueryParameters2D { From = from, To = to, CollisionMask = collisionMask, HitFromInside = hitFromInside, }; if (exclude != null) query.Exclude = new Array(exclude); var result = space.IntersectRay(query); if (result.Count == 0) return null; return new RaycastResult2D( Collider: result["collider"].AsGodotObject(), ColliderId: result["collider_id"].AsInt32(), Rid: (Rid)result["rid"], Shape: result["shape"].AsInt32(), Position: result["position"].AsVector2(), Normal: result["normal"].AsVector2() ); } public static IOption RaycastOptionEx(this PhysicsDirectSpaceState2D space, Vector2 from, Vector2 to, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false) => RaycastEx(space, from, to, collisionMask, exclude, hitFromInside).ToOption(); public static bool RaycastHitEx(this PhysicsDirectSpaceState2D space, Vector2 from, Vector2 to, out RaycastResult2D hit, uint collisionMask = uint.MaxValue, Rid[]? exclude = null, bool hitFromInside = false) { hit = space.RaycastEx(from, to, collisionMask, exclude, hitFromInside)!; return hit is not null; } // 3D Shape Cast public static List IntersectShapeEx(this PhysicsDirectSpaceState3D space, PhysicsShapeQueryParameters3D query, int maxResults = 32) { var results = space.IntersectShape(query, maxResults); var list = new List(results.Count); foreach (var dict in results) { list.Add(new CollisionResultBase( Collider: dict["collider"].AsGodotObject(), ColliderId: dict["collider_id"].AsInt32(), Rid: (Rid)dict["rid"], Shape: dict["shape"].AsInt32() )); } return list; } // 2D Shape Cast public static List IntersectShapeEx(this PhysicsDirectSpaceState2D space, PhysicsShapeQueryParameters2D query, int maxResults = 32) { var results = space.IntersectShape(query, maxResults); var list = new List(results.Count); foreach (var dict in results) { list.Add(new CollisionResultBase( Collider: dict["collider"].AsGodotObject(), ColliderId: dict["collider_id"].AsInt32(), Rid: (Rid)dict["rid"], Shape: dict["shape"].AsInt32() )); } return list; } }