using UnityEngine; namespace FlappyBird.Gameplay.Bird { /// /// Pure C# service — all bird physics and rotation logic lives here. /// No MonoBehaviour, no Unity lifecycle. Injected via Zenject. /// public sealed class BirdController : IBirdController { // ── Dependencies ──────────────────────────────────────────────────── private readonly Rigidbody2D _rigidbody; private readonly BirdSettings _settings; /// /// Constructor injection (Zenject will call this). /// /// The bird's Rigidbody2D component. /// Configurable physics parameters. public BirdController(Rigidbody2D rigidbody, BirdSettings settings) { _rigidbody = rigidbody; _settings = settings; // Lock X position so the bird never drifts horizontally. // The illusion of forward movement comes from pipes scrolling left. _rigidbody.constraints = RigidbodyConstraints2D.FreezePositionX; } // ── IBirdController ───────────────────────────────────────────────── /// public void Tick() { ApplyRotation(); } /// public void Jump() { // Reset vertical velocity so each tap feels consistent regardless of fall speed. // X is frozen via constraints, but we explicitly keep it zero for safety. _rigidbody.linearVelocity = Vector2.zero; _rigidbody.AddForce(Vector2.up * _settings.JumpForce, ForceMode2D.Impulse); } // ── Private helpers ───────────────────────────────────────────────── /// /// Maps vertical velocity to a tilt angle and smoothly rotates the bird. /// Velocity range [rotationUpVelocity .. rotationDownVelocity] maps to /// [maxUpRotation .. maxDownRotation] via an inverse-lerp → lerp. /// private void ApplyRotation() { float velocityY = _rigidbody.linearVelocity.y; // Normalise velocity to [0, 1] (0 = falling fast, 1 = rising fast). float t = Mathf.InverseLerp( _settings.RotationDownVelocity, _settings.RotationUpVelocity, velocityY); float targetAngle = Mathf.Lerp( _settings.MaxDownRotation, _settings.MaxUpRotation, t); // Read current Z rotation from the transform via the rigidbody. float currentAngle = _rigidbody.rotation; float smoothedAngle = Mathf.LerpAngle( currentAngle, targetAngle, _settings.RotationSpeed * Time.deltaTime); _rigidbody.MoveRotation(smoothedAngle); } } }