diff --git a/Assets/AddressableAssetsData/AssetGroups/Settings.asset b/Assets/AddressableAssetsData/AssetGroups/Settings.asset index c2281311..81aa8648 100644 --- a/Assets/AddressableAssetsData/AssetGroups/Settings.asset +++ b/Assets/AddressableAssetsData/AssetGroups/Settings.asset @@ -31,7 +31,7 @@ MonoBehaviour: m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 - m_GUID: a9569848f604a6540827d4d4bb0a35c2 - m_Address: Settings/MinigameSettings + m_Address: Settings/DivingMinigameSettings m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 diff --git a/Assets/Prefabs/Minigames/DivingForPictures/FloatingObstacle.prefab b/Assets/Prefabs/Minigames/DivingForPictures/FloatingObstacle.prefab index fb73fd83..bdc5d45b 100644 --- a/Assets/Prefabs/Minigames/DivingForPictures/FloatingObstacle.prefab +++ b/Assets/Prefabs/Minigames/DivingForPictures/FloatingObstacle.prefab @@ -47,7 +47,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: prefabIndex: 0 - damage: 1 moveSpeed: 2 enableMovement: 1 spawner: {fileID: 0} diff --git a/Assets/Scripts/Core/GameManager.cs b/Assets/Scripts/Core/GameManager.cs index de19a105..0797b577 100644 --- a/Assets/Scripts/Core/GameManager.cs +++ b/Assets/Scripts/Core/GameManager.cs @@ -222,22 +222,4 @@ public class GameManager : MonoBehaviour } return null; } - - // MINIGAME SETTINGS - - // Endless Descender settings - public float EndlessDescenderLerpSpeed => GetSettings()?.EndlessDescenderLerpSpeed ?? 12f; - public float EndlessDescenderMaxOffset => GetSettings()?.EndlessDescenderMaxOffset ?? 3f; - public float EndlessDescenderClampXMin => GetSettings()?.EndlessDescenderClampXMin ?? -3.5f; - public float EndlessDescenderClampXMax => GetSettings()?.EndlessDescenderClampXMax ?? 3.5f; - public float EndlessDescenderSpeedExponent => GetSettings()?.EndlessDescenderSpeedExponent ?? 2.5f; - public float EndlessDescenderTapMaxDistance => GetSettings()?.EndlessDescenderTapMaxDistance ?? 0.5f; - public float EndlessDescenderTapDecelerationRate => GetSettings()?.EndlessDescenderTapDecelerationRate ?? 5.0f; - public int EndlessDescenderInitialTileCount => GetSettings()?.EndlessDescenderInitialTileCount ?? 3; - public float EndlessDescenderTileSpawnBuffer => GetSettings()?.EndlessDescenderTileSpawnBuffer ?? 1f; - public float EndlessDescenderMoveSpeed => GetSettings()?.EndlessDescenderMoveSpeed ?? 3f; - public float EndlessDescenderSpeedUpFactor => GetSettings()?.EndlessDescenderSpeedUpFactor ?? 0.2f; - public float EndlessDescenderSpeedUpInterval => GetSettings()?.EndlessDescenderSpeedUpInterval ?? 10f; - public float EndlessDescenderMaxMoveSpeed => GetSettings()?.EndlessDescenderMaxMoveSpeed ?? 12f; - public float EndlessDescenderVelocityCalculationInterval => GetSettings()?.EndlessDescenderVelocityCalculationInterval ?? 0.5f; } diff --git a/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs b/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs index b35e2412..69a233d7 100644 --- a/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs +++ b/Assets/Scripts/Core/Settings/DivingDeveloperSettings.cs @@ -2,6 +2,15 @@ namespace AppleHills.Core.Settings { + /// + /// Enum defining the type of bump response when player collides with obstacles + /// + public enum BumpMode + { + Impulse = 0, + SmoothToCenter = 1 + } + /// /// Developer settings for the diving minigame technical configuration. /// These settings are separate from gameplay/design settings and focus on technical implementation details. @@ -125,7 +134,7 @@ namespace AppleHills.Core.Settings [SerializeField] private bool blockInputDuringImmunity = true; [Tooltip("Type of bump response: 0=Impulse, 1=SmoothToCenter")] - [SerializeField] private int bumpMode = 0; + [SerializeField] private BumpMode bumpMode = BumpMode.Impulse; [Tooltip("Animation curve controlling bump movement over time")] [SerializeField] private AnimationCurve bumpCurve = new AnimationCurve( @@ -178,7 +187,7 @@ namespace AppleHills.Core.Settings // Collision Settings properties public LayerMask PlayerObstacleLayerMask => playerObstacleLayerMask; public bool BlockInputDuringImmunity => blockInputDuringImmunity; - public int BumpMode => bumpMode; + public BumpMode BumpMode => bumpMode; public AnimationCurve BumpCurve => bumpCurve; public override void OnValidate() @@ -231,7 +240,7 @@ namespace AppleHills.Core.Settings playerRotationSmoothing = Mathf.Max(0.1f, playerRotationSmoothing); // Validate Collision settings - bumpMode = Mathf.Clamp(bumpMode, 0, 1); + bumpMode = (BumpMode)Mathf.Clamp((int)bumpMode, 0, 1); } } } diff --git a/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs b/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs index b53e3103..f12da829 100644 --- a/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs +++ b/Assets/Scripts/Core/Settings/DivingMinigameSettings.cs @@ -8,227 +8,227 @@ namespace AppleHills.Core.Settings [CreateAssetMenu(fileName = "MinigameSettings", menuName = "AppleHills/Settings/Minigames", order = 3)] public class DivingMinigameSettings : BaseSettings, IDivingMinigameSettings { - [Header("Endless Descender - Basic Movement")] + [Header("Basic Movement")] [Tooltip("How quickly the character follows the finger horizontally (higher = more responsive)")] - [SerializeField] private float endlessDescenderLerpSpeed = 12f; + [SerializeField] private float lerpSpeed = 12f; [Tooltip("Maximum horizontal offset allowed between character and finger position")] - [SerializeField] private float endlessDescenderMaxOffset = 3f; + [SerializeField] private float maxOffset = 3f; - [Tooltip("Minimum allowed X position for endless descender movement")] - [SerializeField] private float endlessDescenderClampXMin = -3.5f; + [Tooltip("Minimum allowed X position for movement")] + [SerializeField] private float clampXMin = -3.5f; - [Tooltip("Maximum allowed X position for endless descender movement")] - [SerializeField] private float endlessDescenderClampXMax = 3.5f; + [Tooltip("Maximum allowed X position for movement")] + [SerializeField] private float clampXMax = 3.5f; [Tooltip("Exponent for speed drop-off curve (higher = sharper drop near target)")] - [SerializeField] private float endlessDescenderSpeedExponent = 2.5f; + [SerializeField] private float speedExponent = 2.5f; - [Header("Endless Descender - Player Movement")] + [Header("Player Movement")] [Tooltip("Maximum distance the player can move from a single tap")] - [SerializeField] private float endlessDescenderTapMaxDistance = 0.5f; + [SerializeField] private float tapMaxDistance = 0.5f; [Tooltip("How quickly the tap impulse fades (higher = faster stop)")] - [SerializeField] private float endlessDescenderTapDecelerationRate = 5.0f; + [SerializeField] private float tapDecelerationRate = 5.0f; - [Header("Endless Descender - Monster Spawning")] + [Header("Monster Spawning")] [Tooltip("Base chance (0-1) of spawning a monster on each tile")] - [SerializeField] private float endlessDescenderBaseSpawnProbability = 0.2f; + [SerializeField] private float baseSpawnProbability = 0.2f; [Tooltip("Maximum chance (0-1) of spawning a monster")] - [SerializeField] private float endlessDescenderMaxSpawnProbability = 0.5f; + [SerializeField] private float maxSpawnProbability = 0.5f; [Tooltip("How fast the probability increases per second")] - [SerializeField] private float endlessDescenderProbabilityIncreaseRate = 0.01f; + [SerializeField] private float probabilityIncreaseRate = 0.01f; [Tooltip("Force a spawn after this many seconds without spawns")] - [SerializeField] private float endlessDescenderGuaranteedSpawnTime = 30f; + [SerializeField] private float guaranteedSpawnTime = 30f; [Tooltip("Minimum time between monster spawns")] - [SerializeField] private float endlessDescenderSpawnCooldown = 5f; + [SerializeField] private float spawnCooldown = 5f; - [Header("Endless Descender - Scoring")] + [Header("Scoring")] [Tooltip("Base points for taking a picture")] - [SerializeField] private int endlessDescenderBasePoints = 100; + [SerializeField] private int basePoints = 100; [Tooltip("Additional points per depth unit")] - [SerializeField] private int endlessDescenderDepthMultiplier = 10; + [SerializeField] private int depthMultiplier = 10; - [Header("Endless Descender - Surfacing")] + [Header("Surfacing")] [Tooltip("Duration in seconds for speed transition when surfacing")] - [SerializeField] private float endlessDescenderSpeedTransitionDuration = 2.0f; + [SerializeField] private float speedTransitionDuration = 2.0f; [Tooltip("Factor to multiply speed by when surfacing (usually 1.0 for same speed)")] - [SerializeField] private float endlessDescenderSurfacingSpeedFactor = 3.0f; + [SerializeField] private float surfacingSpeedFactor = 3.0f; [Tooltip("How long to continue spawning tiles after surfacing begins (seconds)")] - [SerializeField] private float endlessDescenderSurfacingSpawnDelay = 5.0f; + [SerializeField] private float surfacingSpawnDelay = 5.0f; - [Header("Endless Descender - Tile Generation")] + [Header("Tile Generation")] [Tooltip("Initial number of tiles to create at start")] - [SerializeField] private int endlessDescenderInitialTileCount = 3; + [SerializeField] private int initialTileCount = 3; [Tooltip("Buffer distance for spawning new tiles")] - [SerializeField] private float endlessDescenderTileSpawnBuffer = 1f; + [SerializeField] private float tileSpawnBuffer = 1f; [Tooltip("Base movement speed for tiles")] - [SerializeField] private float endlessDescenderMoveSpeed = 3f; + [SerializeField] private float moveSpeed = 3f; [Tooltip("Factor to increase speed by each interval")] - [SerializeField] private float endlessDescenderSpeedUpFactor = 0.2f; + [SerializeField] private float speedUpFactor = 0.2f; [Tooltip("Time interval between speed increases (seconds)")] - [SerializeField] private float endlessDescenderSpeedUpInterval = 10f; + [SerializeField] private float speedUpInterval = 10f; [Tooltip("Maximum movement speed allowed")] - [SerializeField] private float endlessDescenderMaxMoveSpeed = 12f; + [SerializeField] private float maxMoveSpeed = 12f; [Tooltip("Interval for velocity calculations (seconds)")] - [SerializeField] private float endlessDescenderVelocityCalculationInterval = 0.5f; + [SerializeField] private float velocityCalculationInterval = 0.5f; - [Header("Endless Descender - Obstacles")] + [Header("Obstacles")] [Tooltip("Time interval between obstacle spawn attempts (in seconds)")] - [SerializeField] private float endlessDescenderObstacleSpawnInterval = 2f; + [SerializeField] private float obstacleSpawnInterval = 2f; [Tooltip("Random variation in obstacle spawn timing (+/- seconds)")] - [SerializeField] private float endlessDescenderObstacleSpawnIntervalVariation = 0.5f; + [SerializeField] private float obstacleSpawnIntervalVariation = 0.5f; [Tooltip("Maximum number of obstacle spawn position attempts before skipping")] - [SerializeField] private int endlessDescenderObstacleMaxSpawnAttempts = 10; + [SerializeField] private int obstacleMaxSpawnAttempts = 10; [Tooltip("Radius around obstacle spawn point to check for tile collisions")] - [SerializeField] private float endlessDescenderObstacleSpawnCollisionRadius = 1f; + [SerializeField] private float obstacleSpawnCollisionRadius = 1f; [Tooltip("Minimum movement speed for spawned obstacles")] - [SerializeField] private float endlessDescenderObstacleMinMoveSpeed = 1f; + [SerializeField] private float obstacleMinMoveSpeed = 1f; [Tooltip("Maximum movement speed for spawned obstacles")] - [SerializeField] private float endlessDescenderObstacleMaxMoveSpeed = 4f; + [SerializeField] private float obstacleMaxMoveSpeed = 4f; - [Header("Endless Descender - Collision Handling")] + [Header("Collision Handling")] [Tooltip("Duration in seconds of damage immunity after being hit")] - [SerializeField] private float endlessDescenderDamageImmunityDuration = 1.0f; + [SerializeField] private float damageImmunityDuration = 1.0f; [Tooltip("Force strength for impulse bumps - higher values push further toward center")] - [SerializeField] private float endlessDescenderBumpForce = 5.0f; + [SerializeField] private float bumpForce = 5.0f; [Tooltip("Speed for smooth movement to center (units per second)")] - [SerializeField] private float endlessDescenderSmoothMoveSpeed = 8.0f; + [SerializeField] private float smoothMoveSpeed = 8.0f; [Tooltip("Whether to block player input during bump movement")] - [SerializeField] private bool endlessDescenderBlockInputDuringBump = true; + [SerializeField] private bool blockInputDuringBump = true; - // IMinigameSettings implementation - Basic Movement - public float EndlessDescenderLerpSpeed => endlessDescenderLerpSpeed; - public float EndlessDescenderMaxOffset => endlessDescenderMaxOffset; - public float EndlessDescenderClampXMin => endlessDescenderClampXMin; - public float EndlessDescenderClampXMax => endlessDescenderClampXMax; - public float EndlessDescenderSpeedExponent => endlessDescenderSpeedExponent; + // IDivingMinigameSettings implementation - Basic Movement + public float LerpSpeed => lerpSpeed; + public float MaxOffset => maxOffset; + public float ClampXMin => clampXMin; + public float ClampXMax => clampXMax; + public float SpeedExponent => speedExponent; - // IMinigameSettings implementation - Player Movement - public float EndlessDescenderTapMaxDistance => endlessDescenderTapMaxDistance; - public float EndlessDescenderTapDecelerationRate => endlessDescenderTapDecelerationRate; + // IDivingMinigameSettings implementation - Player Movement + public float TapMaxDistance => tapMaxDistance; + public float TapDecelerationRate => tapDecelerationRate; - // IMinigameSettings implementation - Monster Spawning - public float EndlessDescenderBaseSpawnProbability => endlessDescenderBaseSpawnProbability; - public float EndlessDescenderMaxSpawnProbability => endlessDescenderMaxSpawnProbability; - public float EndlessDescenderProbabilityIncreaseRate => endlessDescenderProbabilityIncreaseRate; - public float EndlessDescenderGuaranteedSpawnTime => endlessDescenderGuaranteedSpawnTime; - public float EndlessDescenderSpawnCooldown => endlessDescenderSpawnCooldown; + // IDivingMinigameSettings implementation - Monster Spawning + public float BaseSpawnProbability => baseSpawnProbability; + public float MaxSpawnProbability => maxSpawnProbability; + public float ProbabilityIncreaseRate => probabilityIncreaseRate; + public float GuaranteedSpawnTime => guaranteedSpawnTime; + public float SpawnCooldown => spawnCooldown; - // IMinigameSettings implementation - Scoring - public int EndlessDescenderBasePoints => endlessDescenderBasePoints; - public int EndlessDescenderDepthMultiplier => endlessDescenderDepthMultiplier; + // IDivingMinigameSettings implementation - Scoring + public int BasePoints => basePoints; + public int DepthMultiplier => depthMultiplier; - // IMinigameSettings implementation - Surfacing - public float EndlessDescenderSpeedTransitionDuration => endlessDescenderSpeedTransitionDuration; - public float EndlessDescenderSurfacingSpeedFactor => endlessDescenderSurfacingSpeedFactor; - public float EndlessDescenderSurfacingSpawnDelay => endlessDescenderSurfacingSpawnDelay; + // IDivingMinigameSettings implementation - Surfacing + public float SpeedTransitionDuration => speedTransitionDuration; + public float SurfacingSpeedFactor => surfacingSpeedFactor; + public float SurfacingSpawnDelay => surfacingSpawnDelay; - // IMinigameSettings implementation - Tile Generation - public int EndlessDescenderInitialTileCount => endlessDescenderInitialTileCount; - public float EndlessDescenderTileSpawnBuffer => endlessDescenderTileSpawnBuffer; - public float EndlessDescenderMoveSpeed => endlessDescenderMoveSpeed; - public float EndlessDescenderSpeedUpFactor => endlessDescenderSpeedUpFactor; - public float EndlessDescenderSpeedUpInterval => endlessDescenderSpeedUpInterval; - public float EndlessDescenderMaxMoveSpeed => endlessDescenderMaxMoveSpeed; - public float EndlessDescenderVelocityCalculationInterval => endlessDescenderVelocityCalculationInterval; + // IDivingMinigameSettings implementation - Tile Generation + public int InitialTileCount => initialTileCount; + public float TileSpawnBuffer => tileSpawnBuffer; + public float MoveSpeed => moveSpeed; + public float SpeedUpFactor => speedUpFactor; + public float SpeedUpInterval => speedUpInterval; + public float MaxMoveSpeed => maxMoveSpeed; + public float VelocityCalculationInterval => velocityCalculationInterval; - // IMinigameSettings implementation - Obstacles - public float EndlessDescenderObstacleSpawnInterval => endlessDescenderObstacleSpawnInterval; - public float EndlessDescenderObstacleSpawnIntervalVariation => endlessDescenderObstacleSpawnIntervalVariation; - public int EndlessDescenderObstacleMaxSpawnAttempts => endlessDescenderObstacleMaxSpawnAttempts; - public float EndlessDescenderObstacleSpawnCollisionRadius => endlessDescenderObstacleSpawnCollisionRadius; - public float EndlessDescenderObstacleMinMoveSpeed => endlessDescenderObstacleMinMoveSpeed; - public float EndlessDescenderObstacleMaxMoveSpeed => endlessDescenderObstacleMaxMoveSpeed; + // IDivingMinigameSettings implementation - Obstacles + public float ObstacleSpawnInterval => obstacleSpawnInterval; + public float ObstacleSpawnIntervalVariation => obstacleSpawnIntervalVariation; + public int ObstacleMaxSpawnAttempts => obstacleMaxSpawnAttempts; + public float ObstacleSpawnCollisionRadius => obstacleSpawnCollisionRadius; + public float ObstacleMinMoveSpeed => obstacleMinMoveSpeed; + public float ObstacleMaxMoveSpeed => obstacleMaxMoveSpeed; - // IMinigameSettings implementation - Collision Handling - public float EndlessDescenderDamageImmunityDuration => endlessDescenderDamageImmunityDuration; - public float EndlessDescenderBumpForce => endlessDescenderBumpForce; - public float EndlessDescenderSmoothMoveSpeed => endlessDescenderSmoothMoveSpeed; - public bool EndlessDescenderBlockInputDuringBump => endlessDescenderBlockInputDuringBump; + // IDivingMinigameSettings implementation - Collision Handling + public float DamageImmunityDuration => damageImmunityDuration; + public float BumpForce => bumpForce; + public float SmoothMoveSpeed => smoothMoveSpeed; + public bool BlockInputDuringBump => blockInputDuringBump; public override void OnValidate() { base.OnValidate(); // Validate basic movement values - endlessDescenderLerpSpeed = Mathf.Max(0.1f, endlessDescenderLerpSpeed); - endlessDescenderMaxOffset = Mathf.Max(0.1f, endlessDescenderMaxOffset); - endlessDescenderSpeedExponent = Mathf.Max(0.1f, endlessDescenderSpeedExponent); + lerpSpeed = Mathf.Max(0.1f, lerpSpeed); + maxOffset = Mathf.Max(0.1f, maxOffset); + speedExponent = Mathf.Max(0.1f, speedExponent); // Ensure min is less than max for clamping - if (endlessDescenderClampXMin >= endlessDescenderClampXMax) + if (clampXMin >= clampXMax) { - endlessDescenderClampXMin = endlessDescenderClampXMax - 0.1f; + clampXMin = clampXMax - 0.1f; } // Validate player movement - endlessDescenderTapMaxDistance = Mathf.Max(0.01f, endlessDescenderTapMaxDistance); - endlessDescenderTapDecelerationRate = Mathf.Max(0.1f, endlessDescenderTapDecelerationRate); + tapMaxDistance = Mathf.Max(0.01f, tapMaxDistance); + tapDecelerationRate = Mathf.Max(0.1f, tapDecelerationRate); // Validate probability values - endlessDescenderBaseSpawnProbability = Mathf.Clamp01(endlessDescenderBaseSpawnProbability); - endlessDescenderMaxSpawnProbability = Mathf.Clamp01(endlessDescenderMaxSpawnProbability); - endlessDescenderProbabilityIncreaseRate = Mathf.Max(0f, endlessDescenderProbabilityIncreaseRate); + baseSpawnProbability = Mathf.Clamp01(baseSpawnProbability); + maxSpawnProbability = Mathf.Clamp01(maxSpawnProbability); + probabilityIncreaseRate = Mathf.Max(0f, probabilityIncreaseRate); // Ensure max probability is at least base probability - if (endlessDescenderMaxSpawnProbability < endlessDescenderBaseSpawnProbability) + if (maxSpawnProbability < baseSpawnProbability) { - endlessDescenderMaxSpawnProbability = endlessDescenderBaseSpawnProbability; + maxSpawnProbability = baseSpawnProbability; } // Validate time values - endlessDescenderGuaranteedSpawnTime = Mathf.Max(0.1f, endlessDescenderGuaranteedSpawnTime); - endlessDescenderSpawnCooldown = Mathf.Max(0.1f, endlessDescenderSpawnCooldown); - endlessDescenderSpeedTransitionDuration = Mathf.Max(0.1f, endlessDescenderSpeedTransitionDuration); - endlessDescenderSurfacingSpawnDelay = Mathf.Max(0f, endlessDescenderSurfacingSpawnDelay); + guaranteedSpawnTime = Mathf.Max(0.1f, guaranteedSpawnTime); + spawnCooldown = Mathf.Max(0.1f, spawnCooldown); + speedTransitionDuration = Mathf.Max(0.1f, speedTransitionDuration); + surfacingSpawnDelay = Mathf.Max(0f, surfacingSpawnDelay); // Validate scoring - endlessDescenderBasePoints = Mathf.Max(0, endlessDescenderBasePoints); - endlessDescenderDepthMultiplier = Mathf.Max(0, endlessDescenderDepthMultiplier); + basePoints = Mathf.Max(0, basePoints); + depthMultiplier = Mathf.Max(0, depthMultiplier); // Validate tile generation - endlessDescenderInitialTileCount = Mathf.Max(1, endlessDescenderInitialTileCount); - endlessDescenderTileSpawnBuffer = Mathf.Max(0f, endlessDescenderTileSpawnBuffer); - endlessDescenderMoveSpeed = Mathf.Max(0.1f, endlessDescenderMoveSpeed); - endlessDescenderSpeedUpFactor = Mathf.Max(0f, endlessDescenderSpeedUpFactor); - endlessDescenderSpeedUpInterval = Mathf.Max(0.1f, endlessDescenderSpeedUpInterval); - endlessDescenderMaxMoveSpeed = Mathf.Max(endlessDescenderMoveSpeed, endlessDescenderMaxMoveSpeed); - endlessDescenderVelocityCalculationInterval = Mathf.Max(0.01f, endlessDescenderVelocityCalculationInterval); + initialTileCount = Mathf.Max(1, initialTileCount); + tileSpawnBuffer = Mathf.Max(0f, tileSpawnBuffer); + moveSpeed = Mathf.Max(0.1f, moveSpeed); + speedUpFactor = Mathf.Max(0f, speedUpFactor); + speedUpInterval = Mathf.Max(0.1f, speedUpInterval); + maxMoveSpeed = Mathf.Max(moveSpeed, maxMoveSpeed); + velocityCalculationInterval = Mathf.Max(0.01f, velocityCalculationInterval); // Validate obstacle values - endlessDescenderObstacleSpawnInterval = Mathf.Max(0.1f, endlessDescenderObstacleSpawnInterval); - endlessDescenderObstacleSpawnIntervalVariation = Mathf.Max(0f, endlessDescenderObstacleSpawnIntervalVariation); - endlessDescenderObstacleMaxSpawnAttempts = Mathf.Max(1, endlessDescenderObstacleMaxSpawnAttempts); - endlessDescenderObstacleSpawnCollisionRadius = Mathf.Max(0.1f, endlessDescenderObstacleSpawnCollisionRadius); - endlessDescenderObstacleMinMoveSpeed = Mathf.Max(0.1f, endlessDescenderObstacleMinMoveSpeed); - endlessDescenderObstacleMaxMoveSpeed = Mathf.Max(endlessDescenderObstacleMinMoveSpeed, endlessDescenderObstacleMaxMoveSpeed); + obstacleSpawnInterval = Mathf.Max(0.1f, obstacleSpawnInterval); + obstacleSpawnIntervalVariation = Mathf.Max(0f, obstacleSpawnIntervalVariation); + obstacleMaxSpawnAttempts = Mathf.Max(1, obstacleMaxSpawnAttempts); + obstacleSpawnCollisionRadius = Mathf.Max(0.1f, obstacleSpawnCollisionRadius); + obstacleMinMoveSpeed = Mathf.Max(0.1f, obstacleMinMoveSpeed); + obstacleMaxMoveSpeed = Mathf.Max(obstacleMinMoveSpeed, obstacleMaxMoveSpeed); // Validate collision settings - endlessDescenderDamageImmunityDuration = Mathf.Max(0.1f, endlessDescenderDamageImmunityDuration); - endlessDescenderBumpForce = Mathf.Max(0.1f, endlessDescenderBumpForce); - endlessDescenderSmoothMoveSpeed = Mathf.Max(0.1f, endlessDescenderSmoothMoveSpeed); + damageImmunityDuration = Mathf.Max(0.1f, damageImmunityDuration); + bumpForce = Mathf.Max(0.1f, bumpForce); + smoothMoveSpeed = Mathf.Max(0.1f, smoothMoveSpeed); } } } diff --git a/Assets/Scripts/Core/Settings/SettingsInterfaces.cs b/Assets/Scripts/Core/Settings/SettingsInterfaces.cs index dc77aaa9..33da8d20 100644 --- a/Assets/Scripts/Core/Settings/SettingsInterfaces.cs +++ b/Assets/Scripts/Core/Settings/SettingsInterfaces.cs @@ -45,54 +45,54 @@ namespace AppleHills.Core.Settings /// public interface IDivingMinigameSettings { - // Endless Descender settings - Basic Movement - float EndlessDescenderLerpSpeed { get; } - float EndlessDescenderMaxOffset { get; } - float EndlessDescenderClampXMin { get; } - float EndlessDescenderClampXMax { get; } - float EndlessDescenderSpeedExponent { get; } + // Basic Movement + float LerpSpeed { get; } + float MaxOffset { get; } + float ClampXMin { get; } + float ClampXMax { get; } + float SpeedExponent { get; } - // Endless Descender - Player Movement - float EndlessDescenderTapMaxDistance { get; } - float EndlessDescenderTapDecelerationRate { get; } + // Player Movement + float TapMaxDistance { get; } + float TapDecelerationRate { get; } - // Endless Descender - Monster Spawning - float EndlessDescenderBaseSpawnProbability { get; } - float EndlessDescenderMaxSpawnProbability { get; } - float EndlessDescenderProbabilityIncreaseRate { get; } - float EndlessDescenderGuaranteedSpawnTime { get; } - float EndlessDescenderSpawnCooldown { get; } + // Monster Spawning + float BaseSpawnProbability { get; } + float MaxSpawnProbability { get; } + float ProbabilityIncreaseRate { get; } + float GuaranteedSpawnTime { get; } + float SpawnCooldown { get; } - // Endless Descender - Scoring - int EndlessDescenderBasePoints { get; } - int EndlessDescenderDepthMultiplier { get; } + // Scoring + int BasePoints { get; } + int DepthMultiplier { get; } - // Endless Descender - Surfacing - float EndlessDescenderSpeedTransitionDuration { get; } - float EndlessDescenderSurfacingSpeedFactor { get; } - float EndlessDescenderSurfacingSpawnDelay { get; } + // Surfacing + float SpeedTransitionDuration { get; } + float SurfacingSpeedFactor { get; } + float SurfacingSpawnDelay { get; } - // Endless Descender - Tile Generation - int EndlessDescenderInitialTileCount { get; } - float EndlessDescenderTileSpawnBuffer { get; } - float EndlessDescenderMoveSpeed { get; } - float EndlessDescenderSpeedUpFactor { get; } - float EndlessDescenderSpeedUpInterval { get; } - float EndlessDescenderMaxMoveSpeed { get; } - float EndlessDescenderVelocityCalculationInterval { get; } + // Tile Generation + int InitialTileCount { get; } + float TileSpawnBuffer { get; } + float MoveSpeed { get; } + float SpeedUpFactor { get; } + float SpeedUpInterval { get; } + float MaxMoveSpeed { get; } + float VelocityCalculationInterval { get; } - // Endless Descender - Obstacles - float EndlessDescenderObstacleSpawnInterval { get; } - float EndlessDescenderObstacleSpawnIntervalVariation { get; } - int EndlessDescenderObstacleMaxSpawnAttempts { get; } - float EndlessDescenderObstacleSpawnCollisionRadius { get; } - float EndlessDescenderObstacleMinMoveSpeed { get; } - float EndlessDescenderObstacleMaxMoveSpeed { get; } + // Obstacles + float ObstacleSpawnInterval { get; } + float ObstacleSpawnIntervalVariation { get; } + int ObstacleMaxSpawnAttempts { get; } + float ObstacleSpawnCollisionRadius { get; } + float ObstacleMinMoveSpeed { get; } + float ObstacleMaxMoveSpeed { get; } - // Endless Descender - Collision Handling - float EndlessDescenderDamageImmunityDuration { get; } - float EndlessDescenderBumpForce { get; } - float EndlessDescenderSmoothMoveSpeed { get; } - bool EndlessDescenderBlockInputDuringBump { get; } + // Collision Handling + float DamageImmunityDuration { get; } + float BumpForce { get; } + float SmoothMoveSpeed { get; } + bool BlockInputDuringBump { get; } } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs index 1d3ddc1d..1b15d77b 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/DivingGameManager.cs @@ -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(); @@ -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); diff --git a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs index 27860d65..311c2e94 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleSpawner.cs @@ -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 diff --git a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleCollision.cs b/Assets/Scripts/Minigames/DivingForPictures/Player/ObstacleCollision.cs similarity index 81% rename from Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleCollision.cs rename to Assets/Scripts/Minigames/DivingForPictures/Player/ObstacleCollision.cs index c1aca90b..fb333584 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleCollision.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Player/ObstacleCollision.cs @@ -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(); if (obstacleComponent != null) @@ -43,7 +51,7 @@ namespace Minigames.DivingForPictures /// 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 diff --git a/Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleCollision.cs.meta b/Assets/Scripts/Minigames/DivingForPictures/Player/ObstacleCollision.cs.meta similarity index 100% rename from Assets/Scripts/Minigames/DivingForPictures/Obstacles/ObstacleCollision.cs.meta rename to Assets/Scripts/Minigames/DivingForPictures/Player/ObstacleCollision.cs.meta diff --git a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerCollisionBehavior.cs b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerCollisionBehavior.cs index 858dc5d4..f9845ca5 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerCollisionBehavior.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerCollisionBehavior.cs @@ -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(); } + + /// + /// Blocks player input during immunity + /// + protected virtual void BlockPlayerInput() + { + if (playerController != null && playerController.enabled) + { + playerController.enabled = false; + wasInputBlocked = true; + Debug.Log($"[{GetType().Name}] Player input blocked during immunity"); + } + } + + /// + /// Restores player input after immunity + /// + 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"); + } + } + + /// + /// Updates the player controller's target position to the current position to prevent snapping + /// + protected virtual void UpdateControllerTarget() + { + // This would normally be implemented in derived classes if needed + } } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs index b61a8f82..9c3fa3cf 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Player/PlayerController.cs @@ -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); } /// @@ -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; diff --git a/Assets/Scripts/Minigames/DivingForPictures/Player/TileBumpCollision.cs b/Assets/Scripts/Minigames/DivingForPictures/Player/TileBumpCollision.cs index d177e4be..3cb5d32d 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Player/TileBumpCollision.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Player/TileBumpCollision.cs @@ -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"); } /// - /// Applies an impulse force toward center + /// Starts an impulse bump toward the center with force-based distance /// 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})"); } /// - /// Smoothly moves the player to center + /// Starts smooth movement to the center /// 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)"); + } + + /// + /// Common bump initialization using coroutines + /// + 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)); } /// - /// Coroutine to handle impulse bump movement + /// Coroutine that handles the bump movement over time /// - 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; - } - - /// - /// Coroutine to handle smooth movement to center - /// - 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"); } } } diff --git a/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs b/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs index 1d5f9ee5..50f93f69 100644 --- a/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs +++ b/Assets/Scripts/Minigames/DivingForPictures/Tiles/TrenchTileSpawner.cs @@ -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 + + /// + /// Set the layer of a GameObject and all its children recursively + /// + /// The GameObject to set the layer for + /// The layer index to set + 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); + } + } + } } } diff --git a/Assets/Scripts/Utilities.meta b/Assets/Scripts/Utilities.meta new file mode 100644 index 00000000..55c0c5ae --- /dev/null +++ b/Assets/Scripts/Utilities.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d54ca063d685467f9cb2c05507ac833f +timeCreated: 1758717247 \ No newline at end of file diff --git a/Assets/Scripts/Utilities/UnityExtensions.cs b/Assets/Scripts/Utilities/UnityExtensions.cs new file mode 100644 index 00000000..5d75c001 --- /dev/null +++ b/Assets/Scripts/Utilities/UnityExtensions.cs @@ -0,0 +1,55 @@ +using UnityEngine; + +namespace AppleHills.Utilities +{ + /// + /// Collection of useful extension methods for Unity built-in classes + /// + public static class UnityExtensions + { + /// + /// Extension method to check if a layer is in a layermask. + /// Accounts for Unity's 0-indexed layer system when comparing with editor layer values. + /// + /// The layer mask to check + /// The layer value to check for + /// True if the layer is in the mask, false otherwise + public static bool Contains(this LayerMask mask, int layer) + { + // Adjust for the -1 offset as specifically requested + int adjustedLayer = layer - 1; + return mask.value == (mask.value | (1 << adjustedLayer)); + } + + /// + /// Extension method to check if a GameObject's layer is in a layermask. + /// Automatically gets the layer from the GameObject and handles the offset. + /// + /// The layer mask to check + /// The GameObject whose layer to check + /// True if the GameObject's layer is in the mask, false otherwise + public static bool Contains(this LayerMask mask, GameObject gameObject) + { + if (gameObject == null) return false; + + int layer = gameObject.layer; + // Adjust for the -1 offset as specifically requested + int adjustedLayer = layer - 1; + return mask.value == (mask.value | (1 << adjustedLayer)); + } + + /// + /// Bitwise check if a layer is in a layermask. + /// This is an alternative implementation that uses bitwise AND operation. + /// + /// The layer mask to check + /// The layer value to check for + /// True if the layer is in the mask, false otherwise + public static bool ContainsBitwise(this LayerMask mask, int layer) + { + // Adjust for the -1 offset as specifically requested + int adjustedLayer = layer - 1; + return (mask.value & (1 << adjustedLayer)) != 0; + } + } +} diff --git a/Assets/Scripts/Utilities/UnityExtensions.cs.meta b/Assets/Scripts/Utilities/UnityExtensions.cs.meta new file mode 100644 index 00000000..a0a114b7 --- /dev/null +++ b/Assets/Scripts/Utilities/UnityExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3e92a12c248d4b9ab06fcc0ba9c63ef3 +timeCreated: 1758717247 \ No newline at end of file diff --git a/Assets/Settings/Developer/DivingDeveloperSettings.asset b/Assets/Settings/Developer/DivingDeveloperSettings.asset index 7ec0415b..528ea282 100644 --- a/Assets/Settings/Developer/DivingDeveloperSettings.asset +++ b/Assets/Settings/Developer/DivingDeveloperSettings.asset @@ -26,13 +26,11 @@ MonoBehaviour: bubbleWobbleMinScale: 0.2 bubbleWobbleMaxScale: 1.2 bubbleSurfacingSpeedFactor: 0.5 - obstacleLayer: 9 - obstacleTileLayerMask: - serializedVersion: 2 - m_Bits: 0 + obstacleLayer: 11 obstacleUseObjectPooling: 1 obstacleMaxPerPrefabPoolSize: 3 obstacleTotalMaxPoolSize: 15 + trenchTileLayer: 13 trenchTileUseObjectPooling: 1 trenchTileMaxPerPrefabPoolSize: 2 trenchTileTotalMaxPoolSize: 10 @@ -44,12 +42,12 @@ MonoBehaviour: playerSpeedToAmplitude: 2 playerMaxRotationLimit: 45 playerVerticalFrequency: 0.5 - playerVerticalAmplitude: 0.5 + playerVerticalAmplitude: 0.2 playerVelocitySmoothing: 10 playerRotationSmoothing: 10 playerObstacleLayerMask: serializedVersion: 2 - m_Bits: 4294967295 + m_Bits: 5120 blockInputDuringImmunity: 1 bumpMode: 0 bumpCurve: diff --git a/Assets/Settings/MinigameSettings.asset b/Assets/Settings/MinigameSettings.asset index d2ac2a18..e602f5de 100644 --- a/Assets/Settings/MinigameSettings.asset +++ b/Assets/Settings/MinigameSettings.asset @@ -12,8 +12,37 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0ce4dba7a1c54e73b1b3d7131a1c0570, type: 3} m_Name: MinigameSettings m_EditorClassIdentifier: - endlessDescenderLerpSpeed: 2.03 - endlessDescenderMaxOffset: 10 - endlessDescenderClampXMin: -3.5 - endlessDescenderClampXMax: 3.5 - endlessDescenderSpeedExponent: 0.97 + lerpSpeed: 2 + maxOffset: 10 + clampXMin: -3.5 + clampXMax: 3.5 + speedExponent: 0.97 + tapMaxDistance: 0.5 + tapDecelerationRate: 5 + baseSpawnProbability: 0.2 + maxSpawnProbability: 0.5 + probabilityIncreaseRate: 0.01 + guaranteedSpawnTime: 30 + spawnCooldown: 5 + basePoints: 100 + depthMultiplier: 10 + speedTransitionDuration: 2 + surfacingSpeedFactor: 3 + surfacingSpawnDelay: 5 + initialTileCount: 3 + tileSpawnBuffer: 1 + moveSpeed: 2 + speedUpFactor: 0 + speedUpInterval: 10 + maxMoveSpeed: 12 + velocityCalculationInterval: 0.5 + obstacleSpawnInterval: 2 + obstacleSpawnIntervalVariation: 0.5 + obstacleMaxSpawnAttempts: 10 + obstacleSpawnCollisionRadius: 1 + obstacleMinMoveSpeed: 1 + obstacleMaxMoveSpeed: 4 + damageImmunityDuration: 1 + bumpForce: 5 + smoothMoveSpeed: 8 + blockInputDuringBump: 1