Improvements and touchups to a more event-driven flow and fake physics

This commit is contained in:
Michal Pikulski
2025-09-18 14:14:01 +02:00
parent 44c1e48b82
commit 3f52de9e1e
5 changed files with 56 additions and 110 deletions

View File

@@ -4,8 +4,9 @@ using Pooling;
namespace Minigames.DivingForPictures namespace Minigames.DivingForPictures
{ {
/// <summary> /// <summary>
/// Complete floating obstacle component that handles data, movement, and pooling. /// Complete floating obstacle component that handles movement and pooling.
/// Obstacles move upward toward the surface. Collision detection is now handled by the player. /// Obstacles move upward toward the surface. Collision detection is handled by the player.
/// Once an obstacle hits the player, its collider is disabled to prevent further collisions.
/// </summary> /// </summary>
public class FloatingObstacle : MonoBehaviour, IPoolable public class FloatingObstacle : MonoBehaviour, IPoolable
{ {
@@ -13,9 +14,6 @@ namespace Minigames.DivingForPictures
[Tooltip("Index of the prefab this obstacle was created from")] [Tooltip("Index of the prefab this obstacle was created from")]
[SerializeField] private int prefabIndex; [SerializeField] private int prefabIndex;
[Tooltip("Damage this obstacle deals to the player")]
[SerializeField] private float damage = 1f;
[Tooltip("Movement speed of this obstacle")] [Tooltip("Movement speed of this obstacle")]
[SerializeField] private float moveSpeed = 2f; [SerializeField] private float moveSpeed = 2f;
@@ -34,23 +32,14 @@ namespace Minigames.DivingForPictures
set => prefabIndex = value; set => prefabIndex = value;
} }
public float Damage
{
get => damage;
set => damage = value;
}
public float MoveSpeed public float MoveSpeed
{ {
get => moveSpeed; get => moveSpeed;
set => moveSpeed = value; set => moveSpeed = value;
} }
public bool HasDealtDamage => _hasDealtDamage;
// Private fields // Private fields
private Collider2D _collider; private Collider2D _collider;
private bool _hasDealtDamage;
private Camera _mainCamera; private Camera _mainCamera;
private float _screenTop; private float _screenTop;
@@ -90,14 +79,15 @@ namespace Minigames.DivingForPictures
} }
/// <summary> /// <summary>
/// Marks this obstacle as having dealt damage (called by PlayerDamageCollisionBehavior) /// Disables the collider after hitting the player to prevent further collisions
/// This is more performant than tracking hit state
/// </summary> /// </summary>
public void MarkDamageDealt() public void MarkDamageDealt()
{ {
if (!_hasDealtDamage) if (_collider != null && _collider.enabled)
{ {
_hasDealtDamage = true; _collider.enabled = false;
Debug.Log($"[FloatingObstacle] Obstacle {gameObject.name} dealt {damage} damage to player"); Debug.Log($"[FloatingObstacle] Obstacle {gameObject.name} hit player - collider disabled");
} }
} }
@@ -152,9 +142,14 @@ namespace Minigames.DivingForPictures
/// </summary> /// </summary>
public void OnSpawn() public void OnSpawn()
{ {
_hasDealtDamage = false;
_screenTop = 0f; // Reset cached screen bounds _screenTop = 0f; // Reset cached screen bounds
// Re-enable the collider for reuse
if (_collider != null)
{
_collider.enabled = true;
}
// Ensure the obstacle is active and visible // Ensure the obstacle is active and visible
gameObject.SetActive(true); gameObject.SetActive(true);
@@ -166,7 +161,11 @@ namespace Minigames.DivingForPictures
/// </summary> /// </summary>
public void OnDespawn() public void OnDespawn()
{ {
_hasDealtDamage = false; // Re-enable collider for next use (in case it was disabled)
if (_collider != null)
{
_collider.enabled = true;
}
Debug.Log($"[FloatingObstacle] Obstacle {gameObject.name} despawned"); Debug.Log($"[FloatingObstacle] Obstacle {gameObject.name} despawned");
} }

View File

@@ -8,49 +8,16 @@ namespace Minigames.DivingForPictures
/// </summary> /// </summary>
public class ObstacleCollision : PlayerCollisionBehavior public class ObstacleCollision : PlayerCollisionBehavior
{ {
[Header("Damage Settings")]
[Tooltip("Base damage amount dealt by obstacles")]
[SerializeField] private float baseDamage = 1f;
[Tooltip("Whether to use the obstacle's individual damage value or the base damage")]
[SerializeField] private bool useObstacleDamageValue = true;
protected override void HandleCollisionResponse(Collider2D obstacle) protected override void HandleCollisionResponse(Collider2D obstacle)
{ {
float damageAmount = baseDamage; // Mark the obstacle as having dealt damage to prevent multiple hits
FloatingObstacle obstacleComponent = obstacle.GetComponent<FloatingObstacle>();
// Try to get damage from the obstacle component if enabled if (obstacleComponent != null)
if (useObstacleDamageValue)
{ {
FloatingObstacle obstacleComponent = obstacle.GetComponent<FloatingObstacle>(); obstacleComponent.MarkDamageDealt();
if (obstacleComponent != null)
{
damageAmount = obstacleComponent.Damage;
// Mark the obstacle as having dealt damage to prevent multiple hits
obstacleComponent.MarkDamageDealt();
}
} }
// Apply damage (this could be extended to integrate with a health system) Debug.Log($"[ObstacleCollision] Player hit by obstacle {obstacle.gameObject.name}");
ApplyDamage(damageAmount);
Debug.Log($"[ObstacleCollision] Player took {damageAmount} damage from obstacle {obstacle.gameObject.name}");
}
/// <summary>
/// Applies damage to the player
/// Override this method to integrate with your health/damage system
/// </summary>
/// <param name="damage">Amount of damage to apply</param>
protected virtual void ApplyDamage(float damage)
{
// For now, just log the damage
// In a full implementation, this would reduce player health, trigger UI updates, etc.
Debug.Log($"[ObstacleCollision] Applied {damage} damage to player");
// TODO: Integrate with health system when available
// Example: playerHealth.TakeDamage(damage);
} }
/// <summary> /// <summary>
@@ -73,21 +40,5 @@ namespace Minigames.DivingForPictures
Debug.Log($"[ObstacleCollision] Damage immunity ended"); Debug.Log($"[ObstacleCollision] Damage immunity ended");
// No special handling needed - shared immunity system handles collider re-enabling // No special handling needed - shared immunity system handles collider re-enabling
} }
/// <summary>
/// Public method to set base damage at runtime
/// </summary>
public void SetBaseDamage(float damage)
{
baseDamage = damage;
}
/// <summary>
/// Public method to toggle between base damage and obstacle-specific damage
/// </summary>
public void SetUseObstacleDamage(bool useObstacleDamage)
{
useObstacleDamageValue = useObstacleDamage;
}
} }
} }

View File

@@ -42,12 +42,6 @@ namespace Minigames.DivingForPictures
[Tooltip("Maximum movement speed for spawned obstacles")] [Tooltip("Maximum movement speed for spawned obstacles")]
[SerializeField] private float maxMoveSpeed = 4f; [SerializeField] private float maxMoveSpeed = 4f;
[Tooltip("Minimum damage dealt by obstacles")]
[SerializeField] private float minDamage = 0.5f;
[Tooltip("Maximum damage dealt by obstacles")]
[SerializeField] private float maxDamage = 2f;
[Header("Object Pooling")] [Header("Object Pooling")]
[Tooltip("Whether to use object pooling for obstacles")] [Tooltip("Whether to use object pooling for obstacles")]
@@ -356,7 +350,6 @@ namespace Minigames.DivingForPictures
// Randomize properties // Randomize properties
obstacleComponent.MoveSpeed = Random.Range(minMoveSpeed, maxMoveSpeed); obstacleComponent.MoveSpeed = Random.Range(minMoveSpeed, maxMoveSpeed);
obstacleComponent.Damage = Random.Range(minDamage, maxDamage);
// Set spawner reference (since FloatingObstacle has this built-in now) // Set spawner reference (since FloatingObstacle has this built-in now)
obstacleComponent.SetSpawner(this); obstacleComponent.SetSpawner(this);
@@ -423,15 +416,6 @@ namespace Minigames.DivingForPictures
maxMoveSpeed = max; maxMoveSpeed = max;
} }
/// <summary>
/// Public method to set damage range at runtime
/// </summary>
public void SetDamageRange(float min, float max)
{
minDamage = min;
maxDamage = max;
}
/// <summary> /// <summary>
/// Gets the count of currently active obstacles /// Gets the count of currently active obstacles
/// </summary> /// </summary>

View File

@@ -60,16 +60,16 @@ namespace Minigames.DivingForPictures
private void OnEnable() private void OnEnable()
{ {
// Subscribe to damage events // Subscribe to immunity events (renamed from damage events)
PlayerCollisionBehavior.OnDamageStart += StartBlinking; PlayerCollisionBehavior.OnImmunityStarted += StartBlinking;
PlayerCollisionBehavior.OnDamageEnd += StopBlinking; PlayerCollisionBehavior.OnImmunityEnded += StopBlinking;
} }
private void OnDisable() private void OnDisable()
{ {
// Unsubscribe from damage events // Unsubscribe from immunity events
PlayerCollisionBehavior.OnDamageStart -= StartBlinking; PlayerCollisionBehavior.OnImmunityStarted -= StartBlinking;
PlayerCollisionBehavior.OnDamageEnd -= StopBlinking; PlayerCollisionBehavior.OnImmunityEnded -= StopBlinking;
// Stop any ongoing blink effect // Stop any ongoing blink effect
if (_blinkCoroutine != null) if (_blinkCoroutine != null)

View File

@@ -34,28 +34,37 @@ namespace Minigames.DivingForPictures
private static MonoBehaviour _coroutineRunner; private static MonoBehaviour _coroutineRunner;
private static Collider2D _sharedPlayerCollider; private static Collider2D _sharedPlayerCollider;
// Events for damage state changes // Events for immunity and damage state changes
public static event Action OnDamageStart; public static event Action OnImmunityStarted;
public static event Action OnDamageEnd; public static event Action OnImmunityEnded;
public static event Action OnDamageTaken;
// Instance tracking for shared state management // Instance tracking for shared state management
private static readonly System.Collections.Generic.HashSet<PlayerCollisionBehavior> _allInstances = private static readonly System.Collections.Generic.HashSet<PlayerCollisionBehavior> _allInstances =
new System.Collections.Generic.HashSet<PlayerCollisionBehavior>(); new System.Collections.Generic.HashSet<PlayerCollisionBehavior>();
/// <summary> /// <summary>
/// Public static method to trigger damage start event from external classes /// Public static method to trigger immunity start event from external classes
/// </summary> /// </summary>
public static void TriggerDamageStart() public static void TriggerImmunityStarted()
{ {
OnDamageStart?.Invoke(); OnImmunityStarted?.Invoke();
} }
/// <summary> /// <summary>
/// Public static method to trigger damage end event from external classes /// Public static method to trigger immunity end event from external classes
/// </summary> /// </summary>
public static void TriggerDamageEnd() public static void TriggerImmunityEnded()
{ {
OnDamageEnd?.Invoke(); OnImmunityEnded?.Invoke();
}
/// <summary>
/// Public static method to trigger damage taken event from external classes
/// </summary>
public static void TriggerDamageTaken()
{
OnDamageTaken?.Invoke();
} }
protected bool wasInputBlocked; protected bool wasInputBlocked;
@@ -148,6 +157,9 @@ namespace Minigames.DivingForPictures
{ {
if (_isGloballyImmune) return; if (_isGloballyImmune) return;
// Trigger damage taken event first
OnDamageTaken?.Invoke();
// Start shared immunity period // Start shared immunity period
StartGlobalImmunity(); StartGlobalImmunity();
@@ -191,8 +203,8 @@ namespace Minigames.DivingForPictures
} }
} }
// Broadcast damage start event // Broadcast immunity start event
OnDamageStart?.Invoke(); OnImmunityStarted?.Invoke();
} }
/// <summary> /// <summary>
@@ -225,8 +237,8 @@ namespace Minigames.DivingForPictures
} }
} }
// Broadcast damage end event // Broadcast immunity end event
OnDamageEnd?.Invoke(); OnImmunityEnded?.Invoke();
} }
/// <summary> /// <summary>
@@ -352,7 +364,7 @@ namespace Minigames.DivingForPictures
} }
} }
OnDamageEnd?.Invoke(); OnImmunityEnded?.Invoke();
} }
} }
} }