Files
AppleHillsProduction/Assets/Scripts/Minigames/DivingForPictures/PlayerBumpCollisionBehavior.cs

235 lines
8.4 KiB
C#
Raw Normal View History

2025-09-17 16:10:18 +02:00
using UnityEngine;
namespace Minigames.DivingForPictures
{
/// <summary>
/// Collision behavior that bumps the player toward the center of the trench.
/// Provides two modes: impulse (force-based push) or smooth movement to center.
/// </summary>
public class PlayerBumpCollisionBehavior : 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 float _bumpTimer;
private float _bumpStartX;
private float _bumpTargetX;
private float _bumpDuration;
private bool _bumpInputBlocked; // Tracks bump-specific input blocking
protected override void Update()
{
base.Update();
// Handle bump movement
if (_isBumping)
{
_bumpTimer -= Time.deltaTime;
if (_bumpTimer <= 0f)
{
// Bump finished
_isBumping = false;
if (_bumpInputBlocked)
{
RestoreBumpInput();
}
// Ensure we end exactly at target
if (playerCharacter != null)
{
Vector3 currentPos = playerCharacter.transform.position;
playerCharacter.transform.position = new Vector3(_bumpTargetX, currentPos.y, currentPos.z);
}
}
else
{
// Apply bump movement
float progress = 1f - (_bumpTimer / _bumpDuration);
float curveValue = bumpCurve.Evaluate(progress);
float currentX = Mathf.Lerp(_bumpStartX, _bumpTargetX, 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);
}
}
}
}
protected override void HandleCollisionResponse(Collider2D obstacle)
{
switch (bumpMode)
{
case BumpMode.Impulse:
StartImpulseBump();
break;
case BumpMode.SmoothToCenter:
StartSmoothMoveToCenter();
break;
}
Debug.Log($"[PlayerBumpCollisionBehavior] Collision handled with {bumpMode} mode");
}
/// <summary>
/// Starts an impulse bump toward the center with force-based distance
/// </summary>
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;
}
// Set bump parameters
_bumpStartX = currentX;
_bumpTargetX = targetX;
_bumpDuration = 0.5f; // Fixed duration for impulse
StartBump();
Debug.Log($"[PlayerBumpCollisionBehavior] Starting impulse bump from X={_bumpStartX} to X={_bumpTargetX} (force={bumpForce})");
}
/// <summary>
/// Starts smooth movement to the center
/// </summary>
private void StartSmoothMoveToCenter()
{
if (playerCharacter == null) return;
float currentX = playerCharacter.transform.position.x;
float distanceToCenter = Mathf.Abs(currentX);
// Set bump parameters
_bumpStartX = currentX;
_bumpTargetX = 0f; // Always move to center
_bumpDuration = distanceToCenter / smoothMoveSpeed; // Duration based on distance and speed
StartBump();
Debug.Log($"[PlayerBumpCollisionBehavior] Starting smooth move to center from X={_bumpStartX} (speed={smoothMoveSpeed}, duration={_bumpDuration:F2}s)");
}
/// <summary>
/// Common bump initialization
/// </summary>
private void StartBump()
{
_isBumping = true;
_bumpTimer = _bumpDuration;
// Block player input if enabled (use bump-specific blocking)
if (blockInputDuringBump && playerController != null && playerController.enabled)
{
playerController.enabled = false;
_bumpInputBlocked = true;
Debug.Log("[PlayerBumpCollisionBehavior] Player input blocked during bump");
}
}
/// <summary>
/// Restores player input after bump movement
/// </summary>
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("[PlayerBumpCollisionBehavior] Player input restored after bump");
}
}
protected override void OnImmunityEnd()
{
base.OnImmunityEnd();
// Stop any ongoing bump if immunity ends
if (_isBumping)
{
_isBumping = false;
if (_bumpInputBlocked)
{
RestoreBumpInput();
}
}
}
/// <summary>
/// Public method to change bump mode at runtime
/// </summary>
public void SetBumpMode(BumpMode mode)
{
bumpMode = mode;
}
/// <summary>
/// Public method to change bump force at runtime
/// </summary>
public void SetBumpForce(float force)
{
bumpForce = force;
}
/// <summary>
/// Public method to change smooth move speed at runtime
/// </summary>
public void SetSmoothMoveSpeed(float speed)
{
smoothMoveSpeed = speed;
}
/// <summary>
/// Check if player is currently being bumped
/// </summary>
public bool IsBumping => _isBumping;
/// <summary>
/// Check if input is currently blocked by bump
/// </summary>
public bool IsBumpInputBlocked => _bumpInputBlocked;
}
}