From c5f37a5df4fe4dcd605f48f793641cce6114b1d9 Mon Sep 17 00:00:00 2001 From: Michal Pikulski Date: Tue, 16 Dec 2025 19:29:01 +0100 Subject: [PATCH] Fix weapon selection issues and shot tracking --- .../FortFight/Core/AmmunitionManager.cs | 28 +++++ .../FortFight/Core/ProjectileTurnAction.cs | 110 +++++++++++------- .../Minigames/FortFight/Core/TurnManager.cs | 5 +- .../Projectiles/TrashBagProjectile.cs | 31 ++++- 4 files changed, 125 insertions(+), 49 deletions(-) diff --git a/Assets/Scripts/Minigames/FortFight/Core/AmmunitionManager.cs b/Assets/Scripts/Minigames/FortFight/Core/AmmunitionManager.cs index 4b5df415..cdbc11fb 100644 --- a/Assets/Scripts/Minigames/FortFight/Core/AmmunitionManager.cs +++ b/Assets/Scripts/Minigames/FortFight/Core/AmmunitionManager.cs @@ -220,6 +220,34 @@ namespace Minigames.FortFight.Core return true; } + /// + /// Select the first available (non-cooldown) ammo for a player. + /// Called at the start of each turn to reset selection. + /// + public bool SelectFirstAvailableAmmo(int playerIndex) + { + if (!_playerStates.ContainsKey(playerIndex)) + { + Logging.Warning($"[AmmunitionManager] Player {playerIndex} state not found!"); + return false; + } + + var configs = AvailableConfigs; + foreach (var config in configs) + { + if (IsAmmoAvailable(config.projectileType, playerIndex)) + { + return SelectAmmo(config.projectileType, playerIndex); + } + } + + // Fallback: select default even if on cooldown (shouldn't happen in normal gameplay) + Logging.Warning($"[AmmunitionManager] Player {playerIndex}: No ammo available! Falling back to default."); + _playerStates[playerIndex].SelectedAmmo = defaultProjectileType; + OnAmmoSelected?.Invoke(defaultProjectileType, playerIndex); + return false; + } + /// /// Get currently selected projectile type for a specific player /// diff --git a/Assets/Scripts/Minigames/FortFight/Core/ProjectileTurnAction.cs b/Assets/Scripts/Minigames/FortFight/Core/ProjectileTurnAction.cs index 87973780..413e66a0 100644 --- a/Assets/Scripts/Minigames/FortFight/Core/ProjectileTurnAction.cs +++ b/Assets/Scripts/Minigames/FortFight/Core/ProjectileTurnAction.cs @@ -1,5 +1,4 @@ -using AppleHills.Core.Settings; -using Core; +using Core; using Core.Settings; using Minigames.FortFight.Data; using Minigames.FortFight.Projectiles; @@ -13,14 +12,14 @@ namespace Minigames.FortFight.Core /// public class ProjectileTurnAction { - private SlingshotController slingshot; - private AmmunitionManager ammoManager; - private CameraController cameraController; - private int playerIndex; - private ProjectileBase activeProjectile; - private bool launchComplete = false; - private bool projectileSettled = false; - private float settleTimer = 0f; + private SlingshotController _slingshot; + private AmmunitionManager _ammoManager; + private CameraController _cameraController; + private int _playerIndex; + private ProjectileBase _activeProjectile; + private bool _launchComplete = false; + private bool _projectileSettled = false; + private float _settleTimer = 0f; private IFortFightSettings _cachedSettings; private IFortFightSettings CachedSettings @@ -35,14 +34,14 @@ namespace Minigames.FortFight.Core } } - public bool IsComplete => projectileSettled; + public bool IsComplete => _projectileSettled; public ProjectileTurnAction(SlingshotController slingshot, AmmunitionManager ammoManager, CameraController cameraController, int playerIndex) { - this.slingshot = slingshot; - this.ammoManager = ammoManager; - this.cameraController = cameraController; - this.playerIndex = playerIndex; + this._slingshot = slingshot; + this._ammoManager = ammoManager; + this._cameraController = cameraController; + this._playerIndex = playerIndex; } /// @@ -53,12 +52,12 @@ namespace Minigames.FortFight.Core Logging.Debug("[ProjectileTurnAction] Executing - enabling slingshot"); // Enable slingshot - if (slingshot != null) + if (_slingshot != null) { - slingshot.Enable(); + _slingshot.Enable(); // Subscribe to launch event - slingshot.OnProjectileLaunched += HandleProjectileLaunched; + _slingshot.OnProjectileLaunched += HandleProjectileLaunched; } } @@ -67,28 +66,28 @@ namespace Minigames.FortFight.Core /// public void Update() { - if (!launchComplete) return; + if (!_launchComplete) return; // Check if projectile is destroyed or stopped - if (activeProjectile == null) + if (_activeProjectile == null) { // Projectile destroyed - start settle timer - if (settleTimer == 0f) + if (_settleTimer == 0f) { Logging.Debug("[ProjectileTurnAction] Projectile destroyed - starting settle timer"); } - settleTimer += Time.deltaTime; + _settleTimer += Time.deltaTime; float settleDelay = CachedSettings?.ProjectileSettleDelay ?? 2.5f; - if (settleTimer >= settleDelay) + if (_settleTimer >= settleDelay) { - projectileSettled = true; + _projectileSettled = true; // Stop camera tracking when projectile settles - if (cameraController != null) + if (_cameraController != null) { - cameraController.StopFollowingProjectile(); + _cameraController.StopFollowingProjectile(); } Logging.Debug("[ProjectileTurnAction] Turn action complete"); @@ -97,20 +96,20 @@ namespace Minigames.FortFight.Core else { // Check if projectile has stopped moving - Rigidbody2D rb = activeProjectile.GetComponent(); + Rigidbody2D rb = _activeProjectile.GetComponent(); if (rb != null && rb.linearVelocity.magnitude < 0.5f) { - settleTimer += Time.deltaTime; + _settleTimer += Time.deltaTime; float settleDelay = CachedSettings?.ProjectileSettleDelay ?? 2.5f; - if (settleTimer >= settleDelay) + if (_settleTimer >= settleDelay) { - projectileSettled = true; + _projectileSettled = true; // Stop camera tracking when projectile settles - if (cameraController != null) + if (_cameraController != null) { - cameraController.StopFollowingProjectile(); + _cameraController.StopFollowingProjectile(); } Logging.Debug("[ProjectileTurnAction] Projectile settled - turn action complete"); @@ -119,7 +118,7 @@ namespace Minigames.FortFight.Core else { // Reset settle timer if still moving - settleTimer = 0f; + _settleTimer = 0f; } } } @@ -129,10 +128,10 @@ namespace Minigames.FortFight.Core /// public void Cancel() { - if (slingshot != null) + if (_slingshot != null) { - slingshot.Disable(); - slingshot.OnProjectileLaunched -= HandleProjectileLaunched; + _slingshot.Disable(); + _slingshot.OnProjectileLaunched -= HandleProjectileLaunched; } } @@ -140,26 +139,47 @@ namespace Minigames.FortFight.Core { Logging.Debug($"[ProjectileTurnAction] Projectile launched: {projectile.gameObject.name}"); - launchComplete = true; - activeProjectile = projectile; + _launchComplete = true; + _activeProjectile = projectile; // Disable slingshot after launch - if (slingshot != null) + if (_slingshot != null) { - slingshot.Disable(); + _slingshot.Disable(); } // Trigger cooldown for used ammo for this player - if (ammoManager != null) + if (_ammoManager != null) { - ProjectileType usedAmmoType = ammoManager.GetSelectedAmmoType(playerIndex); - ammoManager.UseAmmo(usedAmmoType, playerIndex); + ProjectileType usedAmmoType = _ammoManager.GetSelectedAmmoType(_playerIndex); + _ammoManager.UseAmmo(usedAmmoType, _playerIndex); + } + + // Check if this is a TrashBag projectile to handle explosion tracking + var trashBag = projectile as TrashBagProjectile; + if (trashBag != null) + { + trashBag.OnTrashPiecesSpawned += HandleTrashPiecesSpawned; } // Start camera tracking the projectile - if (cameraController != null && projectile != null) + if (_cameraController != null && projectile != null) { - cameraController.StartFollowingProjectile(projectile.transform); + _cameraController.StartFollowingProjectile(projectile.transform); + } + } + + /// + /// Handle trash bag explosion - switch camera to follow a trash piece + /// + private void HandleTrashPiecesSpawned(Transform trashPiece) + { + if (trashPiece != null && _cameraController != null) + { + Logging.Debug($"[ProjectileTurnAction] TrashBag exploded - switching camera to trash piece"); + _cameraController.StartFollowingProjectile(trashPiece); + + // The turn will complete when the trash piece settles (using existing settle logic) } } } diff --git a/Assets/Scripts/Minigames/FortFight/Core/TurnManager.cs b/Assets/Scripts/Minigames/FortFight/Core/TurnManager.cs index c8322f90..e2f6c3a5 100644 --- a/Assets/Scripts/Minigames/FortFight/Core/TurnManager.cs +++ b/Assets/Scripts/Minigames/FortFight/Core/TurnManager.cs @@ -210,9 +210,12 @@ namespace Minigames.FortFight.Core // Set slingshot owner (used for projectile ownership tracking) activeSlingshot.SetOwner(_currentPlayer.PlayerIndex, _currentPlayer.IsAI); - // Set current ammo on slingshot for this player + // Reset ammo selection to first available weapon at start of turn if (AmmunitionManager.Instance != null) { + AmmunitionManager.Instance.SelectFirstAvailableAmmo(_currentPlayer.PlayerIndex); + + // Set the selected ammo on slingshot ProjectileConfig currentAmmo = AmmunitionManager.Instance.GetSelectedAmmoConfig(_currentPlayer.PlayerIndex); if (currentAmmo != null) { diff --git a/Assets/Scripts/Minigames/FortFight/Projectiles/TrashBagProjectile.cs b/Assets/Scripts/Minigames/FortFight/Projectiles/TrashBagProjectile.cs index 904d3d58..384685d0 100644 --- a/Assets/Scripts/Minigames/FortFight/Projectiles/TrashBagProjectile.cs +++ b/Assets/Scripts/Minigames/FortFight/Projectiles/TrashBagProjectile.cs @@ -1,8 +1,10 @@ -using System.Collections; +using System; +using System.Collections; using Core; using Core.Settings; using Input; using UnityEngine; +using Random = UnityEngine.Random; namespace Minigames.FortFight.Projectiles { @@ -23,6 +25,12 @@ namespace Minigames.FortFight.Projectiles private bool inputEnabled = false; private bool hasExploded = false; + /// + /// Fired when trash bag explodes and spawns pieces. + /// Parameters: (Transform trashPieceToFollow) - a piece for camera to follow + /// + public event Action OnTrashPiecesSpawned; + public override void Launch(Vector2 direction, float force) { base.Launch(direction, force); @@ -145,13 +153,14 @@ namespace Minigames.FortFight.Projectiles /// /// Spawn multiple trash pieces in a cone away from the hit surface. /// Uses hit normal + projectile momentum for realistic splash effect. + /// Returns the first spawned trash piece for camera tracking. /// - private void SpawnTrashPieces(Vector2 impactPoint, Vector2 hitNormal) + private Transform SpawnTrashPieces(Vector2 impactPoint, Vector2 hitNormal) { if (trashPiecePrefab == null) { Logging.Warning("[TrashBagProjectile] No trash piece prefab assigned!"); - return; + return null; } // Get settings @@ -175,6 +184,8 @@ namespace Minigames.FortFight.Projectiles // 70% normal (splash away from surface) + 30% reflection (maintain some momentum direction) Vector2 baseDirection = (hitNormal * 0.7f + reflectDirection * 0.3f).normalized; + Transform firstPiece = null; + // Spawn pieces in a cone around the base direction for (int i = 0; i < pieceCount; i++) { @@ -189,6 +200,12 @@ namespace Minigames.FortFight.Projectiles Vector2 spawnOffset = pieceDirection * 0.2f; // Small offset to prevent clipping GameObject piece = Instantiate(trashPiecePrefab, (Vector2)impactPoint + spawnOffset, Quaternion.identity); + // Store first piece for camera tracking + if (i == 0 && piece != null) + { + firstPiece = piece.transform; + } + // Setup trash piece physics Rigidbody2D pieceRb = piece.GetComponent(); if (pieceRb != null) @@ -203,6 +220,14 @@ namespace Minigames.FortFight.Projectiles Logging.Debug($"[TrashBagProjectile] Spawned trash piece {i} in direction {pieceDirection}"); } + + // Fire event with first piece for camera tracking + if (firstPiece != null) + { + OnTrashPiecesSpawned?.Invoke(firstPiece); + } + + return firstPiece; } #region ITouchInputConsumer Implementation