From e5388bc5e0d252f2496611a66b9fc9d98e8efd36 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sat, 13 Dec 2025 03:09:06 +0100 Subject: [PATCH] Refactor level generation to use asynchronous processing; improve performance with frame budget management --- .../Infrastructure/Unity/GameBootstrap.cs | 31 +++++++++++-------- .../Infrastructure/Unity/LevelGenerator.cs | 31 +++++++++++++++---- ProjectSettings/DynamicsManager.asset | 2 +- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/Assets/Scripts/Infrastructure/Unity/GameBootstrap.cs b/Assets/Scripts/Infrastructure/Unity/GameBootstrap.cs index 4b042a6..b2a4e95 100644 --- a/Assets/Scripts/Infrastructure/Unity/GameBootstrap.cs +++ b/Assets/Scripts/Infrastructure/Unity/GameBootstrap.cs @@ -71,24 +71,29 @@ namespace Infrastructure.Unity if (levelGenerator) { - levelGenerator.Generate(soundManager, _allTiles, _tileViews, cameraController, rumbleManager); + StartCoroutine(levelGenerator.GenerateAsync(soundManager, _allTiles, _tileViews, cameraController, + rumbleManager, + () => + { + if (!floorVisibilityManager) + { + floorVisibilityManager = gameObject.AddComponent(); + } + floorVisibilityManager.Initialize(_gameSession, _allTiles, _tileViews, floorsCount); - if (!floorVisibilityManager) - { - floorVisibilityManager = gameObject.AddComponent(); - } - - floorVisibilityManager.Initialize(_gameSession, _allTiles, _tileViews, floorsCount); + SpawnDeathPlane(); + SpawnPlayer(); + + if (gameOverUi) gameOverUi.SetActive(false); + if (startScreenUi) startScreenUi.SetActive(true); // Show start screen NOW + + WireEvents(); + UpdateScoreUi(_gameSession.Score); + })); } - SpawnDeathPlane(); - SpawnPlayer(); - if (gameOverUi) gameOverUi.SetActive(false); if (startScreenUi) startScreenUi.SetActive(true); - - WireEvents(); - UpdateScoreUi(_gameSession.Score); } private void Update() diff --git a/Assets/Scripts/Infrastructure/Unity/LevelGenerator.cs b/Assets/Scripts/Infrastructure/Unity/LevelGenerator.cs index 92545a3..5861a9a 100644 --- a/Assets/Scripts/Infrastructure/Unity/LevelGenerator.cs +++ b/Assets/Scripts/Infrastructure/Unity/LevelGenerator.cs @@ -1,6 +1,10 @@ +using System; +using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using Core.Domain; using UnityEngine; +using Random = UnityEngine.Random; namespace Infrastructure.Unity { @@ -28,26 +32,41 @@ namespace Infrastructure.Unity private TilePool _tilePool; - public void Generate(SoundManager soundManager, List allTiles, Dictionary tileViews, CameraController camera, RumbleManager rumble) + public IEnumerator GenerateAsync(SoundManager soundManager, List allTiles, Dictionary tileViews, CameraController camera, RumbleManager rumble, Action onComplete) { _tilePool = new TilePool(tilePrefab, transform); + + var stopwatch = new Stopwatch(); + stopwatch.Start(); - GenerateFloor(0, MapPatterns.GenerateSquare(gridSizeX, gridSizeY), soundManager, allTiles, tileViews, camera, rumble); - GenerateFloor(1, MapPatterns.GenerateDonut(gridSizeX, Mathf.FloorToInt(gridSizeX / 3f)), soundManager, allTiles, tileViews, camera, rumble); - GenerateFloor(2, MapPatterns.GenerateCircle(gridSizeX), soundManager, allTiles, tileViews, camera, rumble); + yield return GenerateFloorAsync(0, MapPatterns.GenerateSquare(gridSizeX, gridSizeY), soundManager, allTiles, tileViews, camera, rumble, stopwatch); + yield return GenerateFloorAsync(1, MapPatterns.GenerateDonut(gridSizeX, Mathf.FloorToInt(gridSizeX / 3f)), soundManager, allTiles, tileViews, camera, rumble, stopwatch); + yield return GenerateFloorAsync(2, MapPatterns.GenerateCircle(gridSizeX), soundManager, allTiles, tileViews, camera, rumble, stopwatch); + + stopwatch?.Stop(); + onComplete?.Invoke(); } - private void GenerateFloor(int floorIndex, List coordinates, SoundManager soundManager, - List allTiles, Dictionary tileViews, CameraController camera, RumbleManager rumble) + private IEnumerator GenerateFloorAsync(int floorIndex, List coordinates, SoundManager soundManager, + List allTiles, Dictionary tileViews, CameraController camera, RumbleManager rumble, Stopwatch stopwatch) { var yOffset = -(floorIndex * floorHeightDistance); var xOffset = gridSizeX / 2f; var zOffset = gridSizeY / 2f; + + const long frameBudgetMs = 5; foreach (var coord in coordinates) { var pos = new Vector3(coord.x - xOffset, yOffset, coord.y - zOffset); CreateTile(pos, $"{floorIndex}_{coord.x}_{coord.y}", floorIndex, soundManager, allTiles, tileViews, camera, rumble); + + if (stopwatch.ElapsedMilliseconds > frameBudgetMs) + { + stopwatch.Reset(); + stopwatch.Start(); + yield return null; // Wait for next frame + } } if (floorIndex > 0 && jumpPadPrefab) diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset index 4dc60b4..5b8ab1f 100644 --- a/ProjectSettings/DynamicsManager.asset +++ b/ProjectSettings/DynamicsManager.asset @@ -17,7 +17,7 @@ PhysicsManager: m_EnableAdaptiveForce: 0 m_ClothInterCollisionDistance: 0.1 m_ClothInterCollisionStiffness: 0.2 - m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_LayerCollisionMatrix: fffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff m_SimulationMode: 0 m_AutoSyncTransforms: 0 m_ReuseCollisionCallbacks: 1