using UnityEngine; using System.Collections; namespace Minigames.DivingForPictures { /// /// Collision behavior that bumps the player toward the center of the trench. /// Uses trigger-based collision detection with coroutine-based bump timing. /// public class TileBumpCollision : PlayerCollisionBehavior { [Header("Bump Settings")] [Tooltip("Type of bump response: Impulse pushes with force, SmoothToCenter moves directly to center")] [SerializeField] private BumpMode bumpMode = BumpMode.Impulse; [Tooltip("Force strength for impulse bumps - higher values push further toward center")] [SerializeField] private float bumpForce = 5.0f; [Tooltip("Speed for smooth movement to center (units per second)")] [SerializeField] private float smoothMoveSpeed = 8.0f; [Tooltip("Animation curve controlling bump movement over time")] [SerializeField] private AnimationCurve bumpCurve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 2f), new Keyframe(1f, 1f, 0f, 0f)); [Tooltip("Whether to block player input during bump movement")] [SerializeField] private bool blockInputDuringBump = true; public enum BumpMode { Impulse, // Force-based push toward center (distance depends on force) SmoothToCenter // Smooth movement to center with configurable speed } private bool _isBumping; private Coroutine _bumpCoroutine; private bool _bumpInputBlocked; // Tracks bump-specific input blocking protected override void HandleCollisionResponse(Collider2D obstacle) { switch (bumpMode) { case BumpMode.Impulse: StartImpulseBump(); break; case BumpMode.SmoothToCenter: StartSmoothMoveToCenter(); break; } Debug.Log($"[TileBumpCollision] Collision handled with {bumpMode} mode"); } /// /// Starts an impulse bump toward the center with force-based distance /// private void StartImpulseBump() { if (playerCharacter == null) return; float currentX = playerCharacter.transform.position.x; // 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 = 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)) { targetX = 0f; } float bumpDuration = 0.5f; // Fixed duration for impulse StartBump(currentX, targetX, bumpDuration); Debug.Log($"[TileBumpCollision] Starting impulse bump from X={currentX} to X={targetX} (force={bumpForce})"); } /// /// Starts smooth movement to the center /// private void StartSmoothMoveToCenter() { 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 / smoothMoveSpeed; // Duration based on distance and speed StartBump(currentX, targetX, bumpDuration); Debug.Log($"[TileBumpCollision] Starting smooth move to center from X={currentX} (speed={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 player input if enabled (use bump-specific blocking) if (blockInputDuringBump && playerController != null && playerController.enabled) { playerController.enabled = false; _bumpInputBlocked = true; Debug.Log("[TileBumpCollision] Player input blocked during bump"); } // Start bump coroutine _bumpCoroutine = StartCoroutine(BumpCoroutine(startX, targetX, duration)); } /// /// Coroutine that handles the bump movement over time /// private IEnumerator BumpCoroutine(float startX, float targetX, float duration) { float elapsedTime = 0f; while (elapsedTime < duration) { elapsedTime += Time.deltaTime; // Calculate progress and apply curve float progress = elapsedTime / duration; float curveValue = bumpCurve.Evaluate(progress); // Interpolate position float currentX = Mathf.Lerp(startX, targetX, curveValue); // Apply the position to the player character if (playerCharacter != null) { Vector3 currentPos = playerCharacter.transform.position; playerCharacter.transform.position = new Vector3(currentX, currentPos.y, currentPos.z); } yield return null; } // Ensure we end exactly at target if (playerCharacter != null) { Vector3 currentPos = playerCharacter.transform.position; playerCharacter.transform.position = new Vector3(targetX, currentPos.y, currentPos.z); } // Bump finished _isBumping = false; _bumpCoroutine = null; if (_bumpInputBlocked) { RestoreBumpInput(); } Debug.Log("[TileBumpCollision] Bump movement completed"); } /// /// Restores player input after bump movement /// private void RestoreBumpInput() { if (_bumpInputBlocked && playerController != null) { playerController.enabled = true; _bumpInputBlocked = false; // Update the controller's target position to current position to prevent snapping UpdateControllerTarget(); Debug.Log("[TileBumpCollision] Player input restored after bump"); } } /// /// Override to handle bump-specific input blocking during immunity /// protected override void OnImmunityStart() { Debug.Log($"[TileBumpCollision] Damage immunity started for {damageImmunityDuration} seconds"); // Block input if specified (in addition to any bump input blocking) if (blockInputDuringImmunity && !_bumpInputBlocked) { BlockPlayerInput(); } } /// /// Override to handle immunity end and bump cleanup /// protected override void OnImmunityEnd() { base.OnImmunityEnd(); // Stop any ongoing bump if immunity ends if (_isBumping && _bumpCoroutine != null) { StopCoroutine(_bumpCoroutine); _bumpCoroutine = null; _isBumping = false; if (_bumpInputBlocked) { RestoreBumpInput(); } Debug.Log("[TileBumpCollision] Bump interrupted by immunity end"); } } /// /// Called when component is destroyed - cleanup coroutines /// private void OnDestroy() { if (_bumpCoroutine != null) { StopCoroutine(_bumpCoroutine); _bumpCoroutine = null; } } /// /// Public method to change bump mode at runtime /// public void SetBumpMode(BumpMode mode) { bumpMode = mode; } /// /// Public method to change bump force at runtime /// public void SetBumpForce(float force) { bumpForce = force; } /// /// Public method to change smooth move speed at runtime /// public void SetSmoothMoveSpeed(float speed) { smoothMoveSpeed = speed; } /// /// Check if player is currently being bumped /// public bool IsBumping => _isBumping; /// /// Check if input is currently blocked by bump /// public bool IsBumpInputBlocked => _bumpInputBlocked; /// /// Public method to manually stop bump movement /// public void StopBump() { if (_isBumping && _bumpCoroutine != null) { StopCoroutine(_bumpCoroutine); _bumpCoroutine = null; _isBumping = false; if (_bumpInputBlocked) { RestoreBumpInput(); } Debug.Log("[TileBumpCollision] Bump manually stopped"); } } } }