6.0.0-3D-Surface (Wave A.2 spike): GridPositioner3D camera ray-cast helper. This is a spike, not a production positioner. It validates the highest-risk piece of the 3D surface (Camera3D ray → GridMap cell) end-to-end before committing to the full Wave B/C/D plan. What it does: given a Camera3D, a GridMap, and a screen-space cursor position, returns the GridMap cell the camera is looking at (or null if the ray misses the grid). What it does NOT do: full 2D-style positioner lifecycle, mode gating, multi-camera, recenter, keyboard nav, rotation, etc. Those are Wave B/C/D work; the spike is the math, not the surface. Math: Camera3D.project_ray_origin(screen_pos) + project_ray_normal(screen_pos) gives the world-space ray. We intersect it with the y=0 (or the configured ground plane) and use GridMap.local_to_map(world_hit) to resolve the cell. GridMap is a static body in Godot 4.6; we can also use PhysicsServer3D.space_get_direct_state().intersect_ray() for a more accurate hit (catches diagonal/blocked grids). 6.0.0 host + session pattern: this spike does NOT extend PlacementNode2D / PlacementNode3D. It is a stand-alone Node3D helper; the eventual GridPositioner3D (Wave B) will wire it into the host's _input dispatch via the same pattern as GridPositioner2D (which is also a stand-alone Node2D, not a PlacementNode2D).
Source: addons/grid_placement/systems/grid_targeting/grid_positioner/3d/grid_positioner_3d_spike.gd
Syntax
class GridPositioner3DSpike extends Node3DMembers
| Name | Kind | Summary |
|---|---|---|
camera | Property | The camera that the spike ray-casts through. Set this at _ready() in your test/scene; the spike does not auto-discover. |
grid | Property | The grid the spike resolves cells on. Same pattern as `camera`. |
ground_plane_y | Property | The y-coordinate (in grid-local space) of the ground plane the ray intersects. Default 0.0 = top face of the cell layer at y=0. |
SPIKE_MISS | Field | Sentinel returned when the ray misses the grid. The test asserts on `== SPIKE_MISS` rather than `== null` to make the contract explicit and to avoid Godot's null-Variant ambiguity. |
last_ray_origin | Property | World-space ray of the most recent screen-to-cell call. The positioner mirrors it to the targeting state so hover identity resolves the record the ray hit, not the oldest record overlapping the cell column. |
last_ray_dir | Property | |
surface_height_source | Property | Surface-height source for cursor ground hits: a Callable taking a Vector3i column cell (x, 0, z) and returning the world-space surface height (float), or null when the column has no ground. When valid, ground hits march the ray against these heights instead of the flat [member ground_plane_y] seed plane; when invalid the legacy plane math runs exactly as before. The 3D positioner wires the live placement support surface so the cursor and commits agree on "the ground". |
SURFACE_MARCH_MAX_STEPS | Field | Hard cap on marched columns per ground hit (failsafe; horizon-grazing rays over empty columns would otherwise march to the far plane). |
SURFACE_CELL_EPSILON | Field | A surface caps the cell below it: crossings are mapped a hair under the surface so row-boundary tops (cube faces) resolve the item underneath instead of the empty row above, regardless of float noise. |
VOLUME_CORE_EPS | Field | Step past the shrunk-box entry when mapping a volume hit to its cell (then clamped back inside, so oblique rays cannot punch through a thin box into the far neighbor). |
VOLUME_SHRINK_MIN_SIZE | Field | Volumes thinner than this after shrinking keep the legacy entry+nudge reading: there is no core to re-enter. |
ray_from_screen_to_cell | Method | |
ray_from_screen_to_cell_occluded | Method | |
ray_origin | Property | |
ray_normal | Property | |
cell_from_ray | Method | |
dir | Property | |
world_to_grid | Property | |
best_volume_t | Property | |
best_volume_cell | Property | |
volume | Property | |
entry | Property | |
t | Property | |
owner | Property | |
ground_cell | Property | |
ground_t | Property | |
grid_origin | Property | |
grid_normal | Property | |
marched | Property | |
plain | Property | |
t | Property | |
candidate | Property | |
world_hit | Property | |
cell_size | Property | |
pos | Property | |
d | Property | |
xi | Property | |
zi | Property | |
step_x | Property | |
step_z | Property | |
t_delta_x | Property | |
t_delta_z | Property | |
frac_x | Property | |
frac_z | Property | |
t_max_x | Property | |
t_max_z | Property | |
t | Property | |
steps | Property | |
saw_height | Property | |
t_next | Property | |
y_enter | Property | |
y_exit | Property | |
h_world | Property | |
h_local | Property | |
d_enter | Property | |
d_exit | Property | |
tc | Property | |
local_hit | Property | |
map_hit | Property | |
candidate | Property | |
world_hit | Property | |
world_t | Property | |
ray_intersection_point | Method | |
ray_ground_tracking_point | Method | |
ray_from_screen_to_cell_or_null | Method |