From b2bc77674d1dce05e291ff3f6219cbeb2e5de378 Mon Sep 17 00:00:00 2001 From: Michal Pikulski Date: Thu, 18 Dec 2025 14:04:50 +0100 Subject: [PATCH] Update bird pooper speed discrepancy --- .../BirdPooper/BirdPlayerController.cs | 73 +++++++++- .../BirdPooper/BirdPooperDebugDisplay.cs | 137 ++++++++++++++++++ .../BirdPooper/BirdPooperDebugDisplay.cs.meta | 3 + Assets/Settings/BirdPooperSettings.asset | 4 +- 4 files changed, 208 insertions(+), 9 deletions(-) create mode 100644 Assets/Scripts/Minigames/BirdPooper/BirdPooperDebugDisplay.cs create mode 100644 Assets/Scripts/Minigames/BirdPooper/BirdPooperDebugDisplay.cs.meta diff --git a/Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs b/Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs index 1b36be50..17654328 100644 --- a/Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs +++ b/Assets/Scripts/Minigames/BirdPooper/BirdPlayerController.cs @@ -15,12 +15,22 @@ namespace Minigames.BirdPooper public UnityEngine.Events.UnityEvent OnFlap; public UnityEngine.Events.UnityEvent OnPlayerDamaged; + [Header("Flap Cooldown")] + [Tooltip("Minimum seconds between flaps to prevent multi-tap issues on mobile")] + [SerializeField] private float flapCooldown = 0.15f; + 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 + private float _lastFlapTime = -Mathf.Infinity; // Track last flap time for cooldown + + // Diagnostic tracking + private int _updateFrameCount = 0; + private float _maxDeltaTime = 0f; + private float _minDeltaTime = float.MaxValue; internal override void OnManagedAwake() { @@ -86,17 +96,44 @@ namespace Minigames.BirdPooper } _isInitialized = true; - Debug.Log($"[BirdPlayerController] Initialized! Fixed X position: {_fixedXPosition}"); + + // DIAGNOSTIC: Log all critical values that might differ between platforms + Debug.Log($"[BirdPlayerController] ===== INITIALIZATION DIAGNOSTICS ====="); + Debug.Log($"[BirdPlayerController] Fixed X position: {_fixedXPosition}"); + Debug.Log($"[BirdPlayerController] Time.timeScale: {Time.timeScale}"); + Debug.Log($"[BirdPlayerController] Application.targetFrameRate: {Application.targetFrameRate}"); + Debug.Log($"[BirdPlayerController] Settings.Gravity: {_settings.Gravity}"); + Debug.Log($"[BirdPlayerController] Settings.FlapForce: {_settings.FlapForce}"); + Debug.Log($"[BirdPlayerController] Settings.MaxFallSpeed: {_settings.MaxFallSpeed}"); + Debug.Log($"[BirdPlayerController] Settings.MinY: {_settings.MinY}"); + Debug.Log($"[BirdPlayerController] Settings.MaxY: {_settings.MaxY}"); + Debug.Log($"[BirdPlayerController] =========================================="); } - private void Update() + /// + /// Using FixedUpdate for physics to ensure frame-rate independence. + /// FixedUpdate runs at a fixed timestep (default 0.02s = 50fps) regardless of actual frame rate. + /// + private void FixedUpdate() { // Only run physics/movement if initialized if (!_isInitialized || _isDead || _settings == null || _rb == null) return; - // Apply manual gravity - _verticalVelocity -= _settings.Gravity * Time.deltaTime; + // DIAGNOSTIC: Track fixedDeltaTime (should be consistent) + _updateFrameCount++; + float dt = Time.fixedDeltaTime; + if (dt > _maxDeltaTime) _maxDeltaTime = dt; + if (dt < _minDeltaTime) _minDeltaTime = dt; + + // Log diagnostics every 50 fixed frames (every second at 50fps fixed timestep) + if (_updateFrameCount % 50 == 0) + { + Debug.Log($"[BirdPlayerController] FixedFrame {_updateFrameCount}: fixedDeltaTime={dt:F4}, min={_minDeltaTime:F4}, max={_maxDeltaTime:F4}, velocity={_verticalVelocity:F2}, pos.y={_rb.position.y:F2}"); + } + + // Apply manual gravity using fixedDeltaTime for consistent physics + _verticalVelocity -= _settings.Gravity * dt; // Cap fall speed (terminal velocity) if (_verticalVelocity < -_settings.MaxFallSpeed) @@ -104,15 +141,26 @@ namespace Minigames.BirdPooper // Update position manually Vector2 newPosition = _rb.position; - newPosition.y += _verticalVelocity * Time.deltaTime; + newPosition.y += _verticalVelocity * dt; 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 runs at actual frame rate for smooth visual updates like rotation. + /// Physics calculations moved to FixedUpdate for frame-rate independence. + /// + private void Update() + { + // Only update visuals if initialized + if (!_isInitialized || _isDead || _settings == null) + return; - // Update rotation based on velocity + // Update rotation based on velocity (visual only, runs at frame rate for smoothness) UpdateRotation(); } @@ -138,14 +186,25 @@ namespace Minigames.BirdPooper /// /// Makes the bird flap, applying upward velocity. /// Can be called by input system or externally (e.g., for first tap). + /// Includes cooldown to prevent multi-tap issues on mobile devices. /// public void Flap() { if (!_isInitialized || _isDead || _settings == null) return; + // Cooldown check to prevent multi-tap issues (especially on mobile touchscreens) + if (Time.time < _lastFlapTime + flapCooldown) + { + Debug.Log($"[BirdPlayerController] Flap rejected - on cooldown ({Time.time - _lastFlapTime:F3}s since last flap)"); + return; + } + _verticalVelocity = _settings.FlapForce; - Debug.Log($"[BirdPlayerController] Flap! velocity = {_verticalVelocity}"); + _lastFlapTime = Time.time; + + // DIAGNOSTIC: Log flap details including time values + Debug.Log($"[BirdPlayerController] FLAP! velocity={_verticalVelocity}, Time.time={Time.time}, Time.deltaTime={Time.deltaTime}, Time.timeScale={Time.timeScale}"); // Emit flap event OnFlap?.Invoke(); diff --git a/Assets/Scripts/Minigames/BirdPooper/BirdPooperDebugDisplay.cs b/Assets/Scripts/Minigames/BirdPooper/BirdPooperDebugDisplay.cs new file mode 100644 index 00000000..0f6f8c31 --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/BirdPooperDebugDisplay.cs @@ -0,0 +1,137 @@ +using UnityEngine; +using TMPro; + +namespace Minigames.BirdPooper +{ + /// + /// On-screen debug display for Bird Pooper minigame diagnostics. + /// Shows critical values that might differ between PC and mobile platforms. + /// + public class BirdPooperDebugDisplay : MonoBehaviour + { + [Header("References")] + [SerializeField] private BirdPlayerController birdController; + [SerializeField] private TextMeshProUGUI debugText; + + [Header("Settings")] + [SerializeField] private bool showDebugDisplay = true; + [SerializeField] private float updateInterval = 0.1f; // Update display every 0.1 seconds + + private float _nextUpdateTime; + private int _frameCount; + private float _minDeltaTime = float.MaxValue; + private float _maxDeltaTime = 0f; + private float _avgDeltaTime; + private float _deltaTimeSum; + + private void Start() + { + if (debugText == null) + { + Debug.LogError("[BirdPooperDebugDisplay] Debug text reference not assigned!"); + enabled = false; + return; + } + + if (birdController == null) + { + birdController = FindFirstObjectByType(); + if (birdController == null) + { + Debug.LogError("[BirdPooperDebugDisplay] Could not find BirdPlayerController!"); + enabled = false; + return; + } + } + + debugText.gameObject.SetActive(showDebugDisplay); + _nextUpdateTime = Time.time + updateInterval; + } + + private void Update() + { + if (!showDebugDisplay || debugText == null) + return; + + // Track deltaTime statistics + _frameCount++; + _deltaTimeSum += Time.deltaTime; + if (Time.deltaTime < _minDeltaTime) _minDeltaTime = Time.deltaTime; + if (Time.deltaTime > _maxDeltaTime) _maxDeltaTime = Time.deltaTime; + _avgDeltaTime = _deltaTimeSum / _frameCount; + + // Update display at specified interval + if (Time.time >= _nextUpdateTime) + { + UpdateDebugDisplay(); + _nextUpdateTime = Time.time + updateInterval; + } + } + + private void UpdateDebugDisplay() + { + if (debugText == null) return; + + // Get settings from the bird controller via reflection (hacky but works for debug) + var settingsField = typeof(BirdPlayerController).GetField("_settings", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var settings = settingsField?.GetValue(birdController) as Core.Settings.IBirdPooperSettings; + + var velocityField = typeof(BirdPlayerController).GetField("_verticalVelocity", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + float velocity = velocityField != null ? (float)velocityField.GetValue(birdController) : 0f; + + var rbField = typeof(BirdPlayerController).GetField("_rb", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var rb = rbField?.GetValue(birdController) as Rigidbody2D; + + // Calculate actual FPS + float fps = _avgDeltaTime > 0 ? 1f / _avgDeltaTime : 0f; + + // Build debug string + string debugInfo = "BIRD POOPER DEBUG\n"; + debugInfo += "───────────\n"; + debugInfo += $"PLATFORM: {Application.platform}\n"; + debugInfo += $"TIME SCALE: {Time.timeScale:F2}\n"; + debugInfo += $"TARGET FPS: {Application.targetFrameRate}\n"; + debugInfo += $"ACTUAL FPS: {fps:F1}\n"; + debugInfo += "───────────\n"; + debugInfo += $"ΔTime: {Time.deltaTime:F4}s\n"; + debugInfo += $"ΔTime Min: {_minDeltaTime:F4}s\n"; + debugInfo += $"ΔTime Max: {_maxDeltaTime:F4}s\n"; + debugInfo += $"ΔTime Avg: {_avgDeltaTime:F4}s\n"; + debugInfo += $"Fixed ΔT: {Time.fixedDeltaTime:F4}s\n"; + debugInfo += "───────────\n"; + + if (settings != null) + { + debugInfo += $"Gravity: {settings.Gravity}\n"; + debugInfo += $"Flap Force: {settings.FlapForce}\n"; + debugInfo += $"Max Fall: {settings.MaxFallSpeed}\n"; + debugInfo += "───────────\n"; + } + + debugInfo += $"Velocity: {velocity:F2}\n"; + if (rb != null) + { + debugInfo += $"Position Y: {rb.position.y:F2}\n"; + } + debugInfo += $"Dead: {birdController.IsDead}\n"; + + debugText.text = debugInfo; + } + + /// + /// Toggle debug display visibility - can be called from UI button + /// + public void ToggleDisplay() + { + showDebugDisplay = !showDebugDisplay; + if (debugText != null) + { + debugText.gameObject.SetActive(showDebugDisplay); + } + } + } +} + diff --git a/Assets/Scripts/Minigames/BirdPooper/BirdPooperDebugDisplay.cs.meta b/Assets/Scripts/Minigames/BirdPooper/BirdPooperDebugDisplay.cs.meta new file mode 100644 index 00000000..825863a6 --- /dev/null +++ b/Assets/Scripts/Minigames/BirdPooper/BirdPooperDebugDisplay.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 28d9dbe8309a4e1e8529953f5b400c0e +timeCreated: 1766062170 \ No newline at end of file diff --git a/Assets/Settings/BirdPooperSettings.asset b/Assets/Settings/BirdPooperSettings.asset index 43b25ff0..6e0edae5 100644 --- a/Assets/Settings/BirdPooperSettings.asset +++ b/Assets/Settings/BirdPooperSettings.asset @@ -12,8 +12,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: e7d3f5b948b3454681fa573071bee978, type: 3} m_Name: BirdPooperSettings m_EditorClassIdentifier: AppleHillsScripts::Core.Settings.BirdPooperSettings - gravity: 110 - flapForce: 55 + gravity: 75 + flapForce: 25 maxFallSpeed: 120 minY: -15 maxY: 15