Files
Oleksandr Vlasiuk 1d38990d7f some changes
2026-08-17 12:36:56 +03:00

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 by BreakablePropC) 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 base hit_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 by ZombieC) and delivered into the pistol's own Pay Zone.
  • Displayed by PistolHudC, stacked directly below WeaponHudC's octagon.
  • Added to the pistol's base damage per shot (see PlayerC.fireAt).
  • Visual payoff: WeaponAuraC, an additive Sprite glow on the drawn pistol that grows with the level and flattens out at its own MAX_EFFECT_LEVEL. A Sprite specifically because Character_Pistol is a SkinnedMesh (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 by PAY_ZONE_SCALE and used as-is for the pistol zone; the bat zone is a plain clone of it, offset alongside by its own width plus PAY_ZONE_GAP (see TestSceneC.createPayZoneNodes).
  • PayZoneC.deposited is a lifetime total per instance and must never be reset — each HUD's displayed balance is collected - deposited, so zeroing it would make the counter jump. Per-round progress is deposited - 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 onto position — 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 LVL label.

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.