feat: zone config blockers — decouple MovementManager from zone enums #42

Merged
lavarius merged 9 commits from feat/zone-config-blockers into master 2026-03-29 23:49:40 +00:00
Collaborator

What & Why

Replaces the hard-coded Outside / Inside / Booth / StartScene enum with a data-driven ZoneConfig ScriptableObject, fully decoupling MovementManager from zone naming. Zone triggers now publish capability data; movement code just queries what's currently blocked.


New types

File Purpose
ZoneBlocker.cs Enum: Jump, AutoSprint, AccelerationMovement
ZoneConfig.cs ScriptableObject: int weight + List<ZoneBlocker> blockers

Create Zone Config assets via Assets → Create → Lava Overlay → Zone Config.


ZoneManager (rewritten)

  • RegisterZone(config) / UnregisterZone(config) — called by trigger enter/exit
  • SetSceneDefault(config) — scene baseline set by CharacterSceneInitializer
  • ClearActiveZones() — called on scene load to flush stale trigger state
  • Overlap resolution: only configs at the highest weight apply; their blockers are unioned
  • IsBlocked(ZoneBlocker) — single query point for all consumers

MovementManager

  • Base class: ZoneInfluencedMonoBehaviour
  • Jump() — guarded by IsBlocked(Jump)
  • ShouldSprint!IsBlocked(AutoSprint) || Sprinting
  • Movement() — branches on IsBlocked(AccelerationMovement)

Other changes

  • AnimationControllerZoneInfluenced removed, zone override methods removed, SetZones() direct API kept
  • CharacterZoneChangerOnTriggerStay + blocks list replaced with OnTriggerEnter/OnTriggerExit; field is now ZoneConfig
  • CharacterSpawnPointDefaultZone is now a ZoneConfig reference
  • CharacterSceneInitializerApplyZone calls ZoneManager instead of SetZone on components
  • ZoneInfluenced.csdeleted

Migration

For each CharacterZoneChanger in the scene:

  1. Create a ZoneConfig asset with the appropriate weight and blockers
  2. Assign it to the Zone Config field on the trigger GameObject

For each CharacterSpawnPoint:

  1. Create or reuse a ZoneConfig asset for the scene's default zone
  2. Assign it to Default Zone
## What & Why Replaces the hard-coded `Outside / Inside / Booth / StartScene` enum with a **data-driven `ZoneConfig` ScriptableObject**, fully decoupling `MovementManager` from zone naming. Zone triggers now publish capability data; movement code just queries what's currently blocked. --- ## New types | File | Purpose | |---|---| | `ZoneBlocker.cs` | Enum: `Jump`, `AutoSprint`, `AccelerationMovement` | | `ZoneConfig.cs` | ScriptableObject: `int weight` + `List<ZoneBlocker> blockers` | Create Zone Config assets via **Assets → Create → Lava Overlay → Zone Config**. --- ## ZoneManager (rewritten) - `RegisterZone(config)` / `UnregisterZone(config)` — called by trigger enter/exit - `SetSceneDefault(config)` — scene baseline set by `CharacterSceneInitializer` - `ClearActiveZones()` — called on scene load to flush stale trigger state - **Overlap resolution**: only configs at the **highest weight** apply; their blockers are unioned - `IsBlocked(ZoneBlocker)` — single query point for all consumers --- ## MovementManager - Base class: `ZoneInfluenced` → `MonoBehaviour` - `Jump()` — guarded by `IsBlocked(Jump)` - `ShouldSprint` — `!IsBlocked(AutoSprint) || Sprinting` - `Movement()` — branches on `IsBlocked(AccelerationMovement)` --- ## Other changes - `AnimationController` — `ZoneInfluenced` removed, zone override methods removed, `SetZones()` direct API kept - `CharacterZoneChanger` — `OnTriggerStay` + `blocks` list replaced with `OnTriggerEnter`/`OnTriggerExit`; field is now `ZoneConfig` - `CharacterSpawnPoint` — `DefaultZone` is now a `ZoneConfig` reference - `CharacterSceneInitializer` — `ApplyZone` calls `ZoneManager` instead of `SetZone` on components - `ZoneInfluenced.cs` — **deleted** --- ## Migration For each `CharacterZoneChanger` in the scene: 1. Create a `ZoneConfig` asset with the appropriate `weight` and `blockers` 2. Assign it to the `Zone Config` field on the trigger GameObject For each `CharacterSpawnPoint`: 1. Create or reuse a `ZoneConfig` asset for the scene's default zone 2. Assign it to `Default Zone`
feat: zone config blockers system, decouple MovementManager from zone enums
Some checks are pending
Tests / Run EditMode Tests (pull_request) Waiting to run
e3856c418c
Replace named zone types (Outside/Inside/Booth/StartScene) with a
data-driven ZoneConfig ScriptableObject carrying a weight and a list
of ZoneBlocker enum values.

New files:
- ZoneBlocker.cs      — enum: Jump | AutoSprint | AccelerationMovement
- ZoneConfig.cs       — ScriptableObject: weight + List<ZoneBlocker>

ZoneManager (rewritten):
- Tracks active configs via RegisterZone/UnregisterZone (trigger enter/exit)
- SetSceneDefault sets the scene baseline; ClearActiveZones resets on load
- Recalculate() unions blockers from all configs at the highest weight
- IsBlocked(ZoneBlocker) is the single query point for all consumers

MovementManager:
- No longer inherits ZoneInfluenced; base class is now MonoBehaviour
- Jump()        : IsBlocked(Jump) guard
- Movement()    : branches on IsBlocked(AccelerationMovement)

AnimationController:
- No longer inherits ZoneInfluenced; base class is now MonoBehaviour
- Zone-specific Start/resetZones/Set*Zone overrides removed; SetZones()
  public API retained for direct calls from outside

CharacterZoneChanger:
- Removed blocks list + OnTriggerStay pattern
- OnTriggerEnter -> RegisterZone, OnTriggerExit -> UnregisterZone
- Field: ZoneConfig zoneConfig (assign ScriptableObject in Inspector)

CharacterSpawnPoint / CharacterSceneInitializer:
- DefaultZone is now ZoneConfig instead of zoneTypes enum
- ApplyZone calls ZoneManager.ClearActiveZones + SetSceneDefault

ZoneInfluenced deleted.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
refactor: ZoneConfig as inline [Serializable] class, not ScriptableObject
Some checks failed
Tests / Run EditMode Tests (pull_request) Failing after 12m28s
d6dbb509cc
Config lives directly on CharacterZoneChanger and CharacterSpawnPoint
in the Inspector — no separate .asset files needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: remove stale resetZones() call from RagdollController
All checks were successful
Tests / Run EditMode Tests (pull_request) Successful in 14m31s
16356673dd
AnimationController no longer has zone awareness, so the post-ragdoll
animation layer reset via resetZones() is gone. Removed the
_animationController field and its only usage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: reliable input init via coroutine, reset stale inputSystemInitialized
Some checks failed
Tests / Run EditMode Tests (pull_request) Has been cancelled
5e96ae9045
Two bugs fixed:
- inputSystemInitialized is [SerializeField] and could be saved as true
  in the prefab, causing InitializeInputSystem to bail out immediately.
  Reset it in Awake() to guarantee a clean state every run.
- The event + IsReady check had a same-frame race: InputSystemSpawner
  could fire Start() (setting IsReady=true and invoking the event)
  before MovementManager subscribed, AND MovementManager's subsequent
  IsReady check could still see false depending on execution order.
  Replaced with a simple polling coroutine that waits every frame until
  InputSystemSpawner.Instance exists and IsReady is true, then calls
  InitializeInputSystem directly. Works regardless of script order.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: sprint requires button press, not always active
Some checks failed
Tests / Run EditMode Tests (pull_request) Has been cancelled
6f00366260
ShouldSprint always true regardless of button state.

- Default (no zone): Sprinting = button press required
- Zone with Sprint blocker: sprint disabled entirely even with button

Also renamed ZoneBlocker.AutoSprint -> ZoneBlocker.Sprint since the
blocker now simply means 'this zone prevents sprinting'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
refactor: remove acceleration speed system, use static walk/run speeds
All checks were successful
Tests / Run EditMode Tests (pull_request) Successful in 13m54s
c6220134f7
Removed:
- accelerationRate, decelerationRate, maxSpeed, currentSpeed fields
- lastMoveDirection field (only needed for dot-product acceleration)
- MovementInside() and MovementOutside() methods collapsed into Movement()
- BurstMovementMath.ComputeSpeed (no longer needed)
- ZoneBlocker.AccelerationMovement (no longer two movement modes)

Movement is now simply: rotate character + move at walkingSpeed or
runSpeed depending on ShouldSprint. No acceleration ramp.

Renamed moveSpeed -> runSpeed ([FormerlySerializedAs] preserves
existing prefab values). WriteAnimationParams simplified to drop
the speedFactor that was derived from currentSpeed/maxSpeed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: right-stick-appears-to-cause-movement bug
Some checks failed
Tests / Run EditMode Tests (pull_request) Has been cancelled
6562d15e11
Root cause: Movement() called characterController.Move(moveDirection.normalized
* speed) unconditionally. Vector3.normalized turns ANY non-zero vector into a
full unit vector, so sub-threshold stick drift (values just above the deadzone
e.g. 0.13) moved the character at full walkingSpeed. When the camera was rotated
with the right stick, the drift direction rotated too — making it appear that
the right stick was causing movement.

Two-layer fix:
1. Code: added sqrMagnitude < 0.01f guard at the top of Movement() so drift
   below magnitude 0.1 is ignored before normalize can amplify it. Also skips
   RotateCharacter(), preventing the character from snapping to face the
   camera-relative drift direction.
2. Input asset: added explicit StickDeadzone(min=0.125,max=0.925) processor on
   <Gamepad>/leftStick (Move) and <Gamepad>/rightStick (Look) bindings so Unity
   filters drift at the source rather than relying solely on the global default.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fix: block air movement, preserve jump momentum
Some checks failed
Tests / Run EditMode Tests (pull_request) Has been cancelled
7cb020bb1a
Two behaviours fixed:
- Pressing sprint + stick while airborne no longer moves the character.
  moveDirection or applying any new input.
- Jumping while moving/sprinting preserves the horizontal velocity from
  take-off. Each grounded movement frame snapshots the current velocity
  into airMomentum (direction * speed). While in the air that stored
  vector is replayed via characterController.Move each frame. On landing
  airMomentum is cleared, stopping the slide.

Edge cases:
- Standing still and jumping: airMomentum is zero, no movement in air.
- Sprint released mid-air: momentum was captured at take-off, unaffected.
- Sprint button pressed mid-air: ignored until landing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fbx meta updated for some reason
All checks were successful
Tests / Run EditMode Tests (pull_request) Successful in 14m9s
15b80b3a0c
lavarius merged commit 1fe105218e into master 2026-03-29 23:49:40 +00:00
lavarius deleted branch feat/zone-config-blockers 2026-03-29 23:49:46 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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
lavarius/ProjectOverlay!42
No description provided.