3.8 KiB
Progression
Two independent weapon progressions run at the same time, each fed by its own resource and its own fixed Pay Zone. They are not related and must not be merged into one counter.
Bat level — BatLevelC
- Currency: wood, dropped by crates (
ResourceC, spawned byBreakablePropC) and delivered into the bat's own Pay Zone. - Displayed by
WeaponHudC(the bottom-left octagon). - Added to the bat's damage per crate hit (
PlayerC.updateCombat->BreakablePropC.hit), on top of the debug panel's own basehit_damage. - Visual payoff: that Pay Zone's reward pedestal shows a floating bat
(
PlayerC.createBatDisplay).
Pistol level — PistolLevelC
- Currency: green zombie-part chunks, dropped by dying zombies
(
ZombiePartC, spawned byZombieC) and delivered into the pistol's own Pay Zone. - Displayed by
PistolHudC, stacked directly belowWeaponHudC's octagon. - Added to the pistol's base damage per shot (see
PlayerC.fireAt). - Visual payoff:
WeaponAuraC, an additiveSpriteglow on the drawn pistol that grows with the level and flattens out at its ownMAX_EFFECT_LEVEL. ASpritespecifically becauseCharacter_Pistolis aSkinnedMesh(a same-geometry overlay would need re-binding to the skeleton) and because a light would do nothing against unlit materials. - That Pay Zone's reward pedestal shows a floating pistol
(
PlayerC.createPistolDisplay).
Both createBatDisplay/createPistolDisplay share one private helper in
PlayerC (createWeaponDisplay) that rebuilds a static, unskinned copy of
whichever prop's geometry — never a .clone() of the live mesh, since
Character_Pistol is skinned and would otherwise stay bound to the
character's own skeleton and follow the player's hand around the map.
Pay Zones
Both Pay Zones are PayZoneC instances, constructed in TestSceneC with the
resource/level pair they each belong to (getCollectedCount,
createDepositVisual, onFilled, buildRewardIcon). Filling one raises only
its own level, then it shrinks away, pauses, and grows back in the same
spot — there is no relocation and no randomness.
- The map ships one interactive-zone marker (
UI_Interactive_Zone_02). It is scaled down byPAY_ZONE_SCALEand used as-is for the pistol zone; the bat zone is a plain clone of it, offset alongside by its own width plusPAY_ZONE_GAP(seeTestSceneC.createPayZoneNodes). PayZoneC.depositedis a lifetime total per instance and must never be reset — each HUD's displayed balance iscollected - deposited, so zeroing it would make the counter jump. Per-round progress isdeposited - zoneBaseline.- The marker nodes are nested in the map's own hierarchy, so the bat zone's
clone is positioned via
parent.worldToLocal()rather than a world delta written straight ontoposition— same reasoning as the crate respawn path below. - Each zone's centre also carries a reward preview: a static copy of the
matching weapon (see above) plus a projected DOM
+1 LVLlabel.
Crate respawn
Destroyed crates come back after RESPAWN_DELAY_MS (30 s) at their original
spot — without it a long run strips the map of wood and the bat progression
dies with it.
The same collider nodes are reused across the whole break/respawn cycle;
only the PhysicsBody is rebuilt. BreakablePropC.init therefore takes both an
onDestroyed and an onRespawned callback, and PlayerC.removeObstacle /
PlayerC.addObstacle are mirrors of each other.
respawn() calls root.updateWorldMatrix(true, true) after restoring the
resting transform. Box3.setFromObject only refreshes the node it is handed,
using its parent's existing matrixWorld — without the explicit update, the
obstacle box would be sampled at the sunk, toppled transform the crate was left
in when it broke.