Files
AppleHillsProduction/Assets/Scripts/Minigames/FortFight/UI/AmmoButton.cs
tschesky e60d516e7e Implement Fort Fight minigame (#75)
Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com>
Reviewed-on: #75
2025-12-04 01:18:29 +00:00

253 lines
8.6 KiB
C#

using Core;
using Core.Lifecycle;
using Minigames.FortFight.Core;
using Minigames.FortFight.Data;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Minigames.FortFight.UI
{
/// <summary>
/// Generic reusable ammunition button that displays projectile data.
/// Shows icon, availability state, cooldown progress, and turns remaining.
/// </summary>
public class AmmoButton : ManagedBehaviour
{
#region Inspector References
[Header("UI Components")]
[Tooltip("Icon image for the projectile")]
[SerializeField] private Image iconImage;
[Tooltip("Background overlay that greys out the entire button when on cooldown")]
[SerializeField] private Image cooldownBackgroundImage;
[Tooltip("Radial fill overlay for cooldown visualization")]
[SerializeField] private Image cooldownFillImage;
[Tooltip("Text displaying turns remaining")]
[SerializeField] private TextMeshProUGUI turnsRemainingText;
[Tooltip("Button component")]
[SerializeField] private Button button;
[Tooltip("Visual indicator for selected state (optional border/glow)")]
[SerializeField] private GameObject selectedIndicator;
#endregion
#region State
private ProjectileConfig projectileConfig;
private AmmunitionManager ammunitionManager;
private SlingshotController slingshotController;
private int playerIndex;
private bool isSelected;
#endregion
#region Initialization
/// <summary>
/// Initialize the button with projectile config and system references.
/// Call this after instantiation to configure the button.
/// </summary>
public void Initialize(ProjectileConfig config, AmmunitionManager ammoManager, SlingshotController slingshot, int playerIdx)
{
projectileConfig = config;
ammunitionManager = ammoManager;
slingshotController = slingshot;
playerIndex = playerIdx;
// Setup UI from projectile config
if (iconImage != null && config.icon != null)
{
iconImage.sprite = config.icon;
}
// Setup cooldown background (hidden by default)
if (cooldownBackgroundImage != null)
{
cooldownBackgroundImage.gameObject.SetActive(false);
}
// Setup cooldown fill (hidden by default)
if (cooldownFillImage != null)
{
cooldownFillImage.fillAmount = 0f;
cooldownFillImage.type = Image.Type.Filled;
cooldownFillImage.fillMethod = Image.FillMethod.Radial360;
cooldownFillImage.fillOrigin = (int)Image.Origin360.Top;
cooldownFillImage.gameObject.SetActive(false);
}
// Setup turns text (hidden by default)
if (turnsRemainingText != null)
{
turnsRemainingText.gameObject.SetActive(false);
}
// Setup button
if (button != null)
{
button.onClick.AddListener(OnButtonClicked);
}
// Subscribe to ammunition events
if (ammunitionManager != null)
{
ammunitionManager.OnAmmoSelected += HandleAmmoSelected;
ammunitionManager.OnAmmoCooldownStarted += HandleCooldownStarted;
ammunitionManager.OnAmmoCooldownCompleted += HandleCooldownCompleted;
}
// Initial update
UpdateVisuals();
}
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Unsubscribe from events
if (ammunitionManager != null)
{
ammunitionManager.OnAmmoSelected -= HandleAmmoSelected;
ammunitionManager.OnAmmoCooldownStarted -= HandleCooldownStarted;
ammunitionManager.OnAmmoCooldownCompleted -= HandleCooldownCompleted;
}
// Remove button listener
if (button != null)
{
button.onClick.RemoveListener(OnButtonClicked);
}
}
#endregion
#region Update
private void Update()
{
// Update visuals every frame
UpdateVisuals();
}
/// <summary>
/// Update all visual elements based on current state
/// </summary>
private void UpdateVisuals()
{
if (projectileConfig == null || ammunitionManager == null) return;
// Get current cooldown state for this player
int turnsRemaining = ammunitionManager.GetCooldownRemaining(projectileConfig.projectileType, playerIndex);
bool isAvailable = ammunitionManager.IsAmmoAvailable(projectileConfig.projectileType, playerIndex);
bool onCooldown = turnsRemaining > 0;
// Show/hide cooldown background overlay
if (cooldownBackgroundImage != null)
{
cooldownBackgroundImage.gameObject.SetActive(onCooldown);
}
// Update cooldown fill (0 = no fill, 1 = full fill)
if (cooldownFillImage != null)
{
if (onCooldown && projectileConfig.cooldownTurns > 0)
{
float fillAmount = (float)turnsRemaining / projectileConfig.cooldownTurns;
cooldownFillImage.fillAmount = fillAmount;
cooldownFillImage.gameObject.SetActive(true);
}
else
{
cooldownFillImage.gameObject.SetActive(false);
}
}
// Update turns remaining text
if (turnsRemainingText != null)
{
if (onCooldown)
{
turnsRemainingText.text = turnsRemaining.ToString();
turnsRemainingText.gameObject.SetActive(true);
}
else
{
turnsRemainingText.gameObject.SetActive(false);
}
}
// Update button interactability
if (button != null)
{
button.interactable = isAvailable;
}
// Update selected indicator
if (selectedIndicator != null)
{
selectedIndicator.SetActive(isSelected);
}
}
#endregion
#region Button Click
/// <summary>
/// Called when button is clicked - selects this ammo type
/// </summary>
private void OnButtonClicked()
{
if (projectileConfig == null || ammunitionManager == null) return;
// Try to select this ammo type for this player
bool selected = ammunitionManager.SelectAmmo(projectileConfig.projectileType, playerIndex);
if (selected && slingshotController != null)
{
// Update slingshot with new ammo config
slingshotController.SetAmmo(projectileConfig);
Logging.Debug($"[AmmoButton] Player {playerIndex} selected {projectileConfig.displayName}");
}
}
#endregion
#region Event Handlers
private void HandleAmmoSelected(ProjectileType selectedType, int selectedPlayerIndex)
{
// Only update if this event is for our player
if (selectedPlayerIndex != playerIndex)
return;
// Update selected state - check if this is our player's current selection
isSelected = (selectedType == projectileConfig.projectileType);
}
private void HandleCooldownStarted(ProjectileType type, int cooldownTurns)
{
// Visual update handled in UpdateVisuals()
}
private void HandleCooldownCompleted(ProjectileType type)
{
// Visual update handled in UpdateVisuals()
if (type == projectileConfig.projectileType)
{
Logging.Debug($"[AmmoButton] {projectileConfig.displayName} ready!");
}
}
#endregion
}
}