pooper_minigame (#62)
Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Reviewed-on: #62
This commit is contained in:
197
Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs
Normal file
197
Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using Core;
|
||||
using Core.Lifecycle;
|
||||
using Core.Settings;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Minigames.BirdPooper
|
||||
{
|
||||
/// <summary>
|
||||
/// Bird player controller with Flappy Bird-style flight mechanics.
|
||||
/// Responds to tap input to flap, with manual gravity simulation.
|
||||
/// </summary>
|
||||
public class BirdPlayerController : ManagedBehaviour, ITouchInputConsumer
|
||||
{
|
||||
[Header("Events")]
|
||||
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
|
||||
|
||||
internal override void OnManagedAwake()
|
||||
{
|
||||
base.OnManagedAwake();
|
||||
|
||||
// Initialize events
|
||||
if (OnFlap == null)
|
||||
OnFlap = new UnityEngine.Events.UnityEvent();
|
||||
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
|
||||
{
|
||||
Debug.LogError("[BirdPlayerController] Rigidbody2D component not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Register as override consumer to capture ALL input (except UI button)
|
||||
// Register as override consumer to capture ALL input (except UI button)
|
||||
if (Input.InputManager.Instance != null)
|
||||
{
|
||||
Input.InputManager.Instance.RegisterOverrideConsumer(this);
|
||||
Debug.Log("[BirdPlayerController] Registered as override input consumer");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[BirdPlayerController] InputManager instance not found!");
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnHoldStart(Vector2 position) { }
|
||||
public void OnHoldMove(Vector2 position) { }
|
||||
public void OnHoldEnd(Vector2 position) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rotation
|
||||
|
||||
/// <summary>
|
||||
/// Updates the bird's rotation based on vertical velocity.
|
||||
/// Bird tilts up when flapping, down when falling.
|
||||
/// </summary>
|
||||
private void UpdateRotation()
|
||||
{
|
||||
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
|
||||
);
|
||||
float targetAngle = Mathf.Lerp(
|
||||
-settings.MaxRotationAngle,
|
||||
settings.MaxRotationAngle,
|
||||
velocityPercent
|
||||
);
|
||||
|
||||
// Get current angle (handle 0-360 wrapping to -180-180)
|
||||
float currentAngle = transform.rotation.eulerAngles.z;
|
||||
if (currentAngle > 180f)
|
||||
currentAngle -= 360f;
|
||||
|
||||
// Smooth interpolation to target
|
||||
float smoothedAngle = Mathf.Lerp(
|
||||
currentAngle,
|
||||
targetAngle,
|
||||
settings.RotationSpeed * Time.deltaTime
|
||||
);
|
||||
|
||||
// Apply rotation to Z axis only (2D rotation)
|
||||
transform.rotation = Quaternion.Euler(0, 0, smoothedAngle);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Trigger-Based Collision Detection
|
||||
|
||||
/// <summary>
|
||||
/// Called when a trigger collider enters this object's trigger.
|
||||
/// Used for detecting obstacles without physics interactions.
|
||||
/// </summary>
|
||||
private void OnTriggerEnter2D(Collider2D other)
|
||||
{
|
||||
// Check if the colliding object is tagged as an obstacle
|
||||
if (other.CompareTag("Obstacle"))
|
||||
{
|
||||
HandleDeath();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDeath()
|
||||
{
|
||||
// Only process death once
|
||||
if (isDead) return;
|
||||
|
||||
isDead = true;
|
||||
verticalVelocity = 0f;
|
||||
Debug.Log("[BirdPlayerController] Bird died!");
|
||||
|
||||
// Emit damage event - let the game manager handle UI
|
||||
OnPlayerDamaged?.Invoke();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public bool IsDead => isDead;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user