feat: implement special effect projectiles, large-battle render budgeting, and UI optimizations
This commit is contained in:
+11
-1
@@ -1,3 +1,13 @@
|
||||
# Update: Special Effect Camera Focus
|
||||
|
||||
- `ArenaScene` preloads and creates special-effect animations beside the existing fighter and world-effect assets, then starts `startSpecialEffects()` for live matches only.
|
||||
- During a special cast, `beginSpecialEffectCameraFocus()` zooms toward the caster, `zoomOutSpecialEffectCameraFocus()` zooms back out in place when the projectile starts moving, and `clearSpecialEffectCameraFocus()` restores the previous camera after the configured hold/outro timing.
|
||||
- Special focus temporarily takes priority over selected-fighter, spectator, and meteor focus so the Hurt-frame pose and projectile launch are visible.
|
||||
- When `SPECIAL_EFFECT.CAMERA.CENTER_ON_CASTER_AT_START` is enabled, special focus centers the main camera on the caster's location immediately and keeps it snapped there until projectile handoff, then continues the slower follow motion.
|
||||
- The Hurt-frame preparation window sets `scene.specialEffectPreparationPaused`, pauses the scene clock and Arcade Physics, freezes living fighter animations, pauses active combat-object tweens/animations/velocities, and places a blurred battlefield snapshot plus dim layer beneath the raised caster. Camera focus tweening stays active so the zoom-in can complete while combat and world-effect progression are stopped.
|
||||
- The projectile is not used as a camera target. Special camera targets are still clamped against the current zoom viewport so the focus stack cannot drag the camera outside the arena bounds.
|
||||
- Match restart and match finish both call `clearSpecialEffects()` so pending timers, projectile objects, caster locks, and special camera tweens do not leak into the next battle.
|
||||
|
||||
# Update: Elite-Weighted Scene Counts
|
||||
|
||||
- `ArenaScene.recordDeath()` records an elite death as its represented `stackCount`, keeping persisted species death totals aligned with the displayed army size.
|
||||
@@ -8,7 +18,7 @@
|
||||
|
||||
- The minimap is drawn during live matches by `ArenaScene` as a lightweight `Graphics` overlay through a dedicated `minimap-hud` camera instead of reusing the field camera. Presentation/waiting mode hides it.
|
||||
- The main camera ignores the minimap graphics object, and the HUD camera ignores field objects as they are added to the scene. Minimap rendering uses team-colored living fighter dots and the main camera viewport rectangle, so the minimap frame stays fixed while the main camera follows combat or meteor focus.
|
||||
- `ArenaScene` refreshes HUD candidates on an interval, choosing selected fighters plus nearby visible fighters when zoomed in, then releases unused HUD pool slots.
|
||||
- `ArenaScene` refreshes HUD candidates on an interval, choosing selected fighters plus nearby visible fighters when zoomed in, then releases unused health-bar HUD pool slots. Battlefield name text is not shown.
|
||||
|
||||
# Context: Arena & Scene
|
||||
|
||||
|
||||
+20
-1
@@ -1,3 +1,22 @@
|
||||
# Update: Special Effect Projectile
|
||||
|
||||
- `specialEffects.js` owns the one-shot special effect flow: asset preload/animation creation, random live-match scheduling, underdog caster selection, caster pose lock, launch visuals, projectile path checks, and cleanup.
|
||||
- `SPECIAL_EFFECT` in `src/constants.js` tunes trigger timing, caster Hurt-frame hold, camera zoom, melee projectile assets, ranged projectile asset scale/speed/travel distance/hit radius, target density area, arena edge padding, and lifetime. `WORLD_EFFECT.SPECIAL` points to the same config object.
|
||||
- Casters must be living, non-elite, non-magic fighters from teams that are not currently tied for first by represented living count. When `SPECIAL_EFFECT.CASTER.BALANCE_NON_MAGIC_TYPES` is enabled, caster selection first picks among available non-magic types and then picks a fighter from that type, preventing the larger melee roster from overwhelming ranged special casts. If no caster exists at the chosen time, the timer retries within the configured window instead of firing multiple times.
|
||||
- Special casters receive realtime invulnerability for `SPECIAL_EFFECT.CASTER.INVULNERABLE_MS`. `combat.js` checks that window in normal attacks, world-effect damage, and special instant kills, while `worldEffects.js` also skips frost survivor effects for invulnerable fighters.
|
||||
- While the caster holds the Hurt frame, `specialEffects.js` pauses fighter AI, Arcade Physics, the scene clock, existing combat-object physics velocity, combat-object animations, and combat-object tweens. Existing combat/world delayed calls and already-falling meteor/frost tweens stop advancing until the realtime preparation hold releases into the attack animation.
|
||||
- Caster emphasis uses `SPECIAL_EFFECT.FOCUS_LAYER`: `specialEffects.js` snapshots the current battlefield into a render texture, applies Phaser Blur FX when available, adds a dim layer, and raises the caster above both layers until cleanup.
|
||||
- The special camera does not follow the projectile. When projectile movement begins, `zoomOutSpecialEffectCameraFocus()` zooms out in place using `SPECIAL_EFFECT.CAMERA.PROJECTILE_VIEW_ZOOM` and `PROJECTILE_ZOOM_OUT_MS` so the projectile remains readable without dragging the camera off the arena.
|
||||
- Melee special projectile effects can define 1-based `frameSequence` arrays. `specialEffects.js` converts them to Phaser frames so the largest frames can be repeated for readability, and melee projectile animations loop while traveling. The projectile's `startHoldMs` keeps it visible at the caster before travel begins.
|
||||
- At target-selection time, the special projectile scans living enemies with a summed-area table and locks onto the `SPECIAL_EFFECT.PROJECTILE.targetAreaTiles` square containing the highest represented `stackCount` population. The moving projectile visual is type-based: melee casters fire one random `SPECIAL_EFFECT.MELEE.ASSETS` sprite, while ranged casters fire the configured projectile sprite. Movement uses an Arcade Physics sprite and `physics.moveTo`, matching normal ranged projectile position updates, and projectile travel is cut to the arena bounds using `arenaEdgePadding`.
|
||||
- The special projectile calls `applySpecialEffectInstantKill()` from `combat.js`, so instant kills still use the normal death animation, death-stat recording, kill log attribution when there is a surviving caster, split-on-death behavior, scoreboard refresh, and match-finish checks.
|
||||
|
||||
# Update: Elite Magic Attack Effect Scale
|
||||
|
||||
- `combat.js` resolves instant-spell attack effect scale through constants instead of hard-coding `FIGHTER.SCALE`.
|
||||
- Normal spell effects use `FIGHTER.SCALE * FIGHTER.ATTACK_EFFECT_SCALE_MULTIPLIER`.
|
||||
- Elite magic spell effects additionally multiply by `FIGHTER.ELITE.ATTACK_EFFECT_SCALE_MULTIPLIER`, keeping caster body scale and effect scale separately tunable.
|
||||
|
||||
# Update: Elite Target Damage And Density
|
||||
|
||||
- `combat.js` uses `fighter.isElite` to split damage rules. Elite critical hits deal the greater of the ordinary hit or `COMBAT.CRITICAL_DAMAGE_PERCENT` of max HP; normal critical hits deal `NORMAL_CRITICAL_DAMAGE_MULTIPLIER` times the ordinary hit.
|
||||
@@ -28,7 +47,7 @@
|
||||
- `combat.js` resolves fighter animation keys through `ensureFighterTeamAnimation()` so every action can use the team-shadow baked texture generated from the original spritesheet.
|
||||
- `playIfNeeded()` compares against the team-shadow animation key. This avoids switching back to the original non-team-colored spritesheet when fighters move, attack, take damage, or die.
|
||||
- Frost stun remains a body tint effect in `worldEffects.js`. Since team identity is baked into the floor shadow pixels, there is no `teamMarker` tint state to update or restore.
|
||||
- The removed `teamMarker` display object means death handling no longer needs to hide or destroy a separate marker. HUD cleanup only owns the name label and health bar objects.
|
||||
- The removed `teamMarker` display object means death handling no longer needs to hide or destroy a separate marker. HUD cleanup only owns health-bar objects because battlefield name labels are no longer created.
|
||||
|
||||
# Update: Focused Combat Effects In Large Battles
|
||||
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
# Update: Special Effect Constants
|
||||
|
||||
- `src/constants.js` now exports `SPECIAL_EFFECT` for the special projectile system, while `WORLD_EFFECT.SPECIAL` references the same object for world-effect domain grouping.
|
||||
- `SPECIAL_EFFECT.TRIGGER_DELAY_MIN_MS`, `TRIGGER_DELAY_MAX_MS`, and `RETRY_DELAY_MS` control the once-per-match activation window.
|
||||
- `SPECIAL_EFFECT.CASTER`, `CAMERA`, `MELEE`, and `PROJECTILE` centralize the Hurt-frame pose, non-magic caster type balancing, caster invulnerability time, caster-start centering, zoom timing, projectile-view zoom-out timing, melee projectile frame sequences/looping assets, projectile start hold, size, speed, target density area, arena edge padding, hit radius, travel distance, and lifetime.
|
||||
- `SPECIAL_EFFECT.FOCUS_LAYER` controls the temporary caster-emphasis stack: blurred battlefield snapshot depth/alpha, dim depth/alpha, caster depth, Blur FX quality/strength/steps, and fade timing.
|
||||
|
||||
# Update: Large-Battle Render Budget
|
||||
|
||||
- `PERFORMANCE.LARGE_BATTLE_RENDERED_FIGHTER_LIMIT` caps the number of physical fighter plans produced for large battles.
|
||||
- `matchSetup.js` applies the budget after randomized elite compression by promoting normal 100-member blocks or normal remainder groups to elite groups as needed. It does not change represented `stackCount` population.
|
||||
|
||||
# Update: Large-Battle Elite Probability
|
||||
|
||||
- `FIGHTER.ELITE.RANDOMIZED_COMPRESSION.LARGE_BATTLE_ELITE_BLOCK_PROBABILITY` controls the randomized elite block ratio once the user-entered total fighter count exceeds `PERFORMANCE.LARGE_BATTLE_FIGHTER_THRESHOLD`.
|
||||
- `matchSetup.js` keeps the threshold under `PERFORMANCE` and the elite ratio under `FIGHTER.ELITE`, so performance detection and elite balancing remain separately tunable.
|
||||
|
||||
# Update: Elite Magic Attack Effect Scale
|
||||
|
||||
- `FIGHTER.ATTACK_EFFECT_SCALE_MULTIPLIER` controls normal instant-spell attack effect size.
|
||||
- `FIGHTER.ELITE.ATTACK_EFFECT_SCALE_MULTIPLIER` applies only to elite magic fighters, multiplying the normal spell-effect scale without changing body scale, HP, range, or damage formulas.
|
||||
- Elite skin selection uses the full `FIGHTER.ELITE.TYPE` list, currently `melee` and `magic`.
|
||||
|
||||
# Update: Elite Balance Constants
|
||||
|
||||
- `FIGHTER.ELITE` contains elite type, stack/appearance/HP/range tuning, attack-damage and speed tuning, and randomized large-team compression settings inside the fighter domain.
|
||||
|
||||
+9
-3
@@ -1,14 +1,20 @@
|
||||
# Update: Field HUD Text Removal
|
||||
|
||||
- `fighterFactory.js` no longer creates pooled battlefield name labels. Zoom-visible and selected fighters can still show pooled health bars, while team identity comes from the team-colored sprite shadow.
|
||||
- HUD cleanup now owns only health-bar display objects.
|
||||
|
||||
# Update: Elite Representative Fighter
|
||||
|
||||
- `fighterFactory.js` accepts `isElite` and `stackCount` on a spawn plan. Elite attack damage is tuned by `FIGHTER.ELITE.ATTACK_DAMAGE_BONUS_MULTIPLIER` and `ATTACK_DAMAGE_STACK_EXPONENT`; HP, scale, and range use the other nested elite settings.
|
||||
- `fighterSelection.js` assigns elite plans only skins whose derived type matches `FIGHTER.ELITE.TYPE` (currently `melee`); normal plans still draw from the complete manifest.
|
||||
- `fighterSelection.js` assigns elite plans only skins whose derived type matches `FIGHTER.ELITE.TYPE` (currently `melee` and `magic`); normal plans still draw from the complete manifest.
|
||||
- Elite scale becomes its `baseScaleX`/`baseScaleY`; kill-growth is currently disabled by `COMBAT.KILL_REWARD_ENABLED = false`, but this baseline remains correct if a separate mode enables it later.
|
||||
- Elite magic attack effects are scaled in `combat.js` through `FIGHTER.ELITE.ATTACK_EFFECT_SCALE_MULTIPLIER`, so spell visuals can be tuned independently from body scale.
|
||||
- Elite representatives cannot use `splitOnDeath`. Elite attack-speed and movement-speed bonuses are configurable independently under `FIGHTER.ELITE`.
|
||||
|
||||
# Update: HUD Pooling
|
||||
|
||||
- `fighterFactory.js` no longer creates permanent name labels or health bars for every fighter.
|
||||
- HUD display objects are pooled on the scene and assigned only to selected fighters or zoom-visible nearby fighters chosen by `ArenaScene`.
|
||||
- `fighterFactory.js` no longer creates permanent health bars for every fighter, and battlefield name labels are not created at all.
|
||||
- Health-bar HUD display objects are pooled on the scene and assigned only to selected fighters or zoom-visible nearby fighters chosen by `ArenaScene`.
|
||||
- `syncFighterHud()` acquires a slot lazily and `releaseFighterHud()` returns it to the pool when the fighter leaves the HUD candidate set, dies, or is destroyed.
|
||||
- Tune pool size and visible candidate limits in `PERFORMANCE.FIGHTER_HUD_POOL_SIZE` and `PERFORMANCE.FIGHTER_HUD_VISIBLE_LIMIT`.
|
||||
|
||||
|
||||
+5
-3
@@ -2,11 +2,13 @@
|
||||
|
||||
- Below `FIGHTER.ELITE.RANDOMIZED_COMPRESSION.MIN_TEAM_SIZE`, `matchSetup.js` converts each complete `FIGHTER.ELITE.STACK_SIZE = 100` block into one elite plan and keeps the remainder as individual normal plans. With the current threshold of `100`, complete blocks are randomized.
|
||||
- For starting-zone matches, each elite consumes the assigned spawn point at the start of its represented 100-member block, while remainder normals retain their corresponding individual spawn points.
|
||||
- At or above the randomized-compression threshold, each complete 100-member block becomes one elite at probability `0.6`, or expands into 100 normal plans otherwise. A `*4000` team therefore averages `24 elite` representing 2,400 fighters plus `1,600 normal` fighters.
|
||||
- At or above the randomized-compression threshold, each complete 100-member block becomes one elite at probability `0.6`, or expands into 100 normal plans otherwise.
|
||||
- If the user-entered total fighter count exceeds `PERFORMANCE.LARGE_BATTLE_FIGHTER_THRESHOLD`, randomized compression uses `FIGHTER.ELITE.RANDOMIZED_COMPRESSION.LARGE_BATTLE_ELITE_BLOCK_PROBABILITY` (`0.8` by default) for every eligible team block.
|
||||
- Large battles also enforce `PERFORMANCE.LARGE_BATTLE_RENDERED_FIGHTER_LIMIT` by promoting failed normal blocks or normal remainder groups to elite groups after the random roll. This keeps physical sprites bounded while preserving represented `stackCount`.
|
||||
- `arenaMatchRuntime.js` keeps the submitted population represented through `stackCount`, while `arenaScoreboard.js` intentionally shows living physical composition as `E : <elite sprites> | N : <normal sprites>`.
|
||||
- Trait-generated extra spawning remains enabled for normal fighters only. Elite plans do not apply `spawnMultiplier`, because one aggregate fighter multiplying would multiply the entire represented army.
|
||||
- `ArenaScene` uses setup-aware fighter selection so elite plans receive only skins matching `FIGHTER.ELITE.TYPE` (currently `melee`), while normal plans keep the existing full selection pool.
|
||||
- The team card layout reserves enough horizontal space for values such as `E : 24 | N : 1600`, including the horizontally scrolling mobile scoreboard.
|
||||
- `ArenaScene` uses setup-aware fighter selection so elite plans receive only skins matching `FIGHTER.ELITE.TYPE` (currently `melee` and `magic`), while normal plans keep the existing full selection pool.
|
||||
- The team card layout reserves enough horizontal space for values such as `E : 32 | N : 800`, including the horizontally scrolling mobile scoreboard.
|
||||
|
||||
# Context: Match & UI
|
||||
|
||||
|
||||
Reference in New Issue
Block a user