Week 31: Surfacer player configuration improvements and bug fixes

A simple vector image showing a jump navigation trajectory from one platform to another and landing on a bug.
I did a lot of not-visually-interesting Surfacer debugging.
So... here's a descriptive icon showing a bug being jumped on!

tl;dr: Last week I made assorted Surfacer player improvements—I made configuration patterns easier-to-use and more powerful, and I fixed lots of small bugs.

What happened last week?


  • I started creating a new BehaviorController system.
    • This will make it easier to define high-level movement behavior for characters.
    • More on this next week!
  • I split-apart my Player logic.
    • I split things into the bits that are specific to Surfacer-auto-navigation-logic and the bits that aren't.
    • I moved the Surfacer-agnostic classes into Scaffolder, and updated the Surfacer-specific classes to extend them.
    • This makes it a lot easier for me to create new players that don't use automatic platform navigation (like the vertically-crawling spiders in Momma Duck).
  • I fixed lots of small bugs.

Laundry list

  • Refactor how “fake_players” are used.
    • Instead of instantiating actual Player classes for collision tests during trajectory calculations, I now create a new, simpler FakePlayer class with only a couple convenience fields for matching shape state from the base-Player class.
    • This lets me simplify some logic in the main Player classes.
  • Rename “fake_players” to “crash_test_dummies”.
  • Add a bunch of doc comments, using the upcoming v4.0 syntax.
  • Rename the screen Navigation and the surface Navigator classes to be more descriptive.
  • Spent most of the day trying to debug an inconsistency with collision-detection during calculation of an edge between run-time and build-time.
    • This was a very slight difference--I was only seeing/not-seeing the collision in the final frame of movement for the edge.
    • But this was causing that frame to not be included in the distance calculation sometimes.
    • And I double-check distance calculations to make sure edges are calculated as expected, so I was seeing an error for this.
    • I can add a very simple work-around for this, by just conditionally including a small increase in the distance calculation, depending on whether a collision was detected in the final frame.
    • BUT, that side-steps the underlying problem, which is that Godot’s collision-detection system is behaving differently at build time and at run time!
      • Unfortunately, I have no idea what could be causing the inconsistency here.
      • And I have already spent way too much time looking at this.
      • So I’m going to ignore the underlying problem for now, and re-visit if it manifests in another way later on.
  • Fix an issue with the last-frame of an edge calculation sometimes being omitted due to a detected collision.
  • Discovered that Godot’s `move_and_collide` often returns `KinematicCollision2D` values that correspond to backwards `travel`.
  • Add configuration support for opening the app straight to a given level ID when debugging things.
  • Clean up how debugging-parameter-overrides can be overridden when not in a debug or playtest mode.
  • Refactor PlayerSurfaceState to use two separate update methods.
    • This lets me update some surface-contact state immediately after calling move_and_slide--at the end of the frame, rather than at the beginning.
    • This means that any queries of this state that are triggered from events other than the standard _physics_process frame-update will see fresher/more-accurate state.
  • Add support for tracking surface-contact state for all collisions, rather than only for the grabbed surface.
  • Add support for detecting when a player has reached the end of an intra-surface edge because they collided with a concave neighbor instead of passing the destination position.
  • Update Choreographer zoom to use a multiplier.
  • Decrease range of window for panning camera during navigation preselection.
  • Simplify some player-creation logic.
  • Fix a bug with multi-surface-touch calculations.
  • Implement MoveBackAndForthPlayer.
  • Use MoveBackAndForthPlayer for Porcupine.
  • Replace custom-Momma-Duck-is_logging_events checks with SurfacerPlayer._log_player_event.
  • Support filtering between low-level surfacer events and higher-level game-player events with _log_player_event.
  • Standardize exclamation-mark configuration in SurfacerPlayer, and remove this redundant logic from Momma Duck players.
  • Re-arrange some initialization logic for common scenes when running in-editor, in order to reduce logged errors due to too-early access of AutoLoads.
  • Create a new ScaffolderPlayer.
  • Move SurfacerPlayerAnimator to into Scaffolder as ScaffolderPlayerAnimator.
  • Move ProximityDetector into Scaffolder.
  • Move logic from SurfacerPlayer into ScaffolderPlayer.
  • Rename labeled-control-list to control-row.
  • Update stale links in README files and other markdown files.
  • Update Spider to extend ScaffolderPlayer.
  • Move player-handling logic from Surfacer to Scaffolder.
  • Move annotator logic into Scaffolder.
  • Split apart Surfacer-specific annotator logic and refactor the annotator system to conditionally use Scaffolder vs Surfacer versions as needed.
  • Add the duckling peep back in.
  • Rename Squirrel Away HTML export from "squirrel-away" to "index".
    • This is a more standard name and makes it easier to publish in various places like itch.io.
  • Add concept of player behavior mode--e.g, “rest”, “follow”, “run-away”, “user-navigate”, “custom”.
    • This will be useful as I create standard high-level player behavior utilities, and I need to keep track of how to transition between which behaviors at which times.
  • Fix the how the Spider animator is configured with its non-standard sprite names.
  • Create a new BehaviorController system.
    • Before, I thought I might be able to get away with a class-inheritance approach, with something like a MoveBackAndForthPlayer subclass.
    • However, I was running into problems trying to then add support for a run-away high-level behavior, that would also then return to the starting position afterward, and would also then mix-and-match nicely with the move-back-and-forth behavior.
    • So, this new approach uses composition instead.
    • Only a single BehaviorController is active at a time, and it can transition to whichever other behavior is needed when it’s done or when it’s interrupted.
  • Create placeholders for new BehaviorListener subclasses.
  • Create a new life-cycle event for BehaviorListener classes, `_on_ready_to_move`.
  • Update both Momma Duck and Squirrel Away for latest Scaffolder and Surfacer changes.

What's next?

  • Implement lots of different BehaviorController subclasses:
    • follow
    • collide
    • run_away
    • wander
    • return
    • climb_adjacent_surfaces
    • jump_back_and_forth
  • Finish working through my current backlog of Surfacer bugs.

🎉 Cheers!

This is a simple icon representing my sabbatical.