Surfacing functions in all manager components

This commit is contained in:
2025-09-22 11:40:01 +02:00
parent bb3c91ec94
commit b0e44f156e
6 changed files with 226 additions and 16 deletions

View File

@@ -0,0 +1,48 @@
using UnityEditor;
using UnityEngine;
using Minigames.DivingForPictures;
/// <summary>
/// Custom editor for DivingGameManager that adds runtime buttons for testing surfacing and other functionality
/// </summary>
[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);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8bbb340d8d9b4af581770757e86cc1f8
timeCreated: 1758532258

View File

@@ -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);
}
/// <summary>
/// Start surfacing mode - slow down all bubbles
/// </summary>
public void StartSurfacing()
{
if (_isSurfacing) return; // Already surfacing
_isSurfacing = true;
// Slow down all existing bubbles
Bubble[] activeBubbles = FindObjectsOfType<Bubble>();
foreach (Bubble bubble in activeBubbles)
{
bubble.speed *= surfacingSpeedFactor;
}
Debug.Log($"[BubbleSpawner] Started surfacing mode. Bubbles slowed to {surfacingSpeedFactor * 100}% speed.");
}
/// <summary>
/// Logs the current pool statistics for debugging
/// </summary>

View File

@@ -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.");
}
/// <summary>
/// Starts the surfacing mode - reverses trench direction and adjusts all spawned entities
/// </summary>
public void StartSurfacing()
{
if (_isSurfacing) return; // Already surfacing
_isSurfacing = true;
// 1. Find and reverse trench tile spawner
TrenchTileSpawner tileSpawner = FindFirstObjectByType<TrenchTileSpawner>();
if (tileSpawner != null)
{
tileSpawner.StartSurfacing();
}
// 2. Find bubble spawner and slow down existing bubbles
BubbleSpawner bubbleSpawner = FindFirstObjectByType<BubbleSpawner>();
if (bubbleSpawner != null)
{
bubbleSpawner.StartSurfacing();
}
// 3. Find obstacle spawner and reverse existing obstacles
ObstacleSpawner obstacleSpawner = FindFirstObjectByType<ObstacleSpawner>();
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()
{

View File

@@ -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();
}
}
/// <summary>
@@ -279,5 +289,20 @@ namespace Minigames.DivingForPictures
StartObstacleBehavior();
}
}
/// <summary>
/// Sets surfacing mode, which reverses obstacle movement direction
/// </summary>
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}");
}
}
}

View File

@@ -75,6 +75,7 @@ namespace Minigames.DivingForPictures
private Coroutine _spawnCoroutine;
private readonly List<GameObject> _activeObstacles = new List<GameObject>();
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
/// </summary>
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
@@ -365,10 +401,6 @@ namespace Minigames.DivingForPictures
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();
}
/// <summary>
/// Start surfacing mode - reverse direction of existing obstacles and stop spawning new ones
/// </summary>
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<FloatingObstacle>();
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.");
}
/// <summary>
/// Gets the count of currently active obstacles
/// </summary>