IMplement basic Developer Settings

This commit is contained in:
2025-09-24 12:21:21 +02:00
parent f07ce88331
commit 8b96a5d0c3
18 changed files with 739 additions and 248 deletions

View File

@@ -1,5 +1,6 @@
using UnityEngine;
using Pooling;
using AppleHills.Core.Settings;
namespace Minigames.DivingForPictures
{
@@ -10,25 +11,9 @@ namespace Minigames.DivingForPictures
{
public Bubble bubblePrefab;
public Sprite[] bubbleSprites; // Assign in inspector
public float spawnInterval = 0.3f;
public Vector2 speedRange = new Vector2(0.5f, 2f);
public Vector2 scaleRange = new Vector2(0.3f, 0.7f);
public Vector2 wobbleSpeedRange = new Vector2(1f, 3f);
public Vector2 wobbleAmountRange = new Vector2(0.05f, 0.15f);
public float spawnXMin = -3.5f;
public float spawnXMax = 3.5f;
public float spawnY = -5f;
public float wobbleMinScale = 0.2f;
public float wobbleMaxScale = 1.2f;
[Header("Object Pooling")]
public bool useObjectPooling = true;
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 DivingDeveloperSettings _devSettings;
private IDivingMinigameSettings _gameSettings;
private float _timer;
private float _nextSpawnInterval;
@@ -40,14 +25,24 @@ namespace Minigames.DivingForPictures
{
_mainCamera = Camera.main;
if (useObjectPooling)
// Get developer settings and game settings
_devSettings = GameManager.GetDeveloperSettings<DivingDeveloperSettings>();
_gameSettings = GameManager.GetSettingsObject<IDivingMinigameSettings>();
if (_devSettings == null)
{
Debug.LogError("[BubbleSpawner] Failed to load developer settings!");
return;
}
if (_devSettings.BubbleUseObjectPooling)
{
// Create the bubble pool
GameObject poolGO = new GameObject("BubblePool");
poolGO.transform.SetParent(transform);
_bubblePool = poolGO.AddComponent<BubblePool>();
_bubblePool.initialPoolSize = initialPoolSize;
_bubblePool.maxPoolSize = maxPoolSize;
_bubblePool.initialPoolSize = _devSettings.BubbleInitialPoolSize;
_bubblePool.maxPoolSize = _devSettings.BubbleMaxPoolSize;
_bubblePool.Initialize(bubblePrefab);
// Periodically check for pool statistics in debug builds
@@ -80,7 +75,7 @@ namespace Minigames.DivingForPictures
/// <returns>Randomized interval in seconds.</returns>
float GetRandomizedInterval()
{
return spawnInterval * Random.Range(0.8f, 1.2f);
return _devSettings.BubbleSpawnInterval * Random.Range(0.8f, 1.2f);
}
/// <summary>
@@ -88,11 +83,11 @@ namespace Minigames.DivingForPictures
/// </summary>
void SpawnBubble()
{
float x = Random.Range(spawnXMin, spawnXMax);
Vector3 spawnPos = new Vector3(x, spawnY, 0f);
float x = Random.Range(_devSettings.BubbleSpawnXMin, _devSettings.BubbleSpawnXMax);
Vector3 spawnPos = new Vector3(x, _devSettings.BubbleSpawnY, 0f);
Bubble bubble;
if (useObjectPooling && _bubblePool != null)
if (_devSettings.BubbleUseObjectPooling && _bubblePool != null)
{
bubble = _bubblePool.GetBubble();
bubble.transform.position = spawnPos;
@@ -103,25 +98,25 @@ namespace Minigames.DivingForPictures
}
// Randomize bubble properties
float baseSpeed = Random.Range(speedRange.x, speedRange.y);
float baseSpeed = Random.Range(_devSettings.BubbleSpeedRange.x, _devSettings.BubbleSpeedRange.y);
// Apply surfacing speed reduction if needed
if (_isSurfacing)
{
bubble.speed = baseSpeed * surfacingSpeedFactor;
bubble.speed = baseSpeed * _devSettings.BubbleSurfacingSpeedFactor;
}
else
{
bubble.speed = baseSpeed;
}
bubble.wobbleSpeed = Random.Range(wobbleSpeedRange.x, wobbleSpeedRange.y);
bubble.wobbleSpeed = Random.Range(_devSettings.BubbleWobbleSpeedRange.x, _devSettings.BubbleWobbleSpeedRange.y);
// Set base scale (initial size) for the bubble
float baseScale = Random.Range(scaleRange.x, scaleRange.y);
float baseScale = Random.Range(_devSettings.BubbleScaleRange.x, _devSettings.BubbleScaleRange.y);
bubble.SetBaseScale(baseScale);
// Assign random sprite to BubbleSprite (fixed naming from BottleSprite)
// Assign random sprite to BubbleSprite
if (bubbleSprites != null && bubbleSprites.Length > 0)
{
Sprite randomSprite = bubbleSprites[Random.Range(0, bubbleSprites.Length)];
@@ -132,7 +127,7 @@ namespace Minigames.DivingForPictures
bubble.transform.rotation = Quaternion.Euler(0f, 0f, Random.Range(0f, 360f));
// Pass min/max scale for wobble clamping
bubble.SetWobbleScaleLimits(wobbleMinScale, wobbleMaxScale);
bubble.SetWobbleScaleLimits(_devSettings.BubbleWobbleMinScale, _devSettings.BubbleWobbleMaxScale);
}
/// <summary>
@@ -148,10 +143,10 @@ namespace Minigames.DivingForPictures
Bubble[] activeBubbles = FindObjectsByType<Bubble>(FindObjectsSortMode.None);
foreach (Bubble bubble in activeBubbles)
{
bubble.speed *= surfacingSpeedFactor;
bubble.speed *= _devSettings.BubbleSurfacingSpeedFactor;
}
Debug.Log($"[BubbleSpawner] Started surfacing mode. Bubbles slowed to {surfacingSpeedFactor * 100}% speed.");
Debug.Log($"[BubbleSpawner] Started surfacing mode. Bubbles slowed to {_devSettings.BubbleSurfacingSpeedFactor * 100}% speed.");
}
/// <summary>

View File

@@ -4,6 +4,7 @@ using System;
using System.Collections;
using UnityEngine.Events;
using UnityEngine.Playables;
using AppleHills.Core.Settings;
namespace Minigames.DivingForPictures
{
@@ -13,40 +14,17 @@ namespace Minigames.DivingForPictures
[Tooltip("Array of monster prefabs to spawn randomly")]
[SerializeField] private GameObject[] monsterPrefabs;
[Header("Spawn Probability")]
[Tooltip("Base chance (0-1) of spawning a monster on each tile")]
[SerializeField] private float baseSpawnProbability = 0.2f;
[Tooltip("Maximum chance (0-1) of spawning a monster")]
[SerializeField] private float maxSpawnProbability = 0.5f;
[Tooltip("How fast the probability increases per second")]
[SerializeField] private float probabilityIncreaseRate = 0.01f;
[Header("Spawn Timing")]
[Tooltip("Force a spawn after this many seconds without spawns")]
[SerializeField] private float guaranteedSpawnTime = 30f;
[Tooltip("Minimum time between monster spawns")]
[SerializeField] private float spawnCooldown = 5f;
[Header("Scoring")]
[Tooltip("Base points for taking a picture")]
[SerializeField] private int basePoints = 100;
[Tooltip("Additional points per depth unit")]
[SerializeField] private int depthMultiplier = 10;
[Header("Rope Damage System")]
[Tooltip("Ropes that will break one by one as player takes damage")]
[SerializeField] private RopeBreaker[] playerRopes;
[Header("Surfacing Settings")]
[Tooltip("Duration in seconds for speed transition when surfacing")]
[SerializeField] private float speedTransitionDuration = 2.0f;
[Tooltip("Factor to multiply speed by when surfacing (usually 1.0 for same speed)")]
[SerializeField] private float surfacingSpeedFactor = 3.0f;
[Tooltip("How long to continue spawning tiles after surfacing begins (seconds)")]
[SerializeField] private float surfacingSpawnDelay = 5.0f;
[Tooltip("Reference to the PlayableDirector that will play the surfacing timeline")]
[SerializeField] private PlayableDirector surfacingTimeline;
// Settings reference
private IDivingMinigameSettings _settings;
// Private state variables
private int playerScore = 0;
private float currentSpawnProbability;
@@ -83,7 +61,15 @@ namespace Minigames.DivingForPictures
private void Awake()
{
currentSpawnProbability = baseSpawnProbability;
// Get settings from GameManager
_settings = GameManager.GetSettingsObject<IDivingMinigameSettings>();
if (_settings == null)
{
Debug.LogError("[DivingGameManager] Failed to load diving minigame settings!");
}
// Initialize with base probability from settings
currentSpawnProbability = _settings?.EndlessDescenderBaseSpawnProbability ?? 0.2f;
}
private void Start()
@@ -118,10 +104,10 @@ namespace Minigames.DivingForPictures
// Gradually increase spawn probability over time
float previousProbability = currentSpawnProbability;
if (currentSpawnProbability < maxSpawnProbability)
if (currentSpawnProbability < _settings.EndlessDescenderMaxSpawnProbability)
{
currentSpawnProbability += probabilityIncreaseRate * Time.deltaTime;
currentSpawnProbability = Mathf.Min(currentSpawnProbability, maxSpawnProbability);
currentSpawnProbability += _settings.EndlessDescenderProbabilityIncreaseRate * Time.deltaTime;
currentSpawnProbability = Mathf.Min(currentSpawnProbability, _settings.EndlessDescenderMaxSpawnProbability);
// Only fire event if probability changed significantly
if (Mathf.Abs(currentSpawnProbability - previousProbability) > 0.01f)
@@ -141,8 +127,8 @@ namespace Minigames.DivingForPictures
// If we're surfacing, don't spawn new monsters
if (_isSurfacing) return;
bool forceSpawn = timeSinceLastSpawn >= guaranteedSpawnTime;
bool onCooldown = timeSinceLastSpawn < spawnCooldown;
bool forceSpawn = timeSinceLastSpawn >= _settings.EndlessDescenderGuaranteedSpawnTime;
bool onCooldown = timeSinceLastSpawn < _settings.EndlessDescenderSpawnCooldown;
// Don't spawn if on cooldown, unless forced
if (onCooldown && !forceSpawn) return;
@@ -159,7 +145,7 @@ namespace Minigames.DivingForPictures
// Reset timer and adjust probability
lastSpawnTime = Time.time;
timeSinceLastSpawn = 0f;
currentSpawnProbability = baseSpawnProbability;
currentSpawnProbability = _settings.EndlessDescenderBaseSpawnProbability;
OnSpawnProbabilityChanged?.Invoke(currentSpawnProbability);
}
}
@@ -204,8 +190,8 @@ namespace Minigames.DivingForPictures
private void OnMonsterPictureTaken(Monster monster)
{
// Calculate points based on depth
int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * depthMultiplier);
int pointsAwarded = basePoints + depthBonus;
int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * _settings.EndlessDescenderDepthMultiplier);
int pointsAwarded = _settings.EndlessDescenderBasePoints + depthBonus;
// Add score
playerScore += pointsAwarded;
@@ -356,7 +342,7 @@ namespace Minigames.DivingForPictures
_isSurfacing = true;
// 1. Initiate smooth velocity transition to surfacing speed
float targetVelocityFactor = -1.0f * surfacingSpeedFactor;
float targetVelocityFactor = -1.0f * _settings.EndlessDescenderSurfacingSpeedFactor;
SetVelocityFactor(targetVelocityFactor);
// 2. Find and notify trench tile spawner about direction change (for spawning/despawning logic)
@@ -525,7 +511,7 @@ namespace Minigames.DivingForPictures
private IEnumerator SurfacingSequence()
{
// Wait for the configured delay
yield return new WaitForSeconds(surfacingSpawnDelay);
yield return new WaitForSeconds(_settings.EndlessDescenderSurfacingSpawnDelay);
// Find tile spawner and tell it to stop spawning
TrenchTileSpawner tileSpawner = FindFirstObjectByType<TrenchTileSpawner>();
@@ -594,10 +580,10 @@ namespace Minigames.DivingForPictures
float startFactor = _currentVelocityFactor;
float elapsed = 0f;
while (elapsed < speedTransitionDuration)
while (elapsed < _settings.EndlessDescenderSpeedTransitionDuration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / speedTransitionDuration);
float t = Mathf.Clamp01(elapsed / _settings.EndlessDescenderSpeedTransitionDuration);
// Smooth step interpolation
float smoothStep = t * t * (3f - 2f * t);

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using Pooling;
using AppleHills.Core.Settings;
namespace Minigames.DivingForPictures
{
@@ -16,50 +17,17 @@ namespace Minigames.DivingForPictures
[Tooltip("List of possible obstacle prefabs to spawn")]
[SerializeField] private List<GameObject> obstaclePrefabs;
[Header("Spawn Settings")]
[Tooltip("Time interval between spawn attempts (in seconds)")]
[SerializeField] private float spawnInterval = 2f;
[Tooltip("Random variation in spawn timing (+/- seconds)")]
[SerializeField] private float spawnIntervalVariation = 0.5f;
[Tooltip("Maximum number of spawn position attempts before skipping")]
[SerializeField] private int maxSpawnAttempts = 10;
[Tooltip("Radius around spawn point to check for tile collisions")]
[SerializeField] private float spawnCollisionRadius = 1f;
[Header("Obstacle Properties Randomization")]
[Tooltip("Minimum movement speed for spawned obstacles")]
[SerializeField] private float minMoveSpeed = 1f;
[Tooltip("Maximum movement speed for spawned obstacles")]
[SerializeField] private float maxMoveSpeed = 4f;
[Header("Object Pooling")]
[Tooltip("Whether to use object pooling for obstacles")]
[SerializeField] private bool useObjectPooling = true;
[Tooltip("Maximum objects per prefab type in pool")]
[SerializeField] private int maxPerPrefabPoolSize = 3;
[Tooltip("Total maximum pool size across all prefab types")]
[SerializeField] private int totalMaxPoolSize = 15;
[Header("Layer Settings")]
[Tooltip("Layer mask for tile collision detection during spawn position validation")]
[SerializeField] private LayerMask tileLayerMask = -1; // Let user configure which layers to avoid
[Tooltip("Target layer for spawned obstacles - obstacles will be placed on this layer")]
[SerializeField] private int obstacleLayer = 11; // Default to layer 11, but configurable
[Header("Events")]
[Tooltip("Called when an obstacle is spawned")]
[Tooltip("Invoked when a new obstacle is spawned")]
public UnityEvent<GameObject> onObstacleSpawned;
[Tooltip("Called when an obstacle is returned to pool")]
[Tooltip("Invoked when an obstacle is destroyed or returned to pool")]
public UnityEvent<GameObject> onObstacleDestroyed;
// Settings references
private IDivingMinigameSettings _settings;
private DivingDeveloperSettings _devSettings;
// Private fields
private ObstaclePool _obstaclePool;
private Camera _mainCamera;
@@ -75,13 +43,34 @@ namespace Minigames.DivingForPictures
{
_mainCamera = Camera.main;
// Get settings from GameManager
_settings = GameManager.GetSettingsObject<IDivingMinigameSettings>();
_devSettings = GameManager.GetDeveloperSettings<DivingDeveloperSettings>();
if (_settings == null)
{
Debug.LogError("[ObstacleSpawner] Failed to load diving minigame settings!");
}
if (_devSettings == null)
{
Debug.LogError("[ObstacleSpawner] Failed to load diving developer settings!");
}
// Validate obstacle prefabs
ValidateObstaclePrefabs();
if (useObjectPooling)
if (_devSettings?.ObstacleUseObjectPooling ?? false)
{
InitializeObjectPool();
}
// Initialize events if null
if (onObstacleSpawned == null)
onObstacleSpawned = new UnityEvent<GameObject>();
if (onObstacleDestroyed == null)
onObstacleDestroyed = new UnityEvent<GameObject>();
}
private void Start()
@@ -100,6 +89,8 @@ namespace Minigames.DivingForPictures
/// </summary>
private void ValidateObstaclePrefabs()
{
if (_devSettings == null) return;
for (int i = 0; i < obstaclePrefabs.Count; i++)
{
if (obstaclePrefabs[i] == null) continue;
@@ -112,10 +103,10 @@ namespace Minigames.DivingForPictures
}
// Ensure the prefab is on the correct layer (using configurable obstacleLayer)
if (obstaclePrefabs[i].layer != obstacleLayer)
if (obstaclePrefabs[i].layer != _devSettings.ObstacleLayer)
{
Debug.LogWarning($"Obstacle prefab {obstaclePrefabs[i].name} is not on the configured obstacle layer ({obstacleLayer}). Setting layer automatically.");
SetLayerRecursively(obstaclePrefabs[i], obstacleLayer);
Debug.LogWarning($"Obstacle prefab {obstaclePrefabs[i].name} is not on the configured obstacle layer ({_devSettings.ObstacleLayer}). Setting layer automatically.");
SetLayerRecursively(obstaclePrefabs[i], _devSettings.ObstacleLayer);
}
}
}
@@ -142,8 +133,8 @@ namespace Minigames.DivingForPictures
_obstaclePool = poolGO.AddComponent<ObstaclePool>();
// Set up pool configuration
_obstaclePool.maxPerPrefabPoolSize = maxPerPrefabPoolSize;
_obstaclePool.totalMaxPoolSize = totalMaxPoolSize;
_obstaclePool.maxPerPrefabPoolSize = _devSettings.ObstacleMaxPerPrefabPoolSize;
_obstaclePool.totalMaxPoolSize = _devSettings.ObstacleTotalMaxPoolSize;
// Convert GameObject list to FloatingObstacle list
List<FloatingObstacle> prefabObstacles = new List<FloatingObstacle>(obstaclePrefabs.Count);
@@ -230,7 +221,9 @@ namespace Minigames.DivingForPictures
while (true)
{
// Calculate next spawn time with variation
float nextSpawnTime = spawnInterval + Random.Range(-spawnIntervalVariation, spawnIntervalVariation);
float nextSpawnTime = _settings.EndlessDescenderObstacleSpawnInterval +
Random.Range(-_settings.EndlessDescenderObstacleSpawnIntervalVariation,
_settings.EndlessDescenderObstacleSpawnIntervalVariation);
nextSpawnTime = Mathf.Max(0.1f, nextSpawnTime); // Ensure minimum interval
yield return new WaitForSeconds(nextSpawnTime);
@@ -264,7 +257,7 @@ namespace Minigames.DivingForPictures
bool foundValidPosition = false;
// Try to find a valid spawn position
for (int attempts = 0; attempts < maxSpawnAttempts; attempts++)
for (int attempts = 0; attempts < _settings.EndlessDescenderObstacleMaxSpawnAttempts; attempts++)
{
spawnPosition = GetRandomSpawnPosition();
@@ -277,13 +270,13 @@ namespace Minigames.DivingForPictures
}
else
{
Debug.Log($"[ObstacleSpawner] Position {spawnPosition} invalid (attempt {attempts + 1}/{maxSpawnAttempts})");
Debug.Log($"[ObstacleSpawner] Position {spawnPosition} invalid (attempt {attempts + 1}/{_settings.EndlessDescenderObstacleMaxSpawnAttempts})");
}
}
if (!foundValidPosition)
{
Debug.LogWarning($"[ObstacleSpawner] SPAWN MISSED: Could not find valid spawn position after {maxSpawnAttempts} attempts at {Time.time:F2}");
Debug.LogWarning($"[ObstacleSpawner] SPAWN MISSED: Could not find valid spawn position after {_settings.EndlessDescenderObstacleMaxSpawnAttempts} attempts at {Time.time:F2}");
}
}
@@ -306,7 +299,7 @@ namespace Minigames.DivingForPictures
private bool IsValidSpawnPosition(Vector3 position)
{
// Use OverlapCircle to check for collisions with tiles
Collider2D collision = Physics2D.OverlapCircle(position, spawnCollisionRadius, tileLayerMask);
Collider2D collision = Physics2D.OverlapCircle(position, _settings.EndlessDescenderObstacleSpawnCollisionRadius, _devSettings.ObstacleTileLayerMask);
return collision == null;
}
@@ -330,7 +323,7 @@ namespace Minigames.DivingForPictures
GameObject obstacle;
// Spawn using pool or instantiate directly
if (useObjectPooling && _obstaclePool != null)
if (_devSettings.ObstacleUseObjectPooling && _obstaclePool != null)
{
Debug.Log($"[ObstacleSpawner] Requesting obstacle from pool (prefab index {prefabIndex})");
obstacle = _obstaclePool.GetObstacle(prefabIndex);
@@ -416,8 +409,10 @@ namespace Minigames.DivingForPictures
// Set prefab index
obstacleComponent.PrefabIndex = prefabIndex;
// Randomize properties
obstacleComponent.MoveSpeed = Random.Range(minMoveSpeed, maxMoveSpeed);
// Randomize properties using settings
obstacleComponent.MoveSpeed = Random.Range(
_settings.EndlessDescenderObstacleMinMoveSpeed,
_settings.EndlessDescenderObstacleMaxMoveSpeed);
// Set spawner reference (since FloatingObstacle has this built-in now)
obstacleComponent.SetSpawner(this);
@@ -440,7 +435,7 @@ namespace Minigames.DivingForPictures
onObstacleDestroyed?.Invoke(obstacle);
// Return to pool or destroy
if (useObjectPooling && _obstaclePool != null)
if (_devSettings.ObstacleUseObjectPooling && _obstaclePool != null)
{
Debug.Log($"[ObstacleSpawner] Returning {obstacle.name} to pool");
_obstaclePool.ReturnObstacle(obstacle, prefabIndex);
@@ -457,7 +452,9 @@ namespace Minigames.DivingForPictures
/// </summary>
public void SetSpawnInterval(float interval)
{
spawnInterval = interval;
// This method can no longer directly modify the settings
// Consider implementing a runtime settings override system if needed
Debug.LogWarning("[ObstacleSpawner] SetSpawnInterval no longer modifies settings directly. Settings are now centralized.");
}
/// <summary>
@@ -465,8 +462,9 @@ namespace Minigames.DivingForPictures
/// </summary>
public void SetSpeedRange(float min, float max)
{
minMoveSpeed = min;
maxMoveSpeed = max;
// This method can no longer directly modify the settings
// Consider implementing a runtime settings override system if needed
Debug.LogWarning("[ObstacleSpawner] SetSpeedRange no longer modifies settings directly. Settings are now centralized.");
}
/// <summary>
@@ -534,8 +532,8 @@ namespace Minigames.DivingForPictures
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
// Only draw if screen bounds have been calculated
if (_spawnRangeX > 0f)
// Only draw if screen bounds have been calculated and settings are available
if (_spawnRangeX > 0f && _settings != null)
{
// Draw spawn area using dynamic calculations
Gizmos.color = Color.yellow;
@@ -545,7 +543,7 @@ namespace Minigames.DivingForPictures
// Draw collision radius at spawn point
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(center, spawnCollisionRadius);
Gizmos.DrawWireSphere(center, _settings.EndlessDescenderObstacleSpawnCollisionRadius);
}
}
#endif

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using AppleHills.Core.Settings;
namespace Minigames.DivingForPictures
{
@@ -8,11 +9,8 @@ namespace Minigames.DivingForPictures
/// </summary>
public class PlayerController : MonoBehaviour, ITouchInputConsumer
{
[Header("Tap Movement")]
[Tooltip("Maximum distance the player can move from a single tap")]
[SerializeField] private float tapMaxDistance = 0.5f;
[Tooltip("How quickly the tap impulse fades (higher = faster stop)")]
[SerializeField] private float tapDecelerationRate = 5.0f;
// Settings reference
private IDivingMinigameSettings _settings;
private float _targetFingerX;
private bool _isTouchActive;
@@ -25,6 +23,13 @@ namespace Minigames.DivingForPictures
void Awake()
{
_originY = transform.position.y;
// Get settings from GameManager
_settings = GameManager.GetSettingsObject<IDivingMinigameSettings>();
if (_settings == null)
{
Debug.LogError("[PlayerController] Failed to load diving minigame settings!");
}
}
void Start()
@@ -42,7 +47,7 @@ namespace Minigames.DivingForPictures
public void OnTap(Vector2 worldPosition)
{
// Debug.Log($"[EndlessDescenderController] OnTap at {worldPosition}");
float targetX = Mathf.Clamp(worldPosition.x, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax);
float targetX = Mathf.Clamp(worldPosition.x, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
// Calculate tap direction (+1 for right, -1 for left)
_tapDirection = Mathf.Sign(targetX - transform.position.x);
@@ -63,7 +68,7 @@ namespace Minigames.DivingForPictures
public void OnHoldStart(Vector2 worldPosition)
{
// Debug.Log($"[EndlessDescenderController] OnHoldStart at {worldPosition}");
_targetFingerX = Mathf.Clamp(worldPosition.x, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax);
_targetFingerX = Mathf.Clamp(worldPosition.x, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
_isTouchActive = true;
}
@@ -73,7 +78,7 @@ namespace Minigames.DivingForPictures
public void OnHoldMove(Vector2 worldPosition)
{
// Debug.Log($"[EndlessDescenderController] OnHoldMove at {worldPosition}");
_targetFingerX = Mathf.Clamp(worldPosition.x, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax);
_targetFingerX = Mathf.Clamp(worldPosition.x, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
}
/// <summary>
@@ -91,9 +96,9 @@ namespace Minigames.DivingForPictures
if (_isTouchActive)
{
float currentX = transform.position.x;
float lerpSpeed = GameManager.Instance.EndlessDescenderLerpSpeed;
float maxOffset = GameManager.Instance.EndlessDescenderMaxOffset;
float exponent = GameManager.Instance.EndlessDescenderSpeedExponent;
float lerpSpeed = _settings.EndlessDescenderLerpSpeed;
float maxOffset = _settings.EndlessDescenderMaxOffset;
float exponent = _settings.EndlessDescenderSpeedExponent;
float targetX = _targetFingerX;
float offset = targetX - currentX;
offset = Mathf.Clamp(offset, -maxOffset, maxOffset);
@@ -103,7 +108,7 @@ namespace Minigames.DivingForPictures
// Prevent overshooting
moveStep = Mathf.Clamp(moveStep, -absOffset, absOffset);
float newX = currentX + moveStep;
newX = Mathf.Clamp(newX, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax);
newX = Mathf.Clamp(newX, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
UpdatePosition(newX);
}
@@ -111,21 +116,21 @@ namespace Minigames.DivingForPictures
else if (_tapImpulseStrength > 0)
{
float currentX = transform.position.x;
float maxOffset = GameManager.Instance.EndlessDescenderMaxOffset;
float lerpSpeed = GameManager.Instance.EndlessDescenderLerpSpeed;
float maxOffset = _settings.EndlessDescenderMaxOffset;
float lerpSpeed = _settings.EndlessDescenderLerpSpeed;
// Calculate move distance based on impulse strength
float moveDistance = maxOffset * _tapImpulseStrength * Time.deltaTime * lerpSpeed;
// Limit total movement from single tap
moveDistance = Mathf.Min(moveDistance, tapMaxDistance * _tapImpulseStrength);
moveDistance = Mathf.Min(moveDistance, _settings.EndlessDescenderTapMaxDistance * _tapImpulseStrength);
// Apply movement in tap direction
float newX = currentX + (moveDistance * _tapDirection);
newX = Mathf.Clamp(newX, GameManager.Instance.EndlessDescenderClampXMin, GameManager.Instance.EndlessDescenderClampXMax);
newX = Mathf.Clamp(newX, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
// Reduce impulse strength over time
_tapImpulseStrength -= Time.deltaTime * tapDecelerationRate;
_tapImpulseStrength -= Time.deltaTime * _settings.EndlessDescenderTapDecelerationRate;
if (_tapImpulseStrength < 0.01f)
{
_tapImpulseStrength = 0f;

View File

@@ -4,6 +4,7 @@ using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;
using Pooling;
using AppleHills.Core.Settings;
namespace Minigames.DivingForPictures
{
@@ -16,16 +17,6 @@ namespace Minigames.DivingForPictures
[Tooltip("List of possible trench tile prefabs.")]
[SerializeField] private List<GameObject> tilePrefabs;
[Header("Tile Settings")]
[SerializeField] private int initialTileCount = 3;
[SerializeField] private float tileSpawnBuffer = 1f;
[Header("Movement Settings")]
[SerializeField] private float moveSpeed = 3f;
[SerializeField] private float speedUpFactor = 0.2f;
[SerializeField] private float speedUpInterval = 10f;
[SerializeField] private float maxMoveSpeed = 12f;
[Header("Object Pooling")]
[SerializeField] private bool useObjectPooling = true;
[SerializeField] private int maxPerPrefabPoolSize = 2;
@@ -38,6 +29,9 @@ namespace Minigames.DivingForPictures
[FormerlySerializedAs("OnTileDestroyed")]
public UnityEvent<GameObject> onTileDestroyed;
// Settings reference
private IDivingMinigameSettings _settings;
// Private fields
private readonly Dictionary<GameObject, float> _tileHeights = new Dictionary<GameObject, float>();
private readonly List<GameObject> _activeTiles = new List<GameObject>();
@@ -52,9 +46,6 @@ namespace Minigames.DivingForPictures
// Current velocity for tile movement
private float _currentVelocity;
// Interval for velocity calculations (seconds)
[SerializeField] private float velocityCalculationInterval = 0.5f;
private const float TileSpawnZ = -1f;
private const float DefaultTileHeight = 5f;
@@ -73,7 +64,15 @@ namespace Minigames.DivingForPictures
private void Awake()
{
_mainCamera = Camera.main;
_baseMoveSpeed = moveSpeed; // Store the original base speed
// Get settings from GameManager
_settings = GameManager.GetSettingsObject<IDivingMinigameSettings>();
if (_settings == null)
{
Debug.LogError("[TrenchTileSpawner] Failed to load diving minigame settings!");
}
_baseMoveSpeed = _settings?.EndlessDescenderMoveSpeed ?? 3f; // Store the original base speed
// Calculate tile heights for each prefab
CalculateTileHeights();
@@ -110,7 +109,7 @@ namespace Minigames.DivingForPictures
SpawnInitialTiles();
// Initialize velocity and start the velocity calculation coroutine
_currentVelocity = moveSpeed * Time.fixedDeltaTime;
_currentVelocity = _baseMoveSpeed * Time.fixedDeltaTime;
StartCoroutine(VelocityCalculationRoutine());
}
@@ -148,7 +147,7 @@ namespace Minigames.DivingForPictures
while (true)
{
CalculateVelocity();
yield return new WaitForSeconds(velocityCalculationInterval);
yield return new WaitForSeconds(_settings.EndlessDescenderVelocityCalculationInterval);
}
}
@@ -157,7 +156,7 @@ namespace Minigames.DivingForPictures
/// </summary>
private void CalculateVelocity()
{
_currentVelocity = moveSpeed * Time.fixedDeltaTime;
_currentVelocity = _baseMoveSpeed * Time.fixedDeltaTime;
}
/// <summary>
@@ -247,7 +246,7 @@ namespace Minigames.DivingForPictures
// Move starting position up by 2 tile heights
startingY += tileHeightEstimate * 2;
for (int i = 0; i < initialTileCount; i++)
for (int i = 0; i < _settings.EndlessDescenderInitialTileCount; i++)
{
float y = startingY;
// Calculate proper Y position based on previous tiles
@@ -291,12 +290,12 @@ namespace Minigames.DivingForPictures
// Update the actual move speed based on the velocity factor
// This keeps the original move speed intact for game logic
moveSpeed = _baseMoveSpeed * Mathf.Abs(_velocityFactor);
_baseMoveSpeed = _settings.EndlessDescenderMoveSpeed * Mathf.Abs(_velocityFactor);
// Recalculate velocity immediately
CalculateVelocity();
Debug.Log($"[TrenchTileSpawner] Velocity factor updated to {_velocityFactor:F2}, moveSpeed: {moveSpeed:F2}");
Debug.Log($"[TrenchTileSpawner] Velocity factor updated to {_velocityFactor:F2}, moveSpeed: {_baseMoveSpeed:F2}");
}
/// <summary>
@@ -362,12 +361,12 @@ namespace Minigames.DivingForPictures
if (_isSurfacing)
{
// When surfacing, destroy tiles at the bottom
shouldDestroy = topTile.transform.position.y + tileHeight / 2 < _screenBottom - tileSpawnBuffer;
shouldDestroy = topTile.transform.position.y + tileHeight / 2 < _screenBottom - _settings.EndlessDescenderTileSpawnBuffer;
}
else
{
// When descending, destroy tiles at the top
shouldDestroy = topTile.transform.position.y - tileHeight / 2 > _screenTop + tileSpawnBuffer;
shouldDestroy = topTile.transform.position.y - tileHeight / 2 > _screenTop + _settings.EndlessDescenderTileSpawnBuffer;
}
if (shouldDestroy)
@@ -431,12 +430,12 @@ namespace Minigames.DivingForPictures
if (_isSurfacing)
{
// When surfacing, check if the bottom of the tile is above the top of the screen
isLastTileLeaving = bottomTile.transform.position.y - tileHeight / 2 > _screenTop + tileSpawnBuffer;
isLastTileLeaving = bottomTile.transform.position.y - tileHeight / 2 > _screenTop + _settings.EndlessDescenderTileSpawnBuffer;
}
else
{
// When descending, check if the top of the tile is below the bottom of the screen
isLastTileLeaving = bottomTile.transform.position.y + tileHeight / 2 < _screenBottom - tileSpawnBuffer;
isLastTileLeaving = bottomTile.transform.position.y + tileHeight / 2 < _screenBottom - _settings.EndlessDescenderTileSpawnBuffer;
}
if (isLastTileLeaving)
@@ -454,14 +453,14 @@ namespace Minigames.DivingForPictures
{
// When surfacing, spawn new tiles at the top
float topEdge = bottomTile.transform.position.y + tileHeight / 2;
shouldSpawn = topEdge < _screenTop + tileSpawnBuffer;
shouldSpawn = topEdge < _screenTop + _settings.EndlessDescenderTileSpawnBuffer;
newY = bottomTile.transform.position.y + tileHeight;
}
else
{
// When descending, spawn new tiles at the bottom
float bottomEdge = bottomTile.transform.position.y - tileHeight / 2;
shouldSpawn = bottomEdge > _screenBottom - tileSpawnBuffer;
shouldSpawn = bottomEdge > _screenBottom - _settings.EndlessDescenderTileSpawnBuffer;
newY = bottomTile.transform.position.y - tileHeight;
}
@@ -477,9 +476,9 @@ namespace Minigames.DivingForPictures
private void HandleSpeedRamping()
{
_speedUpTimer += Time.deltaTime;
if (_speedUpTimer >= speedUpInterval)
if (_speedUpTimer >= _settings.EndlessDescenderSpeedUpInterval)
{
moveSpeed = Mathf.Min(moveSpeed + speedUpFactor, maxMoveSpeed);
_baseMoveSpeed = Mathf.Min(_baseMoveSpeed + _settings.EndlessDescenderSpeedUpFactor, _settings.EndlessDescenderMaxMoveSpeed);
_speedUpTimer = 0f;
}
}
@@ -656,16 +655,19 @@ namespace Minigames.DivingForPictures
// Draw tile bounds for debugging
Gizmos.color = Color.cyan;
for (int i = 0; i < initialTileCount; i++)
if (_settings != null)
{
float height = DefaultTileHeight;
if (tilePrefabs != null && tilePrefabs.Count > 0 && tilePrefabs[0] != null &&
_tileHeights.TryGetValue(tilePrefabs[0], out float h))
for (int i = 0; i < _settings.EndlessDescenderInitialTileCount; i++)
{
height = h;
float height = DefaultTileHeight;
if (tilePrefabs != null && tilePrefabs.Count > 0 && tilePrefabs[0] != null &&
_tileHeights.TryGetValue(tilePrefabs[0], out float h))
{
height = h;
}
Vector3 center = new Vector3(0f, _screenBottom + i * height, 0f);
Gizmos.DrawWireCube(center, new Vector3(10f, height, 1f));
}
Vector3 center = new Vector3(0f, _screenBottom + i * height, 0f);
Gizmos.DrawWireCube(center, new Vector3(10f, height, 1f));
}
}
#endif