Time-based difficulty scaling with object pools and bird pooper restart improvements to the minigame

This commit is contained in:
Michal Pikulski
2025-12-16 23:21:10 +01:00
parent 0ff3fbbc70
commit 6133caec53
14 changed files with 994 additions and 280 deletions

View File

@@ -15,11 +15,12 @@ namespace Minigames.BirdPooper
public UnityEngine.Events.UnityEvent OnFlap;
public UnityEngine.Events.UnityEvent OnPlayerDamaged;
private Rigidbody2D rb;
private IBirdPooperSettings settings;
private float verticalVelocity = 0f;
private bool isDead = false;
private float fixedXPosition; // Store the initial X position from the scene
private Rigidbody2D _rb;
private IBirdPooperSettings _settings;
private float _verticalVelocity;
private bool _isDead;
private float _fixedXPosition; // Store the initial X position from the scene
private bool _isInitialized; // Flag to control when physics/input are active
internal override void OnManagedAwake()
{
@@ -31,33 +32,49 @@ namespace Minigames.BirdPooper
if (OnPlayerDamaged == null)
OnPlayerDamaged = new UnityEngine.Events.UnityEvent();
// Load settings
settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
if (settings == null)
{
Debug.LogError("[BirdPlayerController] BirdPooperSettings not found!");
return;
}
// Get Rigidbody2D component (Dynamic with gravityScale = 0)
rb = GetComponent<Rigidbody2D>();
if (rb != null)
{
rb.gravityScale = 0f; // Disable Unity physics gravity
rb.bodyType = RigidbodyType2D.Kinematic; // Kinematic = manual movement, no physics forces
// Store the initial X position from the scene
fixedXPosition = rb.position.x;
Debug.Log($"[BirdPlayerController] Fixed X position set to: {fixedXPosition}");
}
else
// Only cache component references - NO setup yet
_rb = GetComponent<Rigidbody2D>();
if (_rb == null)
{
Debug.LogError("[BirdPlayerController] Rigidbody2D component not found!");
return;
}
// Register as default consumer (gets input if nothing else consumes it)
// This allows UI buttons to work while still flapping when tapping empty space
// Load settings
_settings = GameManager.GetSettingsObject<IBirdPooperSettings>();
if (_settings == null)
{
Debug.LogError("[BirdPlayerController] BirdPooperSettings not found!");
}
Debug.Log("[BirdPlayerController] References cached, waiting for initialization...");
}
/// <summary>
/// Initializes the player controller - enables physics and input.
/// Should be called by BirdPooperGameManager when ready to start the game.
/// </summary>
public void Initialize()
{
if (_isInitialized)
{
Debug.LogWarning("[BirdPlayerController] Already initialized!");
return;
}
if (_rb == null || _settings == null)
{
Debug.LogError("[BirdPlayerController] Cannot initialize - missing references!");
return;
}
// Setup physics
_rb.gravityScale = 0f; // Disable Unity physics gravity
_rb.bodyType = RigidbodyType2D.Kinematic; // Kinematic = manual movement, no physics forces
// Store the initial X position from the scene
_fixedXPosition = _rb.position.x;
// Register as default input consumer
if (Input.InputManager.Instance != null)
{
Input.InputManager.Instance.SetDefaultConsumer(this);
@@ -67,52 +84,74 @@ namespace Minigames.BirdPooper
{
Debug.LogError("[BirdPlayerController] InputManager instance not found!");
}
_isInitialized = true;
Debug.Log($"[BirdPlayerController] Initialized! Fixed X position: {_fixedXPosition}");
}
private void Update()
{
if (!isDead && settings != null && rb != null)
{
// Apply manual gravity
verticalVelocity -= settings.Gravity * Time.deltaTime;
// Cap fall speed (terminal velocity)
if (verticalVelocity < -settings.MaxFallSpeed)
verticalVelocity = -settings.MaxFallSpeed;
// Update position manually
Vector2 newPosition = rb.position;
newPosition.y += verticalVelocity * Time.deltaTime;
newPosition.x = fixedXPosition; // Keep X fixed at scene-configured position
// Clamp Y position to bounds
newPosition.y = Mathf.Clamp(newPosition.y, settings.MinY, settings.MaxY);
rb.MovePosition(newPosition);
// Update rotation based on velocity
UpdateRotation();
}
// Only run physics/movement if initialized
if (!_isInitialized || _isDead || _settings == null || _rb == null)
return;
// Apply manual gravity
_verticalVelocity -= _settings.Gravity * Time.deltaTime;
// Cap fall speed (terminal velocity)
if (_verticalVelocity < -_settings.MaxFallSpeed)
_verticalVelocity = -_settings.MaxFallSpeed;
// Update position manually
Vector2 newPosition = _rb.position;
newPosition.y += _verticalVelocity * Time.deltaTime;
newPosition.x = _fixedXPosition; // Keep X fixed at scene-configured position
// Clamp Y position to bounds
newPosition.y = Mathf.Clamp(newPosition.y, _settings.MinY, _settings.MaxY);
_rb.MovePosition(newPosition);
// Update rotation based on velocity
UpdateRotation();
}
#region ITouchInputConsumer Implementation
public void OnTap(Vector2 tapPosition)
{
if (!isDead && settings != null)
{
verticalVelocity = settings.FlapForce;
Debug.Log($"[BirdPlayerController] Flap! velocity = {verticalVelocity}");
// Emit flap event
OnFlap?.Invoke();
}
// Only respond to input if initialized and alive
if (!_isInitialized || _isDead || _settings == null)
return;
Flap();
}
public void OnHoldStart(Vector2 position) { }
public void OnHoldMove(Vector2 position) { }
public void OnHoldEnd(Vector2 position) { }
#endregion
#region Player Actions
/// <summary>
/// Makes the bird flap, applying upward velocity.
/// Can be called by input system or externally (e.g., for first tap).
/// </summary>
public void Flap()
{
if (!_isInitialized || _isDead || _settings == null)
return;
_verticalVelocity = _settings.FlapForce;
Debug.Log($"[BirdPlayerController] Flap! velocity = {_verticalVelocity}");
// Emit flap event
OnFlap?.Invoke();
}
#endregion
#region Rotation
@@ -123,19 +162,19 @@ namespace Minigames.BirdPooper
/// </summary>
private void UpdateRotation()
{
if (settings == null) return;
if (_settings == null) return;
// Map velocity to rotation angle
// When falling at max speed (-MaxFallSpeed): -MaxRotationAngle (down)
// When at flap velocity (+FlapForce): +MaxRotationAngle (up)
float velocityPercent = Mathf.InverseLerp(
-settings.MaxFallSpeed,
settings.FlapForce,
verticalVelocity
-_settings.MaxFallSpeed,
_settings.FlapForce,
_verticalVelocity
);
float targetAngle = Mathf.Lerp(
-settings.MaxRotationAngle,
settings.MaxRotationAngle,
-_settings.MaxRotationAngle,
_settings.MaxRotationAngle,
velocityPercent
);
@@ -148,7 +187,7 @@ namespace Minigames.BirdPooper
float smoothedAngle = Mathf.Lerp(
currentAngle,
targetAngle,
settings.RotationSpeed * Time.deltaTime
_settings.RotationSpeed * Time.deltaTime
);
// Apply rotation to Z axis only (2D rotation)
@@ -175,10 +214,10 @@ namespace Minigames.BirdPooper
private void HandleDeath()
{
// Only process death once
if (isDead) return;
if (_isDead) return;
isDead = true;
verticalVelocity = 0f;
_isDead = true;
_verticalVelocity = 0f;
Debug.Log("[BirdPlayerController] Bird died!");
// Emit damage event - let the game manager handle UI
@@ -187,9 +226,9 @@ namespace Minigames.BirdPooper
#endregion
#region Public Properties
#region Public Accessors
public bool IsDead => isDead;
public bool IsDead => _isDead;
#endregion
}