Skip to content

Archived on 2026-10-24. The Godot rewrite is cancelled. Migration decisions and work checklists below are withdrawn. Original claims, code examples, file paths, and completion statements have not all been revalidated. Use the current documentation and issue register for maintenance decisions.

Audit correction (2026-10-24): fullscreen startup and in-run spawn suppression remain separate unproven candidates. The text below must not be read as confirmation of fullscreen timing, a display cause, or disappearance in another engine.

Unity Freeze Bug Investigation Notes

Purpose

Expand the known one-minute startup stuck analysis with concrete Unity-side probes. This document does not propose a new implementation; it defines what to observe in the current Unity project.

Working Definition To Confirm

Current clarification: the reported issue happens when the Unity game opens in fullscreen mode. It is likely a Unity startup/window/display/settings issue and may disappear in Godot. Do not use this issue to drive Godot gameplay architecture unless it reproduces in Godot.

Primary startup symptom to confirm:

Symptom Variant What It Would Look Like
Fullscreen startup stuck Game opens into fullscreen and appears stuck/unresponsive for roughly 1 minute before continuing.
Display-mode stall Startup waits during resolution/fullscreen/monitor switching.
Save/settings startup stall Startup waits while loading settings, save data, config, or platform identity.
Platform startup stall Startup waits around Steam/platform initialization.

Older gameplay-stall variants are secondary audit notes only:

Symptom Variant What It Would Look Like
Spawn stall Player can move/attack, but creep waves stop for roughly 60 seconds.
Time-scale pause UI/gameplay appears paused; Time.timeScale == 0.
Reward soft-lock Reward UI is open or expected, but card select/reroll/input does not progress.
Frame freeze Application stops rendering/responding because the main thread is blocked.
Boss/miniboss transition wait Camera/UI/music changes, enemies flee, but next state does not start.

Highest-Value Probes

Startup probes should be checked first:

Probe Variables To Log Related Scripts / Systems Why
Fullscreen boot timing app start time, first scene loaded time, first rendered frame time, fullscreen mode, resolution, monitor id Unity player settings, AppInitiator.cs, SplashUIController.cs, GameSettings.cs Confirms whether the one-minute delay is before gameplay systems run.
Settings/config load config path, file exists, read start/end, selected fullscreen/window mode, selected resolution GameSettings.cs, config .json path Detects slow or invalid settings load.
Save startup load save path, .dat read start/end, migration/check start/end, error/fallback path SaveManager.cs, SaveService.cs Detects synchronous save work during boot.
Steam/platform startup Steam init start/end/error, nickname/user id fetch timing SteamManager, SteamScript, save identity code Detects platform initialization blocking startup.

Gameplay probes are secondary:

Probe Variables To Log Related Scripts Why
Spawn state heartbeat run time, battle state, isMiniBossSpawn, minibossFightTimer, active special event name/id, number of active enemies SpawnerEventManager.cs Miniboss logic intentionally suppresses creep spawns for up to 60 seconds.
Special death matching enemy killId, special spawn event enemy killId, event isActive, event isSpawning SpawnerEventManager.cs, Enemy.cs A missed id match can leave miniboss/special suppression until timer expiry.
Pause/time-scale state GameManager.isPaused, GameState.IsPaused, IsRewarding, IsGameOver, Time.timeScale, RewardRoller.CurrentPhase GameManager.cs, GameStateService.cs, RewardRoller.cs, UpgradeSelection.cs Reward selection and reroll have contradictory-looking pause gates.
Pool instantiate spikes prefab name, pool active count, inactive count, total instantiates this run, frame time PoolManager.cs Cold pools and projectile/effect bursts can cause stalls or GC spikes.
Item coroutine pressure enabled item count, merge coroutine starts, item merger spawns per minute Items.cs, ItemsMerger.cs Each enabled item starts MergeChecking with while(true).
Hot search cost duration and result count for FindGameObjectsWithTag, FindObjectsByType<Items> Player.cs, Enemy.cs, SpawnerEventManager.cs, GameManager.cs, PlayerCollectItem.cs Scene-wide searches can spike with large enemy/item counts.
Reward queue state queue length, current reward type, current phase, reroll amount, card count RewardRoller.cs, UpgradeSelection.cs Soft-lock may be reward flow, not spawn flow.
Save/network at game over save start/end time, leaderboard request start/end/error SaveService.cs, SaveManager.cs, LeaderboardManager.cs, GameManager.cs Less likely during active combat, but can block/stall at game over/menu.

Reproduction Checkpoints

Checkpoint What To Record
App launch build target, fullscreen/window mode, resolution, monitor setup, whether Steam is running, config path, save path.
First visible frame wall-clock time from launch, scene name, whether splash/menu/gameplay is visible.
Startup delay observed whether screen renders, whether input works, whether Windows marks the app unresponsive, CPU/GPU usage, latest startup log line.
Run start Stage, difficulty, player count, selected character ids, selected modifiers, initial ability list.
Every 10 seconds Run timer, battle state, active enemy count, active item count, pool instantiate counts since last sample.
On every special spawn SpawnEvent asset/name, enemy prefab name, enemy type, enemy kill id, isSpawning, isActive, isMiniBossSpawn, minibossFightTimer.
On every enemy death/despawn Enemy name, enemy type, kill id, whether death event fired, whether pooled by border/despawn/death.
On reward start Reward type, queue length, selected player, reward phase, Time.timeScale, isPaused, IsRewarding.
On reward card select/reroll phase before/after, reroll amount, isPaused, selected upgrade id/name.
On boss transition current stage map id, boss active flag, camera lock state, active enemy count, healthbar state, timer state.
On freeze/stuck observed exact wall-clock time, run timer, frame rate, Time.timeScale, battle state, reward phase, active enemy/item/projectile counts, latest special event.

Likely One-Minute Cases

Case Evidence Confidence What Would Confirm It
Unity fullscreen/display startup stall User clarification says the issue happens when opening the Unity game in fullscreen mode. Medium/High Delay occurs before active gameplay; changing fullscreen/window mode or resolution changes the symptom.
Settings/save/platform startup stall Unity boot flow loads settings/save/platform identity near startup. Medium Logs show long wall-clock gap during config, .dat save, or Steam/platform init.
Miniboss suppression is working as coded but feels like a stall SpawnerEventManager sets isMiniBossSpawn = true and minibossFightTimer = 60f; creep spawning is blocked while true. High During the stuck minute, player still moves, Time.timeScale == 1, isMiniBossSpawn == true, timer counts down.
Miniboss clear event is missed MiniBossDeath clears only if death id matches active special spawn enemy kill id. Medium Enemy dies/despawns but isMiniBossSpawn remains true and active special id does not clear.
Reward pause/phase mismatch UpgradeSelection expects pause/selecting state, while RewardRoller.RerollUpgrade returns when manager.isPaused. Medium Freeze occurs with reward UI or reward queue active and inconsistent isPaused/IsRewarding/CurrentPhase.
Pool/GC spike during dense wave PoolManager instantiates on empty pool; many modifiers multiply projectiles/effects. Medium Profiler shows main thread spike in Instantiate, GC allocation, or object activation during the event.
Time-scale zero with scaled waits Many coroutines use scaled WaitForSeconds; GameStateService sets Time.timeScale to 0 when paused/rewarding/game over. Medium During stuck state, Time.timeScale == 0 and the waiting coroutine uses scaled wait.
Item merger coroutine buildup Items.MergeChecking uses while(true) for every item and periodically spawns merger objects. Medium Active item count/coroutine count grows before stall; pool instantiate spikes include item merger objects.
Leaderboard/save blocking Save and leaderboard happen mainly around game over/menu. Low for active combat Freeze occurs after game over or leaderboard action; log shows file/network request duration.

Profiling Targets

Profiler Area Specific Targets
CPU Timeline SpawnerEventManager.Update, SpawnEnemy, SpawnBoss, Enemy.TakeDamage, PlayerWeapon.FireWeapon, PlayerAttack.OnTriggerEnter2D, PoolManager.GetFromPool, Instantiate, GC.Collect.
Memory Allocations from projectiles, damage popups, reward cards, item mergers, target lists/sorts.
Physics 2D Trigger/collision count during dense waves and area abilities.
Rendering Damage popup/UI/effect overdraw only if frame freeze, not spawn stall.
Scripts Scene-wide searches and per-frame sorting in target acquisition.

Concrete Logging Suggestions

Add temporary logs only in a debug build or behind a runtime toggle. Suggested minimal points:

Location Log When
SpawnerEventManager.SpecialSpawnSystem A special event starts, becomes active, or sets isMiniBossSpawn.
SpawnerEventManager.MiniBossDeath Called with id and whether it matched the active special event.
SpawnerEventManager.MinibossFightTimer Timer starts, reaches zero, or clears state.
GameStateService.SetState Any state changes and resulting Time.timeScale.
RewardRoller Phase transitions, reward queue changes, reroll attempts.
PoolManager.SpawnNewObject New instantiation with prefab key and total count.
Items.OnEnable / OnDisable Merge coroutine starts/stops and item merger spawn count.

Open Questions

  • Which fullscreen mode, monitor setup, resolution, and build target reproduce the Unity startup issue?
  • Does startup reach splash/menu/gameplay before the delay, or does the delay happen before the first rendered frame?
  • Does changing fullscreen to windowed/borderless avoid the issue?
  • Does the issue correlate with config .json, save .dat, or Steam/platform initialization?
  • Are spawner assets intentionally saved with isSpawning or isActive set to 1?