2025-05-18 01:04:31 +08:00

174 lines
5.0 KiB
C#

using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace NotificationSamples.Demo
{
/// <summary>
/// UI list item for buying an inventory item.
/// </summary>
public class BuyInventoryItem : MonoBehaviour
{
[SerializeField]
protected TextMeshProUGUI titleLabel;
[SerializeField]
protected TextMeshProUGUI timeLabel;
[SerializeField]
protected TextMeshProUGUI costLabel;
[SerializeField]
protected Image icon;
[SerializeField]
protected Button buyButton;
[SerializeField]
protected Image progressImage;
// Fired when the buy button is pressed.
private Action<BuyInventoryItem> bought;
// When the last bought item will be delivered.
private DateTime? deliveryTime;
// Initial time remaining for the delivery of the last bought item.
private float initialTimeRemaining;
// The last currency received from the game controller.
private int currency;
/// <summary>
/// Title to show in the notification.
/// </summary>
public string Title => titleLabel.text;
/// <summary>
/// Description to show in the notification.
/// </summary>
public string Description { get; private set; }
/// <summary>
/// Fire notification after this amount of minutes.
/// </summary>
public float Minutes { get; set; }
/// <summary>
/// The item's cost.
/// </summary>
public int Cost { get; set; }
/// <summary>
/// The item data linked to this UI item.
/// </summary>
public InventoryItemData ItemData { get; private set; }
/// <summary>
/// Initialise the item with the specified settings.
/// </summary>
public void Initialise(InventoryItemData itemData, Action<BuyInventoryItem> buyAction)
{
ItemData = itemData;
titleLabel.text = itemData.Title;
Minutes = itemData.InitialCreationTime;
Description = itemData.Description;
Cost = itemData.InitialCost;
icon.sprite = itemData.Icon;
bought = buyAction;
deliveryTime = null;
progressImage.fillAmount = 0.0f;
UpdateControls();
}
/// <summary>
/// Called when the buy button is clicked.
/// </summary>
public void OnBuy()
{
bought?.Invoke(this);
}
/// <summary>
/// Called when buying an item was successful.
/// </summary>
public void OnBuySuccess(DateTime boughtDeliveryTime)
{
deliveryTime = boughtDeliveryTime;
initialTimeRemaining = GetTimeRemaining();
buyButton.interactable = false;
UpdateControls();
}
/// <summary>
/// Update UI controls.
/// </summary>
public void UpdateControls()
{
if (deliveryTime != null)
{
// Do not update the labels (i.e. show the old values until the item is delivered).
return;
}
costLabel.text = Cost.ToString("N0");
timeLabel.text = $"Takes {Minutes:F1} minute(s)";
}
/// <summary>
/// Called when the game's currency total changed.
/// </summary>
public void OnCurrencyChanged(int newCurrency)
{
currency = newCurrency;
UpdateBuyButton();
}
/// <summary>
/// Called when an item was delivered.
/// </summary>
public void OnDeliveredItem(InventoryItemData itemData)
{
if (itemData == ItemData)
{
UpdateBuyButton();
}
}
// Time remaining until the last bought item is delivered.
private float GetTimeRemaining()
{
if (deliveryTime == null)
{
return 0.0f;
}
TimeSpan timeSpan = deliveryTime.Value - DateTime.Now;
return Mathf.Max((float)timeSpan.TotalSeconds, 0.0f);
}
private void Update()
{
UpdateProgress();
}
// Determine if the buy button should be interactable.
private void UpdateBuyButton()
{
buyButton.interactable = currency >= Cost && GetTimeRemaining() <= 0.0f;
}
// Update an item's delivery progress, and update the progress bar.
private void UpdateProgress()
{
if (deliveryTime == null)
{
return;
}
float timeRemaining = GetTimeRemaining();
if (timeRemaining > 0.0f)
{
progressImage.fillAmount = 1.0f - Mathf.Clamp01(timeRemaining / initialTimeRemaining);
return;
}
progressImage.fillAmount = 0.0f;
deliveryTime = null;
UpdateControls();
}
}
}