From b0e44f156ef5315bfab798f43dacec8aeb1bcba7 Mon Sep 17 00:00:00 2001 From: AlexanderT Date: Mon, 22 Sep 2025 11:40:01 +0200 Subject: [PATCH] Surfacing functions in all manager components --- Assets/Editor/DivingGameManagerEditor.cs | 48 ++++++++++ Assets/Editor/DivingGameManagerEditor.cs.meta | 3 + .../DivingForPictures/BubbleSpawner.cs | 37 +++++++- .../DivingForPictures/DivingGameManager.cs | 41 +++++++++ .../DivingForPictures/FloatingObstacle.cs | 25 ++++++ .../DivingForPictures/ObstacleSpawner.cs | 88 +++++++++++++++---- 6 files changed, 226 insertions(+), 16 deletions(-) create mode 100644 Assets/Editor/DivingGameManagerEditor.cs create mode 100644 Assets/Editor/DivingGameManagerEditor.cs.meta diff --git a/Assets/Editor/DivingGameManagerEditor.cs b/Assets/Editor/DivingGameManagerEditor.cs new file mode 100644 index 00000000..53bde798 --- /dev/null +++ b/Assets/Editor/DivingGameManagerEditor.cs @@ -0,0 +1,48 @@ +using UnityEditor; +using UnityEngine; +using Minigames.DivingForPictures; + +/// +/// Custom editor for DivingGameManager that adds runtime buttons for testing surfacing and other functionality +/// +[CustomEditor(typeof(DivingGameManager))] +public class DivingGameManagerEditor : UnityEditor.Editor +{ + public override void OnInspectorGUI() + { + // Draw the default inspector + DrawDefaultInspector(); + + // Get the target DivingGameManager + DivingGameManager manager = (DivingGameManager)target; + + // Add space between default inspector and custom buttons + EditorGUILayout.Space(10); + + // Separator line + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + + // Add a label for the runtime testing section + EditorGUILayout.LabelField("Runtime Testing", EditorStyles.boldLabel); + + // Only enable the buttons during play mode + EditorGUI.BeginDisabledGroup(!Application.isPlaying); + + // Add the button to call StartSurfacing + if (GUILayout.Button("Start Surfacing", GUILayout.Height(30))) + { + manager.StartSurfacing(); + } + + // Add a button for breaking a rope (for testing damage) + if (GUILayout.Button("Break Rope (Test Damage)", GUILayout.Height(30))) + { + manager.ForceBreakRope(); + } + + EditorGUI.EndDisabledGroup(); + + // Add explanatory text + EditorGUILayout.HelpBox("These buttons only work in Play Mode. 'Start Surfacing' will reverse the trench direction, slow bubbles, and reverse obstacles. 'Break Rope' simulates player taking damage.", MessageType.Info); + } +} diff --git a/Assets/Editor/DivingGameManagerEditor.cs.meta b/Assets/Editor/DivingGameManagerEditor.cs.meta new file mode 100644 index 00000000..cde212bf --- /dev/null +++ b/Assets/Editor/DivingGameManagerEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8bbb340d8d9b4af581770757e86cc1f8 +timeCreated: 1758532258 \ No newline at end of file diff --git a/Assets/Scripts/Minigames/DivingForPictures/BubbleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/BubbleSpawner.cs index 31758f57..d4859a84 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/BubbleSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/BubbleSpawner.cs @@ -26,10 +26,15 @@ namespace Minigames.DivingForPictures public int initialPoolSize = 10; public int maxPoolSize = 30; + [Header("Surfacing Settings")] + [Tooltip("Factor to multiply bubble speed by when surfacing (0.5 = half speed)")] + [SerializeField] private float surfacingSpeedFactor = 0.5f; + private float _timer; private float _nextSpawnInterval; private BubblePool _bubblePool; private Camera _mainCamera; // Cache camera reference + private bool _isSurfacing = false; void Awake() { @@ -98,7 +103,18 @@ namespace Minigames.DivingForPictures } // Randomize bubble properties - bubble.speed = Random.Range(speedRange.x, speedRange.y); + float baseSpeed = Random.Range(speedRange.x, speedRange.y); + + // Apply surfacing speed reduction if needed + if (_isSurfacing) + { + bubble.speed = baseSpeed * surfacingSpeedFactor; + } + else + { + bubble.speed = baseSpeed; + } + bubble.wobbleSpeed = Random.Range(wobbleSpeedRange.x, wobbleSpeedRange.y); // Set base scale (initial size) for the bubble @@ -119,6 +135,25 @@ namespace Minigames.DivingForPictures bubble.SetWobbleScaleLimits(wobbleMinScale, wobbleMaxScale); } + /// + /// Start surfacing mode - slow down all bubbles + /// + public void StartSurfacing() + { + if (_isSurfacing) return; // Already surfacing + + _isSurfacing = true; + + // Slow down all existing bubbles + Bubble[] activeBubbles = FindObjectsOfType(); + foreach (Bubble bubble in activeBubbles) + { + bubble.speed *= surfacingSpeedFactor; + } + + Debug.Log($"[BubbleSpawner] Started surfacing mode. Bubbles slowed to {surfacingSpeedFactor * 100}% speed."); + } + /// /// Logs the current pool statistics for debugging /// diff --git a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs index 8b8b8b09..0f51521c 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs @@ -56,6 +56,10 @@ namespace Minigames.DivingForPictures // Private state variables for rope system private int currentRopeIndex = 0; private bool isGameOver = false; + private bool _isSurfacing = false; + + // Used to track if we're currently surfacing + public bool IsSurfacing => _isSurfacing; private void Awake() { @@ -114,6 +118,9 @@ namespace Minigames.DivingForPictures if (spawnPoints.Length == 0) return; + // If we're surfacing, don't spawn new monsters + if (_isSurfacing) return; + bool forceSpawn = timeSinceLastSpawn >= guaranteedSpawnTime; bool onCooldown = timeSinceLastSpawn < spawnCooldown; @@ -319,6 +326,40 @@ namespace Minigames.DivingForPictures Debug.Log("[DivingGameManager] Rope system reset."); } + /// + /// Starts the surfacing mode - reverses trench direction and adjusts all spawned entities + /// + public void StartSurfacing() + { + if (_isSurfacing) return; // Already surfacing + + _isSurfacing = true; + + // 1. Find and reverse trench tile spawner + TrenchTileSpawner tileSpawner = FindFirstObjectByType(); + if (tileSpawner != null) + { + tileSpawner.StartSurfacing(); + } + + // 2. Find bubble spawner and slow down existing bubbles + BubbleSpawner bubbleSpawner = FindFirstObjectByType(); + if (bubbleSpawner != null) + { + bubbleSpawner.StartSurfacing(); + } + + // 3. Find obstacle spawner and reverse existing obstacles + ObstacleSpawner obstacleSpawner = FindFirstObjectByType(); + if (obstacleSpawner != null) + { + obstacleSpawner.StartSurfacing(); + } + + // Note: Monster spawning is handled automatically through the Update and OnTileSpawned methods + // which will check the _isSurfacing flag + } + // Call this when the game ends public void EndGame() { diff --git a/Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs b/Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs index 52338634..2f430646 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs @@ -44,8 +44,10 @@ namespace Minigames.DivingForPictures private Collider2D _collider; private Camera _mainCamera; private float _screenTop; + private float _screenBottom; // Added to track bottom of screen private Coroutine _movementCoroutine; private Coroutine _offScreenCheckCoroutine; + private bool _isSurfacing = false; // Flag to track surfacing state private void Awake() { @@ -165,6 +167,9 @@ namespace Minigames.DivingForPictures Vector3 topWorldPoint = _mainCamera.ViewportToWorldPoint(new Vector3(0.5f, 1f, _mainCamera.transform.position.z)); _screenTop = topWorldPoint.y; + Vector3 bottomWorldPoint = _mainCamera.ViewportToWorldPoint(new Vector3(0.5f, 0f, _mainCamera.transform.position.z)); + _screenBottom = bottomWorldPoint.y; + // Check if obstacle is significantly above screen top (obstacles move upward) // Use a larger buffer to ensure obstacles are truly off-screen before returning to pool if (transform.position.y > _screenTop + 5f) @@ -172,6 +177,11 @@ namespace Minigames.DivingForPictures Debug.Log($"[FloatingObstacle] {gameObject.name} off-screen at Y:{transform.position.y:F2}, screen top:{_screenTop:F2}"); ReturnToPool(); } + else if (transform.position.y < _screenBottom - 5f) // Added check for bottom screen edge + { + Debug.Log($"[FloatingObstacle] {gameObject.name} below screen at Y:{transform.position.y:F2}, screen bottom:{_screenBottom:F2}"); + ReturnToPool(); + } } /// @@ -279,5 +289,20 @@ namespace Minigames.DivingForPictures StartObstacleBehavior(); } } + + /// + /// Sets surfacing mode, which reverses obstacle movement direction + /// + public void StartSurfacing() + { + if (_isSurfacing) return; // Already surfacing + + _isSurfacing = true; + + // Reverse movement speed (already handled by ObstacleSpawner, but this ensures consistency) + moveSpeed *= -1; + + Debug.Log($"[FloatingObstacle] {gameObject.name} started surfacing with speed: {moveSpeed}"); + } } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/ObstacleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/ObstacleSpawner.cs index 67f0cffd..e3ecdcd4 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/ObstacleSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/ObstacleSpawner.cs @@ -75,6 +75,7 @@ namespace Minigames.DivingForPictures private Coroutine _spawnCoroutine; private readonly List _activeObstacles = new List(); private int _obstacleCounter = 0; // Counter for unique obstacle naming + private bool _isSurfacing = false; // Flag to track surfacing state private void Awake() { @@ -250,6 +251,13 @@ namespace Minigames.DivingForPictures /// private void TrySpawnObstacle() { + // Don't spawn new obstacles when surfacing + if (_isSurfacing) + { + Debug.Log("[ObstacleSpawner] Skipping obstacle spawn - currently surfacing"); + return; + } + Debug.Log($"[ObstacleSpawner] TrySpawnObstacle called at {Time.time:F2}"); if (obstaclePrefabs == null || obstaclePrefabs.Count == 0) @@ -338,25 +346,53 @@ namespace Minigames.DivingForPictures return; } - Debug.Log($"[ObstacleSpawner] Got obstacle {obstacle.name} from pool, active state: {obstacle.activeInHierarchy}"); - - // FORCE ACTIVATION - bypass pool issues - if (!obstacle.activeInHierarchy) - { - Debug.LogWarning($"[ObstacleSpawner] Pool returned inactive object {obstacle.name}, force activating!"); - obstacle.SetActive(true); - Debug.Log($"[ObstacleSpawner] After force activation, {obstacle.name} active state: {obstacle.activeInHierarchy}"); - } - + // Important: Set position/parent/rotation BEFORE activation to avoid visual glitches obstacle.transform.position = position; obstacle.transform.rotation = prefab.transform.rotation; obstacle.transform.SetParent(transform); - Debug.Log($"[ObstacleSpawner] After positioning, obstacle {obstacle.name} active state: {obstacle.activeInHierarchy}"); + + Debug.Log($"[ObstacleSpawner] Got obstacle {obstacle.name} from pool, active state: {obstacle.activeInHierarchy}"); + + // ENHANCED FORCE ACTIVATION - more robust approach + if (!obstacle.activeInHierarchy) + { + Debug.LogWarning($"[ObstacleSpawner] Pool returned inactive object {obstacle.name}, force activating!"); + + // Configure obstacle BEFORE activation + ConfigureObstacle(obstacle, prefabIndex); + + // Force activate the obstacle + obstacle.SetActive(true); + + // Double-check activation status + if (!obstacle.activeInHierarchy) + { + Debug.LogError($"[ObstacleSpawner] CRITICAL ERROR: Failed to activate {obstacle.name} after multiple attempts!"); + + // Last resort: try to instantiate a new one instead + GameObject newObstacle = Instantiate(prefab, position, prefab.transform.rotation, transform); + if (newObstacle != null) + { + obstacle = newObstacle; + ConfigureObstacle(obstacle, prefabIndex); + } + } + + Debug.Log($"[ObstacleSpawner] After force activation, {obstacle.name} active state: {obstacle.activeInHierarchy}"); + } + else + { + // Still configure if already active + ConfigureObstacle(obstacle, prefabIndex); + } } else { Debug.Log($"[ObstacleSpawner] Instantiating new obstacle (pooling disabled)"); obstacle = Instantiate(prefab, position, prefab.transform.rotation, transform); + + // Configure the newly instantiated obstacle + ConfigureObstacle(obstacle, prefabIndex); } // Assign unique name with counter @@ -364,10 +400,6 @@ namespace Minigames.DivingForPictures string oldName = obstacle.name; obstacle.name = $"Obstacle{_obstacleCounter:D3}"; Debug.Log($"[ObstacleSpawner] Renamed obstacle from '{oldName}' to '{obstacle.name}', active state: {obstacle.activeInHierarchy}"); - - // Configure the obstacle - ConfigureObstacle(obstacle, prefabIndex); - Debug.Log($"[ObstacleSpawner] After configuration, obstacle {obstacle.name} active state: {obstacle.activeInHierarchy}"); // Track active obstacles _activeObstacles.Add(obstacle); @@ -459,6 +491,32 @@ namespace Minigames.DivingForPictures CalculateScreenBounds(); } + /// + /// Start surfacing mode - reverse direction of existing obstacles and stop spawning new ones + /// + public void StartSurfacing() + { + if (_isSurfacing) return; // Already surfacing + + _isSurfacing = true; + + // Reverse direction of all existing obstacles + foreach (GameObject obstacle in _activeObstacles) + { + if (obstacle != null) + { + FloatingObstacle obstacleComponent = obstacle.GetComponent(); + if (obstacleComponent != null) + { + // Call StartSurfacing on the obstacle component itself + obstacleComponent.StartSurfacing(); + } + } + } + + Debug.Log($"[ObstacleSpawner] Started surfacing mode. Reversed direction of {_activeObstacles.Count} active obstacles."); + } + /// /// Gets the count of currently active obstacles ///