Hole Game

v0.9-tuning
Latest

Snappier gravity + live-tunable debug panel · Things finally fall like they mean it. Unity gravity is bumped to 25 m/s² (~2.5× Earth) for the play session, plus a per-absorbable supplemental boost (+12 m/s² flat, plus up to +8 for the smallest items) so cones and signs feel snappier than buildings even though real physics would give them all the same acceleration. A new debug tuning panel (toggle with the backquote / `~` key) exposes sliders for every knob — tweak gravity, growth scale, hole speed, all live mid-match without rebuilding. A spatial-hash registry replaces every per-frame `FindObjectsByType` call so adding more objects no longer scales bot decision-making linearly.

Build notes

Gravity rebalance

  • PrototypeGameManager.Awake now sets Physics.gravity = (0, -25, 0) for the play session — 2.5× Earth. Project setting unchanged; the override only applies while the scene is playing, then resets when you stop.
  • Per-absorbable supplemental gravity in AbsorbableObject.FixedUpdate: body.AddForce(Vector3.down * (GravityBoost + smallnessBoost), ForceMode.Acceleration). GravityBoost is +12 m/s² flat; smallnessBoost ramps from 8 (smallest tier, requiredHoleRadius = 0.10) to 0 (largest, 1.40) via Mathf.Lerp + InverseLerp.
  • Total felt acceleration: cones ~45 m/s², boxes ~44, signs ~42, cars ~40, buildings ~37. About 4× Earth on small stuff, ~3.7× on buildings — buildings still topple gradually enough to read as 'falling over,' but cones get yanked into the void without hanging in the air.
  • All knobs are public static on AbsorbableObject with a RuntimeInitializeOnLoadMethod reset hook so values can't leak across play sessions even when tuned via the panel.

Debug tuning panel

  • New DebugTuningPanel component on _GameManager. IMGUI window in the top-right, draggable by title, scrollable, hidden by default — toggle with **~** (backquote) via Input System.
  • Sliders: gravity boost (0–30), smallness boost (0–20), Unity gravity (1–50), player growth scale (0.05–2), player max speed (1–20). Each row shows label / slider / current value with units.
  • Live-readout section: hole radius, score, active absorbable count.
  • Reset to defaults button hands all values back to the canonical 12 / 8 / 25 / 0.5 / 9.
  • HoleGrowthSystem.GrowthScale and HoleController.MaxSpeed exposed as public properties (clamped to ≥ 0) so the panel can write to them without reflection.

Performance: AbsorbableRegistry

  • New static spatial-hash (8 m cells) over all alive absorbables. Register on Awake, Unregister on OnDestroy, UpdateCell each FixedUpdate while the body is active.
  • BotController.ChooseTarget was calling FindObjectsByType<HoleActor> and FindObjectsByType<AbsorbableObject> every 0.35 s × 3 bots — scene-wide enumeration on every decision tick. Now it reads PrototypeGameManager.Actors for rivals and AbsorbableRegistry.QueryEligible(pos, 18m, holeRadius) for cubes. Sqr-distance comparisons throughout.
  • CityCompletionTracker.ScanScene reads AbsorbableRegistry.All instead of FindObjectsByType. Constant time per absorbable rather than scene-wide cost.
  • Bots become local hunters (18 m radius) rather than scene-wide enumerators. Behaviorally identical at normal play scales; the win is that adding 500+ objects in future versions won't make decision ticks crawl.

Wake-fix tightening

  • v0.8 dropped rebuildMoveThreshold to 0 (always rebuild every FixedUpdate). v0.9 calibrates it back to 0.2 m / 0.04 m radius — the per-frame mesh upload + PhysX recook was leaving budget on the table.
  • The new trick: refresh lastCenters *only* when a rebuild actually fires (not every CollectHoles tick). PrevCenter therefore equals the last *rebuilt* hole position, and the existing swept-cull at the next rebuild covers the entire motion arc since then — no missed cells in the gap-frames.
  • Net: roughly half the recook cost of v0.8's always-rebuild without giving up the wake-bug fix.

Spawn placement & defensive cleanup

  • PrototypeSceneBuilder.TryReservePlacement reserves AABBs as items spawn so absorbables don't overlap and explode under PhysX depenetration. Per-tier offset budgets: props 2.6 m, vehicles 3.5 m, seeds 1 m, buildings 0.
  • On all-attempts-failed, falls back to the base position rather than silently destroying the item. Earlier behaviour deleted props that couldn't find a clean spot inside their block — entire corner-prop sets were going missing in dense layouts.
  • AbsorbableObject.NormalizeRestingCollider lifts a BoxCollider whose local bottom dipped below 0.02 — defensive against any future spawn whose pivot lands below ground (the FBX-from-Blender pivot bug class).

Optional: dormant absorbables (off by default)

  • AbsorbableObject.startDormant (default false) plus ActivatePhysics / CanActivateForHole / SetDormant machinery, wired via GroundTileManager.WakeBodiesNearHoles. Set per-instance to freeze a body until a hole comes near.
  • Default off so 'physics from start' stays the headline feel — buildings can still tip from edge effects in v0.9 just like v0.8. Ready as opt-in for any specific body you want frozen until contact.