Fix weapon selection issues and shot tracking

This commit is contained in:
Michal Pikulski
2025-12-16 19:29:01 +01:00
parent bd4c365d98
commit c5f37a5df4
4 changed files with 125 additions and 49 deletions

View File

@@ -220,6 +220,34 @@ namespace Minigames.FortFight.Core
return true; return true;
} }
/// <summary>
/// Select the first available (non-cooldown) ammo for a player.
/// Called at the start of each turn to reset selection.
/// </summary>
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;
}
/// <summary> /// <summary>
/// Get currently selected projectile type for a specific player /// Get currently selected projectile type for a specific player
/// </summary> /// </summary>

View File

@@ -1,5 +1,4 @@
using AppleHills.Core.Settings; using Core;
using Core;
using Core.Settings; using Core.Settings;
using Minigames.FortFight.Data; using Minigames.FortFight.Data;
using Minigames.FortFight.Projectiles; using Minigames.FortFight.Projectiles;
@@ -13,14 +12,14 @@ namespace Minigames.FortFight.Core
/// </summary> /// </summary>
public class ProjectileTurnAction public class ProjectileTurnAction
{ {
private SlingshotController slingshot; private SlingshotController _slingshot;
private AmmunitionManager ammoManager; private AmmunitionManager _ammoManager;
private CameraController cameraController; private CameraController _cameraController;
private int playerIndex; private int _playerIndex;
private ProjectileBase activeProjectile; private ProjectileBase _activeProjectile;
private bool launchComplete = false; private bool _launchComplete = false;
private bool projectileSettled = false; private bool _projectileSettled = false;
private float settleTimer = 0f; private float _settleTimer = 0f;
private IFortFightSettings _cachedSettings; private IFortFightSettings _cachedSettings;
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) public ProjectileTurnAction(SlingshotController slingshot, AmmunitionManager ammoManager, CameraController cameraController, int playerIndex)
{ {
this.slingshot = slingshot; this._slingshot = slingshot;
this.ammoManager = ammoManager; this._ammoManager = ammoManager;
this.cameraController = cameraController; this._cameraController = cameraController;
this.playerIndex = playerIndex; this._playerIndex = playerIndex;
} }
/// <summary> /// <summary>
@@ -53,12 +52,12 @@ namespace Minigames.FortFight.Core
Logging.Debug("[ProjectileTurnAction] Executing - enabling slingshot"); Logging.Debug("[ProjectileTurnAction] Executing - enabling slingshot");
// Enable slingshot // Enable slingshot
if (slingshot != null) if (_slingshot != null)
{ {
slingshot.Enable(); _slingshot.Enable();
// Subscribe to launch event // Subscribe to launch event
slingshot.OnProjectileLaunched += HandleProjectileLaunched; _slingshot.OnProjectileLaunched += HandleProjectileLaunched;
} }
} }
@@ -67,28 +66,28 @@ namespace Minigames.FortFight.Core
/// </summary> /// </summary>
public void Update() public void Update()
{ {
if (!launchComplete) return; if (!_launchComplete) return;
// Check if projectile is destroyed or stopped // Check if projectile is destroyed or stopped
if (activeProjectile == null) if (_activeProjectile == null)
{ {
// Projectile destroyed - start settle timer // Projectile destroyed - start settle timer
if (settleTimer == 0f) if (_settleTimer == 0f)
{ {
Logging.Debug("[ProjectileTurnAction] Projectile destroyed - starting settle timer"); Logging.Debug("[ProjectileTurnAction] Projectile destroyed - starting settle timer");
} }
settleTimer += Time.deltaTime; _settleTimer += Time.deltaTime;
float settleDelay = CachedSettings?.ProjectileSettleDelay ?? 2.5f; float settleDelay = CachedSettings?.ProjectileSettleDelay ?? 2.5f;
if (settleTimer >= settleDelay) if (_settleTimer >= settleDelay)
{ {
projectileSettled = true; _projectileSettled = true;
// Stop camera tracking when projectile settles // Stop camera tracking when projectile settles
if (cameraController != null) if (_cameraController != null)
{ {
cameraController.StopFollowingProjectile(); _cameraController.StopFollowingProjectile();
} }
Logging.Debug("[ProjectileTurnAction] Turn action complete"); Logging.Debug("[ProjectileTurnAction] Turn action complete");
@@ -97,20 +96,20 @@ namespace Minigames.FortFight.Core
else else
{ {
// Check if projectile has stopped moving // Check if projectile has stopped moving
Rigidbody2D rb = activeProjectile.GetComponent<Rigidbody2D>(); Rigidbody2D rb = _activeProjectile.GetComponent<Rigidbody2D>();
if (rb != null && rb.linearVelocity.magnitude < 0.5f) if (rb != null && rb.linearVelocity.magnitude < 0.5f)
{ {
settleTimer += Time.deltaTime; _settleTimer += Time.deltaTime;
float settleDelay = CachedSettings?.ProjectileSettleDelay ?? 2.5f; float settleDelay = CachedSettings?.ProjectileSettleDelay ?? 2.5f;
if (settleTimer >= settleDelay) if (_settleTimer >= settleDelay)
{ {
projectileSettled = true; _projectileSettled = true;
// Stop camera tracking when projectile settles // Stop camera tracking when projectile settles
if (cameraController != null) if (_cameraController != null)
{ {
cameraController.StopFollowingProjectile(); _cameraController.StopFollowingProjectile();
} }
Logging.Debug("[ProjectileTurnAction] Projectile settled - turn action complete"); Logging.Debug("[ProjectileTurnAction] Projectile settled - turn action complete");
@@ -119,7 +118,7 @@ namespace Minigames.FortFight.Core
else else
{ {
// Reset settle timer if still moving // Reset settle timer if still moving
settleTimer = 0f; _settleTimer = 0f;
} }
} }
} }
@@ -129,10 +128,10 @@ namespace Minigames.FortFight.Core
/// </summary> /// </summary>
public void Cancel() public void Cancel()
{ {
if (slingshot != null) if (_slingshot != null)
{ {
slingshot.Disable(); _slingshot.Disable();
slingshot.OnProjectileLaunched -= HandleProjectileLaunched; _slingshot.OnProjectileLaunched -= HandleProjectileLaunched;
} }
} }
@@ -140,26 +139,47 @@ namespace Minigames.FortFight.Core
{ {
Logging.Debug($"[ProjectileTurnAction] Projectile launched: {projectile.gameObject.name}"); Logging.Debug($"[ProjectileTurnAction] Projectile launched: {projectile.gameObject.name}");
launchComplete = true; _launchComplete = true;
activeProjectile = projectile; _activeProjectile = projectile;
// Disable slingshot after launch // Disable slingshot after launch
if (slingshot != null) if (_slingshot != null)
{ {
slingshot.Disable(); _slingshot.Disable();
} }
// Trigger cooldown for used ammo for this player // Trigger cooldown for used ammo for this player
if (ammoManager != null) if (_ammoManager != null)
{ {
ProjectileType usedAmmoType = ammoManager.GetSelectedAmmoType(playerIndex); ProjectileType usedAmmoType = _ammoManager.GetSelectedAmmoType(_playerIndex);
ammoManager.UseAmmo(usedAmmoType, 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 // Start camera tracking the projectile
if (cameraController != null && projectile != null) if (_cameraController != null && projectile != null)
{ {
cameraController.StartFollowingProjectile(projectile.transform); _cameraController.StartFollowingProjectile(projectile.transform);
}
}
/// <summary>
/// Handle trash bag explosion - switch camera to follow a trash piece
/// </summary>
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)
} }
} }
} }

View File

@@ -210,9 +210,12 @@ namespace Minigames.FortFight.Core
// Set slingshot owner (used for projectile ownership tracking) // Set slingshot owner (used for projectile ownership tracking)
activeSlingshot.SetOwner(_currentPlayer.PlayerIndex, _currentPlayer.IsAI); 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) if (AmmunitionManager.Instance != null)
{ {
AmmunitionManager.Instance.SelectFirstAvailableAmmo(_currentPlayer.PlayerIndex);
// Set the selected ammo on slingshot
ProjectileConfig currentAmmo = AmmunitionManager.Instance.GetSelectedAmmoConfig(_currentPlayer.PlayerIndex); ProjectileConfig currentAmmo = AmmunitionManager.Instance.GetSelectedAmmoConfig(_currentPlayer.PlayerIndex);
if (currentAmmo != null) if (currentAmmo != null)
{ {

View File

@@ -1,8 +1,10 @@
using System.Collections; using System;
using System.Collections;
using Core; using Core;
using Core.Settings; using Core.Settings;
using Input; using Input;
using UnityEngine; using UnityEngine;
using Random = UnityEngine.Random;
namespace Minigames.FortFight.Projectiles namespace Minigames.FortFight.Projectiles
{ {
@@ -23,6 +25,12 @@ namespace Minigames.FortFight.Projectiles
private bool inputEnabled = false; private bool inputEnabled = false;
private bool hasExploded = false; private bool hasExploded = false;
/// <summary>
/// Fired when trash bag explodes and spawns pieces.
/// Parameters: (Transform trashPieceToFollow) - a piece for camera to follow
/// </summary>
public event Action<Transform> OnTrashPiecesSpawned;
public override void Launch(Vector2 direction, float force) public override void Launch(Vector2 direction, float force)
{ {
base.Launch(direction, force); base.Launch(direction, force);
@@ -145,13 +153,14 @@ namespace Minigames.FortFight.Projectiles
/// <summary> /// <summary>
/// Spawn multiple trash pieces in a cone away from the hit surface. /// Spawn multiple trash pieces in a cone away from the hit surface.
/// Uses hit normal + projectile momentum for realistic splash effect. /// Uses hit normal + projectile momentum for realistic splash effect.
/// Returns the first spawned trash piece for camera tracking.
/// </summary> /// </summary>
private void SpawnTrashPieces(Vector2 impactPoint, Vector2 hitNormal) private Transform SpawnTrashPieces(Vector2 impactPoint, Vector2 hitNormal)
{ {
if (trashPiecePrefab == null) if (trashPiecePrefab == null)
{ {
Logging.Warning("[TrashBagProjectile] No trash piece prefab assigned!"); Logging.Warning("[TrashBagProjectile] No trash piece prefab assigned!");
return; return null;
} }
// Get settings // Get settings
@@ -175,6 +184,8 @@ namespace Minigames.FortFight.Projectiles
// 70% normal (splash away from surface) + 30% reflection (maintain some momentum direction) // 70% normal (splash away from surface) + 30% reflection (maintain some momentum direction)
Vector2 baseDirection = (hitNormal * 0.7f + reflectDirection * 0.3f).normalized; Vector2 baseDirection = (hitNormal * 0.7f + reflectDirection * 0.3f).normalized;
Transform firstPiece = null;
// Spawn pieces in a cone around the base direction // Spawn pieces in a cone around the base direction
for (int i = 0; i < pieceCount; i++) 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 Vector2 spawnOffset = pieceDirection * 0.2f; // Small offset to prevent clipping
GameObject piece = Instantiate(trashPiecePrefab, (Vector2)impactPoint + spawnOffset, Quaternion.identity); 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 // Setup trash piece physics
Rigidbody2D pieceRb = piece.GetComponent<Rigidbody2D>(); Rigidbody2D pieceRb = piece.GetComponent<Rigidbody2D>();
if (pieceRb != null) if (pieceRb != null)
@@ -203,6 +220,14 @@ namespace Minigames.FortFight.Projectiles
Logging.Debug($"[TrashBagProjectile] Spawned trash piece {i} in direction {pieceDirection}"); 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 #region ITouchInputConsumer Implementation