Skip to content

Void quest: Add Void retreat transition - #2714

Open
manuq wants to merge 2 commits into
mainfrom
void-receding
Open

Void quest: Add Void retreat transition#2714
manuq wants to merge 2 commits into
mainfrom
void-receding

Conversation

@manuq

@manuq manuq commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

In both the Void runner and closing transition.

manuq added 2 commits August 14, 2026 11:00
Bridges and Void barriers made with `ToggleableTileMapLayer` appeared
and disappeared when toggled. This change give them an optional fade
transition, reusing the world-rewoven effect.

The shader require several changes to be extended to work on a
`TileMapLayer` (or any other `CanvasItem`), in addition to keep
working on a `CanvasGroup`. And now it works better for the prior
`CanvasGroup` case too.

Toggleable transition

Add `transition_duration` to `ToggleableTileMapLayer` . When a usable
material is present it tweens the shader's `progress` parameter
instead of flipping the layer instantly.

- The state is committed halfway through the fade, so the change is
  *felt* mid-transition rather than at the end. Only
  `collision_enabled`, `navigation_enabled` and `occlusion_enabled`
  flip at the midpoint. The prior `enabled` is left until the very
  end, because it also controls rendering and turning it off early
  would hide the second half of the animation.
- Interrupting a transition doesn't reset it. Each half of the tween
  lasts in proportion to the distance it covers, so `progress` moves
  at a constant rate and a toggle that interrupts another one is
  proportionally shorter.
- The material is looked up once, in `target` first and then in the
  first ancestor `CanvasGroup`, since the material may be wrapped in
  one. This is the case for Void barriers because they already have a
  shader, the Void chromakey. It is only accepted if it is a
  `ShaderMaterial` with a `progress` parameter. Otherwise the toggle
  stays instant.

In the `Toggleable` base class, `set_toggled()` now has an `immediate`
parameter, and `initialize_with_value()` passes `true`. This is to
keep the initialisation immediate on scene entry.

World rewoven shader changes

Before the effect was for a `CanvasGroup` to create cutscenes. Now
it's extended to serve both cases.

- Add `target_canvas_group` toggle for the two cases.
- The mask rect is now explicit, sampled from world by new
  `mask_origin` / `mask_size` uniforms, instead of by `UV`. Because on
  a `TileMapLayer` the UV is the coordinate into the tileset *atlas*
  for each tile, so the mask was repeating on every single tile. The
  `mask_texture` also gained `repeat_disable` so the region clamps
  rather than wrapping.
- Drop `render_mode unshaded`. The engine only applies a
  `CanvasModulate`'s color and 2D lights to items that are not
  unshaded, so the layer stayed untinted while the rest of the scene
  darkened.
- Fix `progress` extremes with a threshold, so 0 hides every pixel and
  1 shows every pixel regardless of what the mask contains. In
  between, the mask still shapes the wipe. Previously, pixels at the
  mask minimum value stayed invisible at `progress = 1`.
- Make burn look a bit more as light. The new `canvas_modulate`
  uniform (which unfortunately has to be passed, matching the scene)
  divides out the scene tint so the burn keeps full brightness, and
  the default `burn_color` is now brighter than white. This is a
  detail: when not passed the effect still looks ok. Check
  custom_hookable_objects_test.tscn for a scene that uses it.

New TileMapMaskBounds helper node

Because the mask is now positioned in world units, something has to
supply the rect. This behavior node computes the mask rect from
`get_used_rect()` of the TileMapLayers in its target (itself and any
descendants) and writes `mask_origin` / `mask_size` into the shader
material. It has an "Update bounds" button to apply it after tile
edits.

Note: only TileMapLayer nodes are considered (wouldn't work for
WorldNew / WorldOld in cutscenes). Sprite2Ds and other CanvasItems are
ignored because Godot doesn't have a general method to obtain bounds
on them. This is surfaced as a configuration warning when no tile
layer is found.

Add BaseCanvasItemBehavior and refactor ModulateAsSkyBehavior to use
it, plus this new behavior above.

Scene changes

Transitions applied to existing toggleable layers, each paired with a
TileMapMaskBounds:

- `frays_end.tscn`: Dev Archipelago bridge fixed / broken. Also updated waiters in the townie dialogue lines to out-last the new bridge transition.
- `frays_end.tscn`: Void barrier (same style as in linenville below).
- `song_sanctuary_path.tscn`: The side-quest bridge fixed / broken.
- `grapple_gym_2.tscn`: The bridge that appears (I had to initialize it in the scene script).
- `linenville_path.tscn`: The Void barrier. For this one I used a noise texture and a different burn color, because it's not actually a rewoven, it's a "void cleared" effect.
- `custom_hookable_objects_test.tscn` and `custom_repellable_objects_test.tscn`: The fence doors.

Also the two `world_rewoven_cutscene_*.tscn` scenes were updated for
the new uniforms (`target_canvas_group`, `mask_origin`, `mask_size`,
`canvas_modulate`, new `burn_color`).
In both the Void runner and closing transition.
@manuq

manuq commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Stacked on top of #2699

@manuq
manuq marked this pull request as ready for review August 14, 2026 18:56
@manuq
manuq requested a review from a team as a code owner August 14, 2026 18:56

func repel_void() -> void:
whole_scene_camera.priority += 20
await void_layer.uncover_all(3.0)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we go with this, should we remove TileMapCover.uncover_all() ??

@github-actions

Copy link
Copy Markdown

Play this branch at https://play.threadbare.game/branches/endlessm/void-receding/.

(This launches the game from the start, not directly at the change(s) in this pull request.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant