The feel is fine
This commit is contained in:
@@ -69,7 +69,7 @@ namespace Minigames.DivingForPictures
|
||||
}
|
||||
|
||||
// Initialize with base probability from settings
|
||||
currentSpawnProbability = _settings?.EndlessDescenderBaseSpawnProbability ?? 0.2f;
|
||||
currentSpawnProbability = _settings?.BaseSpawnProbability ?? 0.2f;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
@@ -104,10 +104,10 @@ namespace Minigames.DivingForPictures
|
||||
|
||||
// Gradually increase spawn probability over time
|
||||
float previousProbability = currentSpawnProbability;
|
||||
if (currentSpawnProbability < _settings.EndlessDescenderMaxSpawnProbability)
|
||||
if (currentSpawnProbability < _settings.MaxSpawnProbability)
|
||||
{
|
||||
currentSpawnProbability += _settings.EndlessDescenderProbabilityIncreaseRate * Time.deltaTime;
|
||||
currentSpawnProbability = Mathf.Min(currentSpawnProbability, _settings.EndlessDescenderMaxSpawnProbability);
|
||||
currentSpawnProbability += _settings.ProbabilityIncreaseRate * Time.deltaTime;
|
||||
currentSpawnProbability = Mathf.Min(currentSpawnProbability, _settings.MaxSpawnProbability);
|
||||
|
||||
// Only fire event if probability changed significantly
|
||||
if (Mathf.Abs(currentSpawnProbability - previousProbability) > 0.01f)
|
||||
@@ -127,8 +127,8 @@ namespace Minigames.DivingForPictures
|
||||
// If we're surfacing, don't spawn new monsters
|
||||
if (_isSurfacing) return;
|
||||
|
||||
bool forceSpawn = timeSinceLastSpawn >= _settings.EndlessDescenderGuaranteedSpawnTime;
|
||||
bool onCooldown = timeSinceLastSpawn < _settings.EndlessDescenderSpawnCooldown;
|
||||
bool forceSpawn = timeSinceLastSpawn >= _settings.GuaranteedSpawnTime;
|
||||
bool onCooldown = timeSinceLastSpawn < _settings.SpawnCooldown;
|
||||
|
||||
// Don't spawn if on cooldown, unless forced
|
||||
if (onCooldown && !forceSpawn) return;
|
||||
@@ -145,7 +145,7 @@ namespace Minigames.DivingForPictures
|
||||
// Reset timer and adjust probability
|
||||
lastSpawnTime = Time.time;
|
||||
timeSinceLastSpawn = 0f;
|
||||
currentSpawnProbability = _settings.EndlessDescenderBaseSpawnProbability;
|
||||
currentSpawnProbability = _settings.BaseSpawnProbability;
|
||||
OnSpawnProbabilityChanged?.Invoke(currentSpawnProbability);
|
||||
}
|
||||
}
|
||||
@@ -190,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) * _settings.EndlessDescenderDepthMultiplier);
|
||||
int pointsAwarded = _settings.EndlessDescenderBasePoints + depthBonus;
|
||||
int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * _settings.DepthMultiplier);
|
||||
int pointsAwarded = _settings.BasePoints + depthBonus;
|
||||
|
||||
// Add score
|
||||
playerScore += pointsAwarded;
|
||||
@@ -342,7 +342,7 @@ namespace Minigames.DivingForPictures
|
||||
_isSurfacing = true;
|
||||
|
||||
// 1. Initiate smooth velocity transition to surfacing speed
|
||||
float targetVelocityFactor = -1.0f * _settings.EndlessDescenderSurfacingSpeedFactor;
|
||||
float targetVelocityFactor = -1.0f * _settings.SurfacingSpeedFactor;
|
||||
SetVelocityFactor(targetVelocityFactor);
|
||||
|
||||
// 2. Find and notify trench tile spawner about direction change (for spawning/despawning logic)
|
||||
@@ -511,7 +511,7 @@ namespace Minigames.DivingForPictures
|
||||
private IEnumerator SurfacingSequence()
|
||||
{
|
||||
// Wait for the configured delay
|
||||
yield return new WaitForSeconds(_settings.EndlessDescenderSurfacingSpawnDelay);
|
||||
yield return new WaitForSeconds(_settings.SurfacingSpawnDelay);
|
||||
|
||||
// Find tile spawner and tell it to stop spawning
|
||||
TrenchTileSpawner tileSpawner = FindFirstObjectByType<TrenchTileSpawner>();
|
||||
@@ -580,10 +580,10 @@ namespace Minigames.DivingForPictures
|
||||
float startFactor = _currentVelocityFactor;
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < _settings.EndlessDescenderSpeedTransitionDuration)
|
||||
while (elapsed < _settings.SpeedTransitionDuration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / _settings.EndlessDescenderSpeedTransitionDuration);
|
||||
float t = Mathf.Clamp01(elapsed / _settings.SpeedTransitionDuration);
|
||||
|
||||
// Smooth step interpolation
|
||||
float smoothStep = t * t * (3f - 2f * t);
|
||||
|
||||
@@ -221,9 +221,9 @@ namespace Minigames.DivingForPictures
|
||||
while (true)
|
||||
{
|
||||
// Calculate next spawn time with variation
|
||||
float nextSpawnTime = _settings.EndlessDescenderObstacleSpawnInterval +
|
||||
Random.Range(-_settings.EndlessDescenderObstacleSpawnIntervalVariation,
|
||||
_settings.EndlessDescenderObstacleSpawnIntervalVariation);
|
||||
float nextSpawnTime = _settings.ObstacleSpawnInterval +
|
||||
Random.Range(-_settings.ObstacleSpawnIntervalVariation,
|
||||
_settings.ObstacleSpawnIntervalVariation);
|
||||
nextSpawnTime = Mathf.Max(0.1f, nextSpawnTime); // Ensure minimum interval
|
||||
|
||||
yield return new WaitForSeconds(nextSpawnTime);
|
||||
@@ -257,7 +257,7 @@ namespace Minigames.DivingForPictures
|
||||
bool foundValidPosition = false;
|
||||
|
||||
// Try to find a valid spawn position
|
||||
for (int attempts = 0; attempts < _settings.EndlessDescenderObstacleMaxSpawnAttempts; attempts++)
|
||||
for (int attempts = 0; attempts < _settings.ObstacleMaxSpawnAttempts; attempts++)
|
||||
{
|
||||
spawnPosition = GetRandomSpawnPosition();
|
||||
|
||||
@@ -270,13 +270,13 @@ namespace Minigames.DivingForPictures
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"[ObstacleSpawner] Position {spawnPosition} invalid (attempt {attempts + 1}/{_settings.EndlessDescenderObstacleMaxSpawnAttempts})");
|
||||
Debug.Log($"[ObstacleSpawner] Position {spawnPosition} invalid (attempt {attempts + 1}/{_settings.ObstacleMaxSpawnAttempts})");
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundValidPosition)
|
||||
{
|
||||
Debug.LogWarning($"[ObstacleSpawner] SPAWN MISSED: Could not find valid spawn position after {_settings.EndlessDescenderObstacleMaxSpawnAttempts} attempts at {Time.time:F2}");
|
||||
Debug.LogWarning($"[ObstacleSpawner] SPAWN MISSED: Could not find valid spawn position after {_settings.ObstacleMaxSpawnAttempts} attempts at {Time.time:F2}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ namespace Minigames.DivingForPictures
|
||||
{
|
||||
// Use OverlapCircle to check for collisions with tiles using just the layer
|
||||
// Convert the single layer to a layer mask inline (1 << layerNumber)
|
||||
Collider2D collision = Physics2D.OverlapCircle(position, _settings.EndlessDescenderObstacleSpawnCollisionRadius, 1 << _devSettings.TrenchTileLayer);
|
||||
Collider2D collision = Physics2D.OverlapCircle(position, _settings.ObstacleSpawnCollisionRadius, 1 << _devSettings.TrenchTileLayer);
|
||||
return collision == null;
|
||||
}
|
||||
|
||||
@@ -412,8 +412,8 @@ namespace Minigames.DivingForPictures
|
||||
|
||||
// Randomize properties using settings
|
||||
obstacleComponent.MoveSpeed = Random.Range(
|
||||
_settings.EndlessDescenderObstacleMinMoveSpeed,
|
||||
_settings.EndlessDescenderObstacleMaxMoveSpeed);
|
||||
_settings.ObstacleMinMoveSpeed,
|
||||
_settings.ObstacleMaxMoveSpeed);
|
||||
|
||||
// Set spawner reference (since FloatingObstacle has this built-in now)
|
||||
obstacleComponent.SetSpawner(this);
|
||||
@@ -544,7 +544,7 @@ namespace Minigames.DivingForPictures
|
||||
|
||||
// Draw collision radius at spawn point
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawWireSphere(center, _settings.EndlessDescenderObstacleSpawnCollisionRadius);
|
||||
Gizmos.DrawWireSphere(center, _settings.ObstacleSpawnCollisionRadius);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,14 @@ namespace Minigames.DivingForPictures
|
||||
|
||||
protected override void HandleCollisionResponse(Collider2D obstacle)
|
||||
{
|
||||
// Check if the obstacle is on the ObstacleLayer
|
||||
if (obstacle.gameObject.layer != _devSettings.ObstacleLayer)
|
||||
{
|
||||
// If not on the obstacle layer, don't process the collision
|
||||
Debug.Log($"[ObstacleCollision] Ignored collision with object on layer {obstacle.gameObject.layer} (expected {_devSettings.ObstacleLayer})");
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark the obstacle as having dealt damage to prevent multiple hits
|
||||
FloatingObstacle obstacleComponent = obstacle.GetComponent<FloatingObstacle>();
|
||||
if (obstacleComponent != null)
|
||||
@@ -43,7 +51,7 @@ namespace Minigames.DivingForPictures
|
||||
/// </summary>
|
||||
private void HandleImmunityStarted()
|
||||
{
|
||||
Debug.Log($"[ObstacleCollision] Damage immunity started for {_gameSettings.EndlessDescenderDamageImmunityDuration} seconds");
|
||||
Debug.Log($"[ObstacleCollision] Damage immunity started for {_gameSettings.DamageImmunityDuration} seconds");
|
||||
|
||||
// Don't block input for obstacle damage - let player keep moving
|
||||
// The shared immunity system will handle the collision prevention
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using AppleHills.Core.Settings;
|
||||
using AppleHills.Utilities;
|
||||
|
||||
namespace Minigames.DivingForPictures
|
||||
{
|
||||
@@ -27,6 +28,7 @@ namespace Minigames.DivingForPictures
|
||||
private static Coroutine _globalImmunityCoroutine;
|
||||
private static MonoBehaviour _coroutineRunner;
|
||||
private static Collider2D _sharedPlayerCollider;
|
||||
private static bool wasInputBlocked = false; // Track if input was blocked
|
||||
|
||||
// Events for immunity and damage state changes
|
||||
public static event Action OnImmunityStarted;
|
||||
@@ -117,8 +119,8 @@ namespace Minigames.DivingForPictures
|
||||
if (_isGloballyImmune)
|
||||
return;
|
||||
|
||||
// Check if the collider is an obstacle
|
||||
if ((_devSettings.PlayerObstacleLayerMask.value & (1 << other.gameObject.layer)) != 0)
|
||||
// Use our extension method to check if the collider's layer is in the obstacle layer mask
|
||||
if (_devSettings.PlayerObstacleLayerMask.Contains(other.gameObject))
|
||||
{
|
||||
HandleObstacleCollision(other);
|
||||
}
|
||||
@@ -179,6 +181,8 @@ namespace Minigames.DivingForPictures
|
||||
if (_devSettings.BlockInputDuringImmunity && playerController != null)
|
||||
{
|
||||
// Notify player controller to block input
|
||||
BlockPlayerInput();
|
||||
wasInputBlocked = true;
|
||||
}
|
||||
|
||||
// Trigger event for all listeners
|
||||
@@ -200,13 +204,57 @@ namespace Minigames.DivingForPictures
|
||||
private IEnumerator ImmunityTimerCoroutine()
|
||||
{
|
||||
// Wait for the immunity duration
|
||||
yield return new WaitForSeconds(_gameSettings.EndlessDescenderDamageImmunityDuration);
|
||||
yield return new WaitForSeconds(_gameSettings.DamageImmunityDuration);
|
||||
|
||||
// Reset immunity state
|
||||
_isGloballyImmune = false;
|
||||
|
||||
// Restore player input if it was blocked
|
||||
if (_devSettings.BlockInputDuringImmunity)
|
||||
{
|
||||
RestorePlayerInput();
|
||||
}
|
||||
|
||||
// Trigger event for all listeners
|
||||
OnImmunityEnded?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blocks player input during immunity
|
||||
/// </summary>
|
||||
protected virtual void BlockPlayerInput()
|
||||
{
|
||||
if (playerController != null && playerController.enabled)
|
||||
{
|
||||
playerController.enabled = false;
|
||||
wasInputBlocked = true;
|
||||
Debug.Log($"[{GetType().Name}] Player input blocked during immunity");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores player input after immunity
|
||||
/// </summary>
|
||||
protected virtual void RestorePlayerInput()
|
||||
{
|
||||
if (playerController != null && wasInputBlocked)
|
||||
{
|
||||
playerController.enabled = true;
|
||||
wasInputBlocked = false;
|
||||
|
||||
// Update the controller's target position to current position to prevent snapping
|
||||
UpdateControllerTarget();
|
||||
|
||||
Debug.Log($"[{GetType().Name}] Player input restored after immunity");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the player controller's target position to the current position to prevent snapping
|
||||
/// </summary>
|
||||
protected virtual void UpdateControllerTarget()
|
||||
{
|
||||
// This would normally be implemented in derived classes if needed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Minigames.DivingForPictures
|
||||
public void OnTap(Vector2 worldPosition)
|
||||
{
|
||||
// Debug.Log($"[EndlessDescenderController] OnTap at {worldPosition}");
|
||||
float targetX = Mathf.Clamp(worldPosition.x, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
|
||||
float targetX = Mathf.Clamp(worldPosition.x, _settings.ClampXMin, _settings.ClampXMax);
|
||||
|
||||
// Calculate tap direction (+1 for right, -1 for left)
|
||||
_tapDirection = Mathf.Sign(targetX - transform.position.x);
|
||||
@@ -68,7 +68,7 @@ namespace Minigames.DivingForPictures
|
||||
public void OnHoldStart(Vector2 worldPosition)
|
||||
{
|
||||
// Debug.Log($"[EndlessDescenderController] OnHoldStart at {worldPosition}");
|
||||
_targetFingerX = Mathf.Clamp(worldPosition.x, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
|
||||
_targetFingerX = Mathf.Clamp(worldPosition.x, _settings.ClampXMin, _settings.ClampXMax);
|
||||
_isTouchActive = true;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Minigames.DivingForPictures
|
||||
public void OnHoldMove(Vector2 worldPosition)
|
||||
{
|
||||
// Debug.Log($"[EndlessDescenderController] OnHoldMove at {worldPosition}");
|
||||
_targetFingerX = Mathf.Clamp(worldPosition.x, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
|
||||
_targetFingerX = Mathf.Clamp(worldPosition.x, _settings.ClampXMin, _settings.ClampXMax);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,9 +96,9 @@ namespace Minigames.DivingForPictures
|
||||
if (_isTouchActive)
|
||||
{
|
||||
float currentX = transform.position.x;
|
||||
float lerpSpeed = _settings.EndlessDescenderLerpSpeed;
|
||||
float maxOffset = _settings.EndlessDescenderMaxOffset;
|
||||
float exponent = _settings.EndlessDescenderSpeedExponent;
|
||||
float lerpSpeed = _settings.LerpSpeed;
|
||||
float maxOffset = _settings.MaxOffset;
|
||||
float exponent = _settings.SpeedExponent;
|
||||
float targetX = _targetFingerX;
|
||||
float offset = targetX - currentX;
|
||||
offset = Mathf.Clamp(offset, -maxOffset, maxOffset);
|
||||
@@ -108,7 +108,7 @@ namespace Minigames.DivingForPictures
|
||||
// Prevent overshooting
|
||||
moveStep = Mathf.Clamp(moveStep, -absOffset, absOffset);
|
||||
float newX = currentX + moveStep;
|
||||
newX = Mathf.Clamp(newX, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
|
||||
newX = Mathf.Clamp(newX, _settings.ClampXMin, _settings.ClampXMax);
|
||||
|
||||
UpdatePosition(newX);
|
||||
}
|
||||
@@ -116,21 +116,21 @@ namespace Minigames.DivingForPictures
|
||||
else if (_tapImpulseStrength > 0)
|
||||
{
|
||||
float currentX = transform.position.x;
|
||||
float maxOffset = _settings.EndlessDescenderMaxOffset;
|
||||
float lerpSpeed = _settings.EndlessDescenderLerpSpeed;
|
||||
float maxOffset = _settings.MaxOffset;
|
||||
float lerpSpeed = _settings.LerpSpeed;
|
||||
|
||||
// Calculate move distance based on impulse strength
|
||||
float moveDistance = maxOffset * _tapImpulseStrength * Time.deltaTime * lerpSpeed;
|
||||
|
||||
// Limit total movement from single tap
|
||||
moveDistance = Mathf.Min(moveDistance, _settings.EndlessDescenderTapMaxDistance * _tapImpulseStrength);
|
||||
moveDistance = Mathf.Min(moveDistance, _settings.TapMaxDistance * _tapImpulseStrength);
|
||||
|
||||
// Apply movement in tap direction
|
||||
float newX = currentX + (moveDistance * _tapDirection);
|
||||
newX = Mathf.Clamp(newX, _settings.EndlessDescenderClampXMin, _settings.EndlessDescenderClampXMax);
|
||||
newX = Mathf.Clamp(newX, _settings.ClampXMin, _settings.ClampXMax);
|
||||
|
||||
// Reduce impulse strength over time
|
||||
_tapImpulseStrength -= Time.deltaTime * _settings.EndlessDescenderTapDecelerationRate;
|
||||
_tapImpulseStrength -= Time.deltaTime * _settings.TapDecelerationRate;
|
||||
if (_tapImpulseStrength < 0.01f)
|
||||
{
|
||||
_tapImpulseStrength = 0f;
|
||||
|
||||
@@ -12,157 +12,139 @@ namespace Minigames.DivingForPictures
|
||||
{
|
||||
private bool _isBumping;
|
||||
private Coroutine _bumpCoroutine;
|
||||
private bool _bumpInputBlocked; // Tracks bump-specific input blocking
|
||||
|
||||
|
||||
protected override void HandleCollisionResponse(Collider2D obstacle)
|
||||
{
|
||||
// Check if the obstacle is on the TrenchTileLayer
|
||||
if (obstacle.gameObject.layer != _devSettings.TrenchTileLayer)
|
||||
{
|
||||
// If not on the trench tile layer, don't process the collision
|
||||
Debug.Log($"[TileBumpCollision] Ignored collision with object on layer {obstacle.gameObject.layer} (expected {_devSettings.TrenchTileLayer})");
|
||||
return;
|
||||
}
|
||||
|
||||
// Use bump mode from developer settings
|
||||
switch (_devSettings.BumpMode)
|
||||
{
|
||||
case 0: // Impulse mode
|
||||
case BumpMode.Impulse:
|
||||
StartImpulseBump();
|
||||
break;
|
||||
|
||||
case 1: // SmoothToCenter mode
|
||||
case BumpMode.SmoothToCenter:
|
||||
StartSmoothMoveToCenter();
|
||||
break;
|
||||
}
|
||||
|
||||
Debug.Log($"[TileBumpCollision] Collision handled with {(_devSettings.BumpMode == 0 ? "Impulse" : "SmoothToCenter")} mode");
|
||||
Debug.Log($"[TileBumpCollision] Collision handled with {_devSettings.BumpMode} mode");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies an impulse force toward center
|
||||
/// Starts an impulse bump toward the center with force-based distance
|
||||
/// </summary>
|
||||
private void StartImpulseBump()
|
||||
{
|
||||
if (_isBumping || playerCharacter == null)
|
||||
return;
|
||||
if (playerCharacter == null) return;
|
||||
|
||||
_isBumping = true;
|
||||
float currentX = playerCharacter.transform.position.x;
|
||||
|
||||
// Block input during bump if configured
|
||||
if (_gameSettings.EndlessDescenderBlockInputDuringBump && playerController != null)
|
||||
// Calculate bump distance based on force and current position
|
||||
float directionToCenter = currentX > 0 ? -1f : 1f; // Direction toward center
|
||||
|
||||
// Calculate target position - closer to center based on bump force
|
||||
float bumpDistance = _gameSettings.BumpForce * 0.2f; // Scale factor for distance
|
||||
float targetX = currentX + (directionToCenter * bumpDistance);
|
||||
|
||||
// Clamp to center if we would overshoot
|
||||
if ((currentX > 0 && targetX < 0) || (currentX < 0 && targetX > 0))
|
||||
{
|
||||
_bumpInputBlocked = true;
|
||||
// TODO: Implement input blocking
|
||||
targetX = 0f;
|
||||
}
|
||||
|
||||
// Calculate direction to center (X = 0)
|
||||
float directionToCenter = Mathf.Sign(-playerCharacter.transform.position.x);
|
||||
float bumpDuration = 0.5f; // Fixed duration for impulse
|
||||
|
||||
// Start impulse bump coroutine
|
||||
if (_bumpCoroutine != null)
|
||||
StopCoroutine(_bumpCoroutine);
|
||||
StartBump(currentX, targetX, bumpDuration);
|
||||
|
||||
_bumpCoroutine = StartCoroutine(ImpulseBumpCoroutine(directionToCenter));
|
||||
|
||||
Debug.Log($"[TileBumpCollision] Started impulse bump with force {_gameSettings.EndlessDescenderBumpForce} in direction {directionToCenter}");
|
||||
Debug.Log($"[TileBumpCollision] Starting impulse bump from X={currentX} to X={targetX} (force={_gameSettings.BumpForce})");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smoothly moves the player to center
|
||||
/// Starts smooth movement to the center
|
||||
/// </summary>
|
||||
private void StartSmoothMoveToCenter()
|
||||
{
|
||||
if (_isBumping || playerCharacter == null)
|
||||
return;
|
||||
if (playerCharacter == null) return;
|
||||
|
||||
float currentX = playerCharacter.transform.position.x;
|
||||
float distanceToCenter = Mathf.Abs(currentX);
|
||||
|
||||
float targetX = 0f; // Always move to center
|
||||
float bumpDuration = distanceToCenter / _gameSettings.SmoothMoveSpeed; // Duration based on distance and speed
|
||||
|
||||
StartBump(currentX, targetX, bumpDuration);
|
||||
|
||||
Debug.Log($"[TileBumpCollision] Starting smooth move to center from X={currentX} (speed={_gameSettings.SmoothMoveSpeed}, duration={bumpDuration:F2}s)");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common bump initialization using coroutines
|
||||
/// </summary>
|
||||
private void StartBump(float startX, float targetX, float duration)
|
||||
{
|
||||
// Stop any existing bump
|
||||
if (_bumpCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_bumpCoroutine);
|
||||
_bumpCoroutine = null;
|
||||
}
|
||||
|
||||
_isBumping = true;
|
||||
|
||||
// Block input during bump if configured
|
||||
if (_gameSettings.EndlessDescenderBlockInputDuringBump && playerController != null)
|
||||
{
|
||||
_bumpInputBlocked = true;
|
||||
// TODO: Implement input blocking
|
||||
}
|
||||
|
||||
// Start smooth move coroutine
|
||||
if (_bumpCoroutine != null)
|
||||
StopCoroutine(_bumpCoroutine);
|
||||
|
||||
_bumpCoroutine = StartCoroutine(SmoothMoveToCenterCoroutine());
|
||||
|
||||
Debug.Log($"[TileBumpCollision] Started smooth move to center with speed {_gameSettings.EndlessDescenderSmoothMoveSpeed}");
|
||||
// Start bump coroutine
|
||||
_bumpCoroutine = StartCoroutine(BumpCoroutine(startX, targetX, duration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine to handle impulse bump movement
|
||||
/// Coroutine that handles the bump movement over time
|
||||
/// </summary>
|
||||
private IEnumerator ImpulseBumpCoroutine(float direction)
|
||||
private IEnumerator BumpCoroutine(float startX, float targetX, float duration)
|
||||
{
|
||||
float elapsedTime = 0f;
|
||||
float bumpDuration = 0.5f; // Fixed duration for impulse
|
||||
Vector3 startPosition = playerCharacter.transform.position;
|
||||
|
||||
while (elapsedTime < bumpDuration)
|
||||
while (elapsedTime < duration)
|
||||
{
|
||||
elapsedTime += Time.deltaTime;
|
||||
|
||||
// Use evaluation time from curve for non-linear movement
|
||||
float t = elapsedTime / bumpDuration;
|
||||
float curveValue = _devSettings.BumpCurve.Evaluate(t);
|
||||
// Calculate progress and apply curve
|
||||
float progress = elapsedTime / duration;
|
||||
float curveValue = _devSettings.BumpCurve.Evaluate(progress);
|
||||
|
||||
// Calculate movement distance based on force and curve
|
||||
float distance = _gameSettings.EndlessDescenderBumpForce * curveValue * Time.deltaTime;
|
||||
// Interpolate position
|
||||
float currentX = Mathf.Lerp(startX, targetX, curveValue);
|
||||
|
||||
// Move the player toward center
|
||||
Vector3 newPosition = playerCharacter.transform.position;
|
||||
newPosition.x += direction * distance;
|
||||
|
||||
// Clamp to valid range
|
||||
newPosition.x = Mathf.Clamp(newPosition.x, _gameSettings.EndlessDescenderClampXMin, _gameSettings.EndlessDescenderClampXMax);
|
||||
|
||||
// Apply the position
|
||||
playerCharacter.transform.position = newPosition;
|
||||
// Apply the position to the player character
|
||||
if (playerCharacter != null)
|
||||
{
|
||||
Vector3 currentPos = playerCharacter.transform.position;
|
||||
currentPos.x = Mathf.Clamp(currentX, _gameSettings.ClampXMin, _gameSettings.ClampXMax);
|
||||
playerCharacter.transform.position = currentPos;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Finish bump
|
||||
_isBumping = false;
|
||||
_bumpInputBlocked = false;
|
||||
_bumpCoroutine = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine to handle smooth movement to center
|
||||
/// </summary>
|
||||
private IEnumerator SmoothMoveToCenterCoroutine()
|
||||
{
|
||||
Vector3 startPosition = playerCharacter.transform.position;
|
||||
Vector3 targetPosition = new Vector3(0f, startPosition.y, startPosition.z);
|
||||
|
||||
// Calculate distance to center and expected duration
|
||||
float distanceToCenter = Mathf.Abs(startPosition.x);
|
||||
float expectedDuration = distanceToCenter / _gameSettings.EndlessDescenderSmoothMoveSpeed;
|
||||
float elapsedTime = 0f;
|
||||
|
||||
// Move until we reach the center
|
||||
while (elapsedTime < expectedDuration)
|
||||
// Ensure we end exactly at target
|
||||
if (playerCharacter != null)
|
||||
{
|
||||
elapsedTime += Time.deltaTime;
|
||||
|
||||
// Calculate progress based on time and curve
|
||||
float t = elapsedTime / expectedDuration;
|
||||
float curveValue = _devSettings.BumpCurve.Evaluate(t);
|
||||
|
||||
// Calculate interpolated position
|
||||
Vector3 newPosition = Vector3.Lerp(startPosition, targetPosition, curveValue);
|
||||
|
||||
// Apply the position
|
||||
playerCharacter.transform.position = newPosition;
|
||||
|
||||
yield return null;
|
||||
Vector3 currentPos = playerCharacter.transform.position;
|
||||
float clampedTargetX = Mathf.Clamp(targetX, _gameSettings.ClampXMin, _gameSettings.ClampXMax);
|
||||
playerCharacter.transform.position = new Vector3(clampedTargetX, currentPos.y, currentPos.z);
|
||||
}
|
||||
|
||||
// Ensure we end at exactly the center
|
||||
playerCharacter.transform.position = targetPosition;
|
||||
|
||||
// Finish bump
|
||||
// Bump finished
|
||||
_isBumping = false;
|
||||
_bumpInputBlocked = false;
|
||||
_bumpCoroutine = null;
|
||||
|
||||
Debug.Log("[TileBumpCollision] Bump movement completed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace Minigames.DivingForPictures
|
||||
Debug.LogError("[TrenchTileSpawner] Failed to load diving developer settings!");
|
||||
}
|
||||
|
||||
_baseMoveSpeed = _settings?.EndlessDescenderMoveSpeed ?? 3f; // Store the original base speed
|
||||
_baseMoveSpeed = _settings?.MoveSpeed ?? 3f; // Store the original base speed
|
||||
|
||||
// Calculate tile heights for each prefab
|
||||
CalculateTileHeights();
|
||||
@@ -150,7 +150,7 @@ namespace Minigames.DivingForPictures
|
||||
while (true)
|
||||
{
|
||||
CalculateVelocity();
|
||||
yield return new WaitForSeconds(_settings.EndlessDescenderVelocityCalculationInterval);
|
||||
yield return new WaitForSeconds(_settings.VelocityCalculationInterval);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ namespace Minigames.DivingForPictures
|
||||
// Move starting position up by 2 tile heights
|
||||
startingY += tileHeightEstimate * 2;
|
||||
|
||||
for (int i = 0; i < _settings.EndlessDescenderInitialTileCount; i++)
|
||||
for (int i = 0; i < _settings.InitialTileCount; i++)
|
||||
{
|
||||
float y = startingY;
|
||||
// Calculate proper Y position based on previous tiles
|
||||
@@ -293,7 +293,7 @@ namespace Minigames.DivingForPictures
|
||||
|
||||
// Update the actual move speed based on the velocity factor
|
||||
// This keeps the original move speed intact for game logic
|
||||
_baseMoveSpeed = _settings.EndlessDescenderMoveSpeed * Mathf.Abs(_velocityFactor);
|
||||
_baseMoveSpeed = _settings.MoveSpeed * Mathf.Abs(_velocityFactor);
|
||||
|
||||
// Recalculate velocity immediately
|
||||
CalculateVelocity();
|
||||
@@ -364,12 +364,12 @@ namespace Minigames.DivingForPictures
|
||||
if (_isSurfacing)
|
||||
{
|
||||
// When surfacing, destroy tiles at the bottom
|
||||
shouldDestroy = topTile.transform.position.y + tileHeight / 2 < _screenBottom - _settings.EndlessDescenderTileSpawnBuffer;
|
||||
shouldDestroy = topTile.transform.position.y + tileHeight / 2 < _screenBottom - _settings.TileSpawnBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// When descending, destroy tiles at the top
|
||||
shouldDestroy = topTile.transform.position.y - tileHeight / 2 > _screenTop + _settings.EndlessDescenderTileSpawnBuffer;
|
||||
shouldDestroy = topTile.transform.position.y - tileHeight / 2 > _screenTop + _settings.TileSpawnBuffer;
|
||||
}
|
||||
|
||||
if (shouldDestroy)
|
||||
@@ -433,12 +433,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 + _settings.EndlessDescenderTileSpawnBuffer;
|
||||
isLastTileLeaving = bottomTile.transform.position.y - tileHeight / 2 > _screenTop + _settings.TileSpawnBuffer;
|
||||
}
|
||||
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 - _settings.EndlessDescenderTileSpawnBuffer;
|
||||
isLastTileLeaving = bottomTile.transform.position.y + tileHeight / 2 < _screenBottom - _settings.TileSpawnBuffer;
|
||||
}
|
||||
|
||||
if (isLastTileLeaving)
|
||||
@@ -456,14 +456,14 @@ namespace Minigames.DivingForPictures
|
||||
{
|
||||
// When surfacing, spawn new tiles at the top
|
||||
float topEdge = bottomTile.transform.position.y + tileHeight / 2;
|
||||
shouldSpawn = topEdge < _screenTop + _settings.EndlessDescenderTileSpawnBuffer;
|
||||
shouldSpawn = topEdge < _screenTop + _settings.TileSpawnBuffer;
|
||||
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 - _settings.EndlessDescenderTileSpawnBuffer;
|
||||
shouldSpawn = bottomEdge > _screenBottom - _settings.TileSpawnBuffer;
|
||||
newY = bottomTile.transform.position.y - tileHeight;
|
||||
}
|
||||
|
||||
@@ -479,9 +479,9 @@ namespace Minigames.DivingForPictures
|
||||
private void HandleSpeedRamping()
|
||||
{
|
||||
_speedUpTimer += Time.deltaTime;
|
||||
if (_speedUpTimer >= _settings.EndlessDescenderSpeedUpInterval)
|
||||
if (_speedUpTimer >= _settings.SpeedUpInterval)
|
||||
{
|
||||
_baseMoveSpeed = Mathf.Min(_baseMoveSpeed + _settings.EndlessDescenderSpeedUpFactor, _settings.EndlessDescenderMaxMoveSpeed);
|
||||
_baseMoveSpeed = Mathf.Min(_baseMoveSpeed + _settings.SpeedUpFactor, _settings.MaxMoveSpeed);
|
||||
_speedUpTimer = 0f;
|
||||
}
|
||||
}
|
||||
@@ -520,11 +520,25 @@ namespace Minigames.DivingForPictures
|
||||
tile.transform.position = new Vector3(0f, y, TileSpawnZ);
|
||||
tile.transform.rotation = prefab.transform.rotation;
|
||||
tile.transform.SetParent(transform);
|
||||
|
||||
// Set the layer to the configured trench tile layer
|
||||
if (_devSettings != null)
|
||||
{
|
||||
tile.layer = _devSettings.TrenchTileLayer;
|
||||
SetLayerRecursively(tile, _devSettings.TrenchTileLayer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the prefab's original rotation
|
||||
tile = Instantiate(prefab, new Vector3(0f, y, TileSpawnZ), prefab.transform.rotation, transform);
|
||||
|
||||
// Set the layer to the configured trench tile layer
|
||||
if (_devSettings != null)
|
||||
{
|
||||
tile.layer = _devSettings.TrenchTileLayer;
|
||||
SetLayerRecursively(tile, _devSettings.TrenchTileLayer);
|
||||
}
|
||||
}
|
||||
|
||||
_activeTiles.Add(tile);
|
||||
@@ -660,7 +674,7 @@ namespace Minigames.DivingForPictures
|
||||
Gizmos.color = Color.cyan;
|
||||
if (_settings != null)
|
||||
{
|
||||
for (int i = 0; i < _settings.EndlessDescenderInitialTileCount; i++)
|
||||
for (int i = 0; i < _settings.InitialTileCount; i++)
|
||||
{
|
||||
float height = DefaultTileHeight;
|
||||
if (tilePrefabs != null && tilePrefabs.Count > 0 && tilePrefabs[0] != null &&
|
||||
@@ -674,5 +688,25 @@ namespace Minigames.DivingForPictures
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Set the layer of a GameObject and all its children recursively
|
||||
/// </summary>
|
||||
/// <param name="obj">The GameObject to set the layer for</param>
|
||||
/// <param name="layer">The layer index to set</param>
|
||||
private void SetLayerRecursively(GameObject obj, int layer)
|
||||
{
|
||||
if (obj == null) return;
|
||||
|
||||
obj.layer = layer;
|
||||
|
||||
foreach (Transform child in obj.transform)
|
||||
{
|
||||
if (child != null)
|
||||
{
|
||||
SetLayerRecursively(child.gameObject, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user