Week 34: Crawling on ceilings and reworking "corner" cases

An animated GIF of a recording from Squirrel Away showing the squirrel climbing all the way around the outside of a square.
Characters can now crawl on ceilings!

tl;dr: I added support for crawling on ceiling surfaces, and I refactored the system for calculating runtime updates to character-surface contact state.

What happened last week?


  • I added support for crawling on ceilings.
  • I refactored the system for calculating runtime updates to character-surface contact state.
  • I refactored the system for build-time climb-from-surface-to-adjacent-surface edge calculations.

Laundry list

  • Add support for characters attaching to ceiling surfaces:
    • Update cat and squirrel animators to support ceiling surfaces.
    • Fix ceiling action-handler registration.
    • Add logic for calculating jump-land-positions for ceiling surfaces.
      • This is the first step in calculating jump or fall trajectories from ceilings.
      • This involves a lot of heuristics to pick promising start-position, end-position, start-velocity combinations for a given pair of edges.
      • The resulting positions and velocity are highly dependent on the relative positioning and directions of the surfaces.
      • And there are a lot of edge cases to handle explicitly here!
    • Add support for a ceiling-crawling edge-weight multiplier.
      • Add missing support for considering ceiling surface attachment across the Surfacer codebase.
        • This had been inconsistently supported before, since I’d as-of-yet never used characters that could grab ceilings.
      • Make a distinction between is_a_jump_calculator, can_hold_jump_button_at_start, and can_backtrack_on_height.
    • Add support for grabbing the ceiling using the hidden "grab" input.
    • Offset grab instructions to not happen after the edge is already finished.
    • Add support for requiring that jumps-to-ceiling calculations land while still ascending.
    • Add the let-go-of-ceiling instruction to depart-from-ceiling edges.
    • Fix the cat's crawl-on-ceiling animation speed.

A screenshot showing annotations of edge trajectories for falling from a ceiling surface.
Edge trajectories for jumping/falling from a ceiling surface.

  • Refactor the system for calculating runtime updates to character-surface contact state:
    • Fix a regression with player horizontal-facing direction when climbing some walls.
    • Added support for rounding convex corners and tracking the corresponding surface-state changes.
      • Refactor the surface_state touch/grab/contact state update sequence.
        • Consolidate surface_state update calls.
          • There used to be a separate call for updating surface_state after processing input for the frame and a separate call for updating surface-state after processing movement for the frame.
        • Refactor surface_state contact tracking:
          • Maintain a custom collection of `SurfaceContact` references.
          • Only ever invoke `get_slide_count()`--Godot’s collision querying API--once per frame at max.
          • Bypass Godot’s collision API if rounding a corner.
          • Bypass Godot’s collision API if `bypasses_runtime_physics` is enabled.
        • Update surface_state to explicitly clear just-changed flags each frame, rather than using an preserves_just_changed_state param.
          • Rename "touches" to "contacts".
            • Store a `character` reference on surface_state instead of piping it through method calls.
            • Add action-handlers for updating the character's position in order to hug the corner when crawling around a convex corner.
            • Rename climb_over_wall_corner_calc_shape to rounding_corner_shape.
            • Fix bug with character-offset calculation when calculating just-changed-surface-while-rounding-corner flags.
            • Fix bug with detecting whether we're triggering explicit floor grabs.
            • Fix a bug with falling off of wall surfaces after rounding corners.
            • Fix a bug with rounding-corner-from-wall-to-floor trajectory.
            • Add support for distinguishing between whether we are rounding a corner on the side of the previous surface.
            • Update is_rounding_corner to only consider is_still_triggering_previous_surface_grab_since_rounding_corner when rounding the corner along the side of the previous surface.
            • Distinguish between explicit and implicit surface-grab triggers, and use this to fix issues with some "corner" cases.
          • Refactor the system for build-time climb-from-surface-to-adjacent-surface edge calculations:
            • Add climb-to-neighbor-surface edge and calculator.
            • Remove old edges and calculators:
              • walk-to-ascend-wall-from-floor
              • climb-over-wall-to-floor
              • climb-down-wall-to-floor
            • Fix some bugs with climb-to-neighbor-surface-edge trajectory calculations.

          A screenshot showing annotations of edge trajectories around outside and inside corners.
          Edge trajectories around outside and inside corners (across adjacent surfaces).

          • Miscellaneous:
            • Add back in support for handling tile-map-coord calculations for collisions with erroneous backwards normals.
              • This is an interesting/annoying quirk of Godot's collision engine.
              • When colliding with a corner between two sides of a tile, Godot's collision APIs can sometimes get confused about the direction of the surface normal (that is, which side of the tile the surface is on). It sometimes returns the opposite direction.
              • I think think bug happens because even though the character is moving away from the surface rather than into the surface, it's still hitting the corner, and Godot consequently thinks the character is colliding with the surface that it's actually moving away from.
            • Fix an issue with fall-from-floor trajectory calculations not correctly accounting for max horizontal speed.
            • Adjust checkmark draw utility to show a better shape.
            • Fix text alignment in the ruler annotator.
            • Fix cat animator scale reset.
            • Decouple player/npc trajectory annotator properties.
              • Fix a bug with how get_collision_tile_map_coord handles Godot-collision false-positives.
                • Update get_surface_for_tile usages to be robust to Godot-collision false-positives.
                  • Update Level annotator to also toggle background visibility.
                    • Update Momma Duck for latest framework changes.
                    • Add custom overlay and slider nine-patch textures for Momma Duck.
                    • Add a shortcut key for toggling the HUD visibility.
                    • Add a utility for resizing a string, no matter whether increasing or decreasing the size.
                    • Fix surface annotation offset.
                    • Add an exponential decay to the surface-annotation depth fade.
                    • Increase surfaces annotator opacity.
                    • Embed the crypto_uuid_v4 addon within scaffolder.
                      • This way the consumer doesn't need to worry about including it separately.

                  What's next?

                  • Finish making a few other systems work with the new ceiling support and the new surface-state calculations—for example: bypassing runtime physics.
                  • Fix a handful of small bugs on my current backlog.
                  • Add support for fall-through floors and walk-through walls.
                    • These are the kinds of surfaces that you can either stop on or pass through, depending on what buttons you're pressing.
                    • A lot of platformers have thin platforms like this.
                    • You can usually always jump from below.
                  • I have plans for adding some basic flying-character movement, but I probably won't get started on that until after next week!

                  🎉 Cheers!

                  This is a simple icon representing my sabbatical.