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
isSpawningorisActiveset to1?