Coroutine updates WIP
This commit is contained in:
@@ -1,30 +1,38 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using System.Collections;
|
||||||
using Pooling;
|
using Pooling;
|
||||||
|
|
||||||
namespace Minigames.DivingForPictures
|
namespace Minigames.DivingForPictures
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single bubble, handling its movement, wobble effect, scaling, and sprite assignment.
|
/// Represents a single bubble, handling its movement, wobble effect, scaling, and sprite assignment.
|
||||||
|
/// Uses coroutines for better performance instead of Update() calls.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Bubble : MonoBehaviour, IPoolableWithReference<BubblePool>
|
public class Bubble : MonoBehaviour, IPoolableWithReference<BubblePool>
|
||||||
{
|
{
|
||||||
public float speed = 1f;
|
public float speed = 1f;
|
||||||
public float wobbleSpeed = 1f;
|
public float wobbleSpeed = 1f;
|
||||||
private SpriteRenderer spriteRenderer;
|
private SpriteRenderer spriteRenderer;
|
||||||
private SpriteRenderer bubbleSpriteRenderer; // Renamed from bottleSpriteRenderer
|
private SpriteRenderer bubbleSpriteRenderer;
|
||||||
private float timeOffset;
|
private float timeOffset;
|
||||||
private float minScale = 0.2f;
|
private float minScale = 0.2f;
|
||||||
private float maxScale = 1.2f;
|
private float maxScale = 1.2f;
|
||||||
private float baseScale = 1f; // Added to store the initial scale
|
private float baseScale = 1f;
|
||||||
|
|
||||||
private Camera mainCamera; // Cache camera reference
|
private Camera mainCamera;
|
||||||
private BubblePool parentPool; // Reference to the pool this bubble came from
|
private BubblePool parentPool;
|
||||||
|
|
||||||
|
// Coroutine references
|
||||||
|
private Coroutine _movementCoroutine;
|
||||||
|
private Coroutine _wobbleCoroutine;
|
||||||
|
private Coroutine _offScreenCheckCoroutine;
|
||||||
|
|
||||||
void Awake()
|
void Awake()
|
||||||
{
|
{
|
||||||
// Cache references and randomize time offset for wobble
|
// Cache references and randomize time offset for wobble
|
||||||
spriteRenderer = GetComponent<SpriteRenderer>();
|
spriteRenderer = GetComponent<SpriteRenderer>();
|
||||||
timeOffset = Random.value * 100f;
|
timeOffset = Random.value * 100f;
|
||||||
|
|
||||||
// Find the child named "BubbleSprite" and get its SpriteRenderer
|
// Find the child named "BubbleSprite" and get its SpriteRenderer
|
||||||
Transform bubbleSpriteTransform = transform.Find("BubbleSprite");
|
Transform bubbleSpriteTransform = transform.Find("BubbleSprite");
|
||||||
if (bubbleSpriteTransform != null)
|
if (bubbleSpriteTransform != null)
|
||||||
@@ -36,20 +44,101 @@ namespace Minigames.DivingForPictures
|
|||||||
mainCamera = Camera.main;
|
mainCamera = Camera.main;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
StartBubbleBehavior();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
StopBubbleBehavior();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts all bubble behavior coroutines
|
||||||
|
/// </summary>
|
||||||
|
private void StartBubbleBehavior()
|
||||||
|
{
|
||||||
|
_movementCoroutine = StartCoroutine(MovementCoroutine());
|
||||||
|
_wobbleCoroutine = StartCoroutine(WobbleCoroutine());
|
||||||
|
_offScreenCheckCoroutine = StartCoroutine(OffScreenCheckCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops all bubble behavior coroutines
|
||||||
|
/// </summary>
|
||||||
|
private void StopBubbleBehavior()
|
||||||
|
{
|
||||||
|
if (_movementCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(_movementCoroutine);
|
||||||
|
_movementCoroutine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_wobbleCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(_wobbleCoroutine);
|
||||||
|
_wobbleCoroutine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_offScreenCheckCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(_offScreenCheckCoroutine);
|
||||||
|
_offScreenCheckCoroutine = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coroutine that handles bubble upward movement
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerator MovementCoroutine()
|
||||||
|
{
|
||||||
|
while (enabled && gameObject.activeInHierarchy)
|
||||||
{
|
{
|
||||||
// Move bubble upward
|
// Move bubble upward
|
||||||
transform.position += Vector3.up * (speed * Time.deltaTime);
|
transform.position += Vector3.up * (speed * Time.deltaTime);
|
||||||
|
|
||||||
|
// Wait for next frame
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coroutine that handles the wobble scaling effect
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerator WobbleCoroutine()
|
||||||
|
{
|
||||||
|
while (enabled && gameObject.activeInHierarchy)
|
||||||
|
{
|
||||||
// Wobble effect (smooth oscillation between min and max scale)
|
// Wobble effect (smooth oscillation between min and max scale)
|
||||||
float t = (Mathf.Sin((Time.time + timeOffset) * wobbleSpeed) + 1f) * 0.5f; // t in [0,1]
|
float t = (Mathf.Sin((Time.time + timeOffset) * wobbleSpeed) + 1f) * 0.5f; // t in [0,1]
|
||||||
float wobbleFactor = Mathf.Lerp(minScale, maxScale, t);
|
float wobbleFactor = Mathf.Lerp(minScale, maxScale, t);
|
||||||
transform.localScale = Vector3.one * (baseScale * wobbleFactor);
|
transform.localScale = Vector3.one * (baseScale * wobbleFactor);
|
||||||
|
|
||||||
// Destroy when off screen - using cached camera reference
|
// Wait for next frame
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coroutine that checks if bubble has moved off-screen
|
||||||
|
/// Runs at a lower frequency for better performance
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerator OffScreenCheckCoroutine()
|
||||||
|
{
|
||||||
|
const float checkInterval = 0.1f; // Check every 100ms instead of every frame
|
||||||
|
|
||||||
|
while (enabled && gameObject.activeInHierarchy)
|
||||||
|
{
|
||||||
|
// Check if bubble is off screen
|
||||||
if (mainCamera != null && transform.position.y > mainCamera.orthographicSize + 2f)
|
if (mainCamera != null && transform.position.y > mainCamera.orthographicSize + 2f)
|
||||||
{
|
{
|
||||||
OnBubbleDestroy();
|
OnBubbleDestroy();
|
||||||
|
yield break; // Exit coroutine since bubble is being destroyed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the check interval
|
||||||
|
yield return new WaitForSeconds(checkInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +233,24 @@ namespace Minigames.DivingForPictures
|
|||||||
maxScale = max;
|
maxScale = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the movement speed at runtime
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newSpeed">New movement speed</param>
|
||||||
|
public void SetSpeed(float newSpeed)
|
||||||
|
{
|
||||||
|
speed = newSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the wobble speed at runtime
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newWobbleSpeed">New wobble speed</param>
|
||||||
|
public void SetWobbleSpeed(float newWobbleSpeed)
|
||||||
|
{
|
||||||
|
wobbleSpeed = newWobbleSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the bubble state for reuse from object pool
|
/// Resets the bubble state for reuse from object pool
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using System.Collections;
|
||||||
using Pooling;
|
using Pooling;
|
||||||
|
|
||||||
namespace Minigames.DivingForPictures
|
namespace Minigames.DivingForPictures
|
||||||
@@ -7,6 +8,7 @@ namespace Minigames.DivingForPictures
|
|||||||
/// Complete floating obstacle component that handles movement and pooling.
|
/// Complete floating obstacle component that handles movement and pooling.
|
||||||
/// Obstacles move upward toward the surface. Collision detection is 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.
|
/// Once an obstacle hits the player, its collider is disabled to prevent further collisions.
|
||||||
|
/// Uses coroutines for better performance instead of Update() calls.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FloatingObstacle : MonoBehaviour, IPoolable
|
public class FloatingObstacle : MonoBehaviour, IPoolable
|
||||||
{
|
{
|
||||||
@@ -42,6 +44,8 @@ namespace Minigames.DivingForPictures
|
|||||||
private Collider2D _collider;
|
private Collider2D _collider;
|
||||||
private Camera _mainCamera;
|
private Camera _mainCamera;
|
||||||
private float _screenTop;
|
private float _screenTop;
|
||||||
|
private Coroutine _movementCoroutine;
|
||||||
|
private Coroutine _offScreenCheckCoroutine;
|
||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
@@ -60,22 +64,77 @@ namespace Minigames.DivingForPictures
|
|||||||
_mainCamera = Camera.main;
|
_mainCamera = Camera.main;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
if (enableMovement)
|
StartObstacleBehavior();
|
||||||
{
|
|
||||||
HandleMovement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckIfOffScreen();
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
StopObstacleBehavior();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Moves the obstacle upward based on its speed
|
/// Starts the obstacle behavior coroutines
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void HandleMovement()
|
private void StartObstacleBehavior()
|
||||||
{
|
{
|
||||||
|
if (enableMovement)
|
||||||
|
{
|
||||||
|
_movementCoroutine = StartCoroutine(MovementCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
_offScreenCheckCoroutine = StartCoroutine(OffScreenCheckCoroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops all obstacle behavior coroutines
|
||||||
|
/// </summary>
|
||||||
|
private void StopObstacleBehavior()
|
||||||
|
{
|
||||||
|
if (_movementCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(_movementCoroutine);
|
||||||
|
_movementCoroutine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_offScreenCheckCoroutine != null)
|
||||||
|
{
|
||||||
|
StopCoroutine(_offScreenCheckCoroutine);
|
||||||
|
_offScreenCheckCoroutine = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coroutine that handles obstacle movement
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerator MovementCoroutine()
|
||||||
|
{
|
||||||
|
while (enabled && gameObject.activeInHierarchy)
|
||||||
|
{
|
||||||
|
// Move the obstacle upward
|
||||||
transform.position += Vector3.up * (moveSpeed * Time.deltaTime);
|
transform.position += Vector3.up * (moveSpeed * Time.deltaTime);
|
||||||
|
|
||||||
|
// Wait for next frame
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coroutine that checks if obstacle has moved off-screen
|
||||||
|
/// Runs at a lower frequency than movement for better performance
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerator OffScreenCheckCoroutine()
|
||||||
|
{
|
||||||
|
const float checkInterval = 0.2f; // Check every 200ms instead of every frame
|
||||||
|
|
||||||
|
while (enabled && gameObject.activeInHierarchy)
|
||||||
|
{
|
||||||
|
CheckIfOffScreen();
|
||||||
|
|
||||||
|
// Wait for the check interval
|
||||||
|
yield return new WaitForSeconds(checkInterval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -177,5 +236,22 @@ namespace Minigames.DivingForPictures
|
|||||||
{
|
{
|
||||||
ReturnToPool();
|
ReturnToPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Public method to enable/disable movement at runtime
|
||||||
|
/// </summary>
|
||||||
|
public void SetMovementEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (enableMovement == enabled) return;
|
||||||
|
|
||||||
|
enableMovement = enabled;
|
||||||
|
|
||||||
|
// Restart coroutines to apply movement change
|
||||||
|
if (gameObject.activeInHierarchy)
|
||||||
|
{
|
||||||
|
StopObstacleBehavior();
|
||||||
|
StartObstacleBehavior();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ namespace Minigames.DivingForPictures
|
|||||||
private ObstaclePool _obstaclePool;
|
private ObstaclePool _obstaclePool;
|
||||||
private Camera _mainCamera;
|
private Camera _mainCamera;
|
||||||
private float _screenBottom;
|
private float _screenBottom;
|
||||||
|
private float _spawnRangeX;
|
||||||
private Coroutine _spawnCoroutine;
|
private Coroutine _spawnCoroutine;
|
||||||
private readonly List<GameObject> _activeObstacles = new List<GameObject>();
|
private readonly List<GameObject> _activeObstacles = new List<GameObject>();
|
||||||
|
|
||||||
@@ -174,7 +175,7 @@ namespace Minigames.DivingForPictures
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate screen bounds in world space
|
/// Calculate screen bounds in world space dynamically
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void CalculateScreenBounds()
|
private void CalculateScreenBounds()
|
||||||
{
|
{
|
||||||
@@ -188,8 +189,19 @@ namespace Minigames.DivingForPictures
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate screen bottom (Y spawn position will be 2 units below this)
|
||||||
Vector3 bottomWorldPoint = _mainCamera.ViewportToWorldPoint(new Vector3(0.5f, 0f, _mainCamera.nearClipPlane));
|
Vector3 bottomWorldPoint = _mainCamera.ViewportToWorldPoint(new Vector3(0.5f, 0f, _mainCamera.nearClipPlane));
|
||||||
_screenBottom = bottomWorldPoint.y;
|
_screenBottom = bottomWorldPoint.y;
|
||||||
|
|
||||||
|
// Calculate screen width in world units
|
||||||
|
Vector3 leftWorldPoint = _mainCamera.ViewportToWorldPoint(new Vector3(0f, 0.5f, _mainCamera.nearClipPlane));
|
||||||
|
Vector3 rightWorldPoint = _mainCamera.ViewportToWorldPoint(new Vector3(1f, 0.5f, _mainCamera.nearClipPlane));
|
||||||
|
float screenWidth = rightWorldPoint.x - leftWorldPoint.x;
|
||||||
|
|
||||||
|
// Calculate spawn range based on 80% of screen width (40% on each side from center)
|
||||||
|
_spawnRangeX = (screenWidth * 0.8f) / 2f;
|
||||||
|
|
||||||
|
Debug.Log($"[ObstacleSpawner] Screen calculated - Width: {screenWidth:F2}, Bottom: {_screenBottom:F2}, Spawn Range X: ±{_spawnRangeX:F2}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -273,8 +285,10 @@ namespace Minigames.DivingForPictures
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Vector3 GetRandomSpawnPosition()
|
private Vector3 GetRandomSpawnPosition()
|
||||||
{
|
{
|
||||||
float randomX = Random.Range(-spawnRangeX, spawnRangeX);
|
// Use dynamically calculated spawn range (80% of screen width)
|
||||||
float spawnY = _screenBottom - spawnDistanceBelowScreen;
|
float randomX = Random.Range(-_spawnRangeX, _spawnRangeX);
|
||||||
|
// Spawn 2 units below screen bottom
|
||||||
|
float spawnY = _screenBottom - 2f;
|
||||||
|
|
||||||
return new Vector3(randomX, spawnY, 0f);
|
return new Vector3(randomX, spawnY, 0f);
|
||||||
}
|
}
|
||||||
@@ -416,6 +430,14 @@ namespace Minigames.DivingForPictures
|
|||||||
maxMoveSpeed = max;
|
maxMoveSpeed = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Public method to recalculate screen bounds (useful if camera changes)
|
||||||
|
/// </summary>
|
||||||
|
public void RecalculateScreenBounds()
|
||||||
|
{
|
||||||
|
CalculateScreenBounds();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the count of currently active obstacles
|
/// Gets the count of currently active obstacles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -424,16 +446,20 @@ namespace Minigames.DivingForPictures
|
|||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private void OnDrawGizmosSelected()
|
private void OnDrawGizmosSelected()
|
||||||
{
|
{
|
||||||
// Draw spawn area
|
// Only draw if screen bounds have been calculated
|
||||||
|
if (_spawnRangeX > 0f)
|
||||||
|
{
|
||||||
|
// Draw spawn area using dynamic calculations
|
||||||
Gizmos.color = Color.yellow;
|
Gizmos.color = Color.yellow;
|
||||||
Vector3 center = new Vector3(0f, _screenBottom - spawnDistanceBelowScreen, 0f);
|
Vector3 center = new Vector3(0f, _screenBottom - 2f, 0f);
|
||||||
Vector3 size = new Vector3(spawnRangeX * 2f, 1f, 1f);
|
Vector3 size = new Vector3(_spawnRangeX * 2f, 1f, 1f);
|
||||||
Gizmos.DrawWireCube(center, size);
|
Gizmos.DrawWireCube(center, size);
|
||||||
|
|
||||||
// Draw collision radius at spawn point
|
// Draw collision radius at spawn point
|
||||||
Gizmos.color = Color.red;
|
Gizmos.color = Color.red;
|
||||||
Gizmos.DrawWireSphere(center, spawnCollisionRadius);
|
Gizmos.DrawWireSphere(center, spawnCollisionRadius);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user