- Simulated "fake" physics and collisions - Object pooling for tiles, obstacles and monster spawns - Base monster scoring with proximity triggers and depth multiplier Co-authored-by: AlexanderT <alexander@foolhardyhorizons.com> Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Reviewed-on: #5
295 lines
10 KiB
C#
295 lines
10 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
|
|
namespace Minigames.DivingForPictures
|
|
{
|
|
/// <summary>
|
|
/// Collision behavior that bumps the player toward the center of the trench.
|
|
/// Uses trigger-based collision detection with coroutine-based bump timing.
|
|
/// </summary>
|
|
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");
|
|
}
|
|
|
|
/// <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;
|
|
}
|
|
|
|
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})");
|
|
}
|
|
|
|
/// <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);
|
|
|
|
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)");
|
|
}
|
|
|
|
/// <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 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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Coroutine that handles the bump movement over time
|
|
/// </summary>
|
|
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");
|
|
}
|
|
|
|
/// <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("[TileBumpCollision] Player input restored after bump");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override to handle bump-specific input blocking during immunity
|
|
/// </summary>
|
|
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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override to handle immunity end and bump cleanup
|
|
/// </summary>
|
|
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");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when component is destroyed - cleanup coroutines
|
|
/// </summary>
|
|
private void OnDestroy()
|
|
{
|
|
if (_bumpCoroutine != null)
|
|
{
|
|
StopCoroutine(_bumpCoroutine);
|
|
_bumpCoroutine = null;
|
|
}
|
|
}
|
|
|
|
/// <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;
|
|
|
|
/// <summary>
|
|
/// Public method to manually stop bump movement
|
|
/// </summary>
|
|
public void StopBump()
|
|
{
|
|
if (_isBumping && _bumpCoroutine != null)
|
|
{
|
|
StopCoroutine(_bumpCoroutine);
|
|
_bumpCoroutine = null;
|
|
_isBumping = false;
|
|
|
|
if (_bumpInputBlocked)
|
|
{
|
|
RestoreBumpInput();
|
|
}
|
|
|
|
Debug.Log("[TileBumpCollision] Bump manually stopped");
|
|
}
|
|
}
|
|
}
|
|
}
|