Entrance arrow sinks below the water on a submerged doorstep #132

Open
opened 2026-09-27 20:10:35 +01:00 by liamjd · 0 comments
Owner

The entrance arrow drawn during building placement sinks below the water when the doorstep cell is submerged.

Cause

PlacementController positions the arrow with map.cell_to_world(doorstep_cell), and cell_to_world() uses level_at(), which for a water tile is the seabed. _paint_cells() draws water at the datum, so the arrow ends up under the visible surface by however deep the seabed is.

#46 (PR #131) added TerrainGrid.drawn_level_at() for exactly this and moved the tile highlight and ghost height onto it. The arrow was left out because it goes through cell_to_world(), which has other callers.

Why not just change cell_to_world()

Its other callers mostly want the terrain itself, not the visible surface:

  • find_path() and random_walkable_position() in terrain_grid.gd, plus pawns.gd:205: pawn movement. Water is unwalkable, so these never see a water cell today, but changing them should be a deliberate choice rather than a side effect.
  • BuildingSite (building_site.gd:31), toast camera targets (toast_message.gd) and tools/screenshot_entrance_arrow.gd.

Changing cell_to_world() might turn out to be correct, since its doc comment says "sitting exactly on its top face", and for water the visible top face is the datum. But that decision should cover every caller, not just be made for the sake of the arrow.

Options

  1. Narrow fix: in PlacementController, keep X/Z from cell_to_world() and take Y from surface_y(drawn_level_at(doorstep_cell)) (converted to global). Mirror the change in tools/screenshot_entrance_arrow.gd.
  2. Broad fix: make cell_to_world() use drawn_level_at() and review every caller above. level_at() stays the query for terrain reasoning.

Acceptance criteria

  • With the doorstep over water, the arrow hovers arrow_hover_height above the visible water surface.
  • On dry land the arrow position is unchanged.
  • A test covers the chosen seam: for option 1, the arrow's Y over a forced-submerged doorstep; for option 2, cell_to_world() over a forced-submerged cell, using the _levels technique from test_terrain_drawn_level.gd.
The entrance arrow drawn during building placement sinks below the water when the doorstep cell is submerged. ## Cause `PlacementController` positions the arrow with `map.cell_to_world(doorstep_cell)`, and `cell_to_world()` uses `level_at()`, which for a water tile is the **seabed**. `_paint_cells()` draws water at the datum, so the arrow ends up under the visible surface by however deep the seabed is. #46 (PR #131) added `TerrainGrid.drawn_level_at()` for exactly this and moved the tile highlight and ghost height onto it. The arrow was left out because it goes through `cell_to_world()`, which has other callers. ## Why not just change `cell_to_world()` Its other callers mostly want the terrain itself, not the visible surface: - `find_path()` and `random_walkable_position()` in `terrain_grid.gd`, plus `pawns.gd:205`: pawn movement. Water is unwalkable, so these never see a water cell today, but changing them should be a deliberate choice rather than a side effect. - `BuildingSite` (`building_site.gd:31`), toast camera targets (`toast_message.gd`) and `tools/screenshot_entrance_arrow.gd`. Changing `cell_to_world()` might turn out to be correct, since its doc comment says "sitting exactly on its top face", and for water the visible top face is the datum. But that decision should cover every caller, not just be made for the sake of the arrow. ## Options 1. **Narrow fix:** in `PlacementController`, keep X/Z from `cell_to_world()` and take Y from `surface_y(drawn_level_at(doorstep_cell))` (converted to global). Mirror the change in `tools/screenshot_entrance_arrow.gd`. 2. **Broad fix:** make `cell_to_world()` use `drawn_level_at()` and review every caller above. `level_at()` stays the query for terrain reasoning. ## Acceptance criteria - With the doorstep over water, the arrow hovers `arrow_hover_height` above the visible water surface. - On dry land the arrow position is unchanged. - A test covers the chosen seam: for option 1, the arrow's Y over a forced-submerged doorstep; for option 2, `cell_to_world()` over a forced-submerged cell, using the `_levels` technique from `test_terrain_drawn_level.gd`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
liamjd/UntitledColonyBuilder#132
No description provided.