Working state for minigameobstacles
This commit is contained in:
233
Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs
Normal file
233
Assets/Scripts/Minigames/DivingForPictures/FloatingObstacle.cs
Normal file
@@ -0,0 +1,233 @@
|
||||
using UnityEngine;
|
||||
using Pooling;
|
||||
|
||||
namespace Minigames.DivingForPictures
|
||||
{
|
||||
/// <summary>
|
||||
/// Complete floating obstacle component that handles data, movement, collision detection, and pooling.
|
||||
/// Obstacles move upward toward the surface and detect collisions with the player.
|
||||
/// </summary>
|
||||
public class FloatingObstacle : MonoBehaviour, IPoolable
|
||||
{
|
||||
[Header("Obstacle Properties")]
|
||||
[Tooltip("Index of the prefab this obstacle was created from")]
|
||||
[SerializeField] private int prefabIndex;
|
||||
|
||||
[Tooltip("Damage this obstacle deals to the player")]
|
||||
[SerializeField] private float damage = 1f;
|
||||
|
||||
[Tooltip("Movement speed of this obstacle")]
|
||||
[SerializeField] private float moveSpeed = 2f;
|
||||
|
||||
[Header("Movement")]
|
||||
[Tooltip("Whether this obstacle moves (can be disabled for static obstacles)")]
|
||||
[SerializeField] private bool enableMovement = true;
|
||||
|
||||
[Header("Collision Detection")]
|
||||
[Tooltip("Layer mask for player detection - should match Player layer")]
|
||||
[SerializeField] private LayerMask playerLayerMask = 1 << 7; // Player layer
|
||||
|
||||
[Tooltip("How often to check for collisions (in seconds)")]
|
||||
[SerializeField] private float collisionCheckInterval = 0.1f;
|
||||
|
||||
[Header("References")]
|
||||
[Tooltip("Reference to the spawner that created this obstacle")]
|
||||
[SerializeField] private ObstacleSpawner spawner;
|
||||
|
||||
// Public properties
|
||||
public int PrefabIndex
|
||||
{
|
||||
get => prefabIndex;
|
||||
set => prefabIndex = value;
|
||||
}
|
||||
|
||||
public float Damage
|
||||
{
|
||||
get => damage;
|
||||
set => damage = value;
|
||||
}
|
||||
|
||||
public float MoveSpeed
|
||||
{
|
||||
get => moveSpeed;
|
||||
set => moveSpeed = value;
|
||||
}
|
||||
|
||||
public bool HasDealtDamage => _hasDealtDamage;
|
||||
|
||||
// Private fields
|
||||
private Collider2D _collider;
|
||||
private float _collisionCheckTimer;
|
||||
private bool _hasDealtDamage;
|
||||
private Camera _mainCamera;
|
||||
private float _screenTop;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_collider = GetComponent<Collider2D>();
|
||||
|
||||
if (_collider == null)
|
||||
{
|
||||
_collider = GetComponentInChildren<Collider2D>();
|
||||
}
|
||||
|
||||
if (_collider == null)
|
||||
{
|
||||
Debug.LogError($"[FloatingObstacle] No Collider2D found on {gameObject.name}!");
|
||||
}
|
||||
|
||||
_mainCamera = Camera.main;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (enableMovement)
|
||||
{
|
||||
HandleMovement();
|
||||
}
|
||||
|
||||
HandleCollisionDetection();
|
||||
CheckIfOffScreen();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the obstacle upward based on its speed
|
||||
/// </summary>
|
||||
private void HandleMovement()
|
||||
{
|
||||
transform.position += Vector3.up * (moveSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks for collisions with the player at regular intervals
|
||||
/// </summary>
|
||||
private void HandleCollisionDetection()
|
||||
{
|
||||
if (_hasDealtDamage || _collider == null) return;
|
||||
|
||||
_collisionCheckTimer -= Time.deltaTime;
|
||||
if (_collisionCheckTimer <= 0f)
|
||||
{
|
||||
_collisionCheckTimer = collisionCheckInterval;
|
||||
CheckForPlayerCollision();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this obstacle is colliding with the player
|
||||
/// </summary>
|
||||
private void CheckForPlayerCollision()
|
||||
{
|
||||
Collider2D[] overlapping = new Collider2D[5];
|
||||
ContactFilter2D filter = new ContactFilter2D();
|
||||
filter.SetLayerMask(playerLayerMask);
|
||||
filter.useTriggers = true;
|
||||
|
||||
int count = _collider.Overlap(filter, overlapping);
|
||||
|
||||
if (count > 0 && !_hasDealtDamage)
|
||||
{
|
||||
// Found collision with player
|
||||
OnPlayerCollision(overlapping[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when this obstacle collides with the player
|
||||
/// </summary>
|
||||
/// <param name="playerCollider">The player's collider</param>
|
||||
private void OnPlayerCollision(Collider2D playerCollider)
|
||||
{
|
||||
_hasDealtDamage = true;
|
||||
|
||||
// Trigger damage through events (following the existing pattern)
|
||||
Debug.Log($"[FloatingObstacle] Obstacle dealt {damage} damage to player");
|
||||
|
||||
// Broadcast damage event using the static method
|
||||
PlayerCollisionBehavior.TriggerDamageStart();
|
||||
|
||||
// Continue moving upward - don't destroy or stop the obstacle
|
||||
Debug.Log($"[FloatingObstacle] Obstacle {gameObject.name} hit player and continues moving");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the obstacle has moved off-screen and should be despawned
|
||||
/// </summary>
|
||||
private void CheckIfOffScreen()
|
||||
{
|
||||
if (_mainCamera == null) return;
|
||||
|
||||
// Calculate screen top if not cached
|
||||
if (_screenTop == 0f)
|
||||
{
|
||||
Vector3 topWorldPoint = _mainCamera.ViewportToWorldPoint(new Vector3(0.5f, 1f, _mainCamera.nearClipPlane));
|
||||
_screenTop = topWorldPoint.y;
|
||||
}
|
||||
|
||||
// Check if obstacle is above screen
|
||||
if (transform.position.y > _screenTop + 2f) // Extra buffer for safety
|
||||
{
|
||||
ReturnToPool();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns this obstacle to the spawner's pool
|
||||
/// </summary>
|
||||
private void ReturnToPool()
|
||||
{
|
||||
if (spawner != null)
|
||||
{
|
||||
spawner.ReturnObstacleToPool(gameObject, prefabIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[FloatingObstacle] Cannot return {gameObject.name} to pool - missing spawner reference");
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the spawner reference for this obstacle
|
||||
/// </summary>
|
||||
/// <param name="obstacleSpawner">The spawner that created this obstacle</param>
|
||||
public void SetSpawner(ObstacleSpawner obstacleSpawner)
|
||||
{
|
||||
spawner = obstacleSpawner;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the obstacle is retrieved from the pool
|
||||
/// </summary>
|
||||
public void OnSpawn()
|
||||
{
|
||||
_hasDealtDamage = false;
|
||||
_collisionCheckTimer = 0f;
|
||||
_screenTop = 0f; // Reset cached screen bounds
|
||||
|
||||
// Ensure the obstacle is active and visible
|
||||
gameObject.SetActive(true);
|
||||
|
||||
Debug.Log($"[FloatingObstacle] Obstacle {gameObject.name} spawned");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the obstacle is returned to the pool
|
||||
/// </summary>
|
||||
public void OnDespawn()
|
||||
{
|
||||
_hasDealtDamage = false;
|
||||
_collisionCheckTimer = 0f;
|
||||
|
||||
Debug.Log($"[FloatingObstacle] Obstacle {gameObject.name} despawned");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Public method to manually trigger return to pool (for external systems)
|
||||
/// </summary>
|
||||
public void ForceReturnToPool()
|
||||
{
|
||||
ReturnToPool();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user