You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
318 lines
8.7 KiB
C#
318 lines
8.7 KiB
C#
2 months ago
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Purchasing;
|
||
|
using TMPro;
|
||
|
using UnityEngine.UI;
|
||
|
using DG.Tweening;
|
||
|
using UnityEngine.Purchasing.Extension;
|
||
|
|
||
|
[Serializable]
|
||
|
public class ConsumableItem
|
||
|
{
|
||
|
public string Name;
|
||
|
public string Id;
|
||
|
public string desc;
|
||
|
public float price;
|
||
|
}
|
||
|
|
||
|
[Serializable]
|
||
|
public class CarItem
|
||
|
{
|
||
|
public int carId;
|
||
|
public int price;
|
||
|
public CarData carData;
|
||
|
public Button carButton; // CarTile main selection
|
||
|
public Image backgroundImage;
|
||
|
public GameObject lockIcon;
|
||
|
public GameObject selectedHighlight;
|
||
|
public Button priceButton; // Button shown on locked cars
|
||
|
public TextMeshProUGUI priceText; // Text inside price button
|
||
|
}
|
||
|
|
||
|
|
||
|
public class ShopManager : MonoBehaviour, IDetailedStoreListener
|
||
|
{
|
||
|
IStoreController m_StoreController;
|
||
|
|
||
|
[Header("Consumables")]
|
||
|
public List<ConsumableItem> cItem;
|
||
|
public List<int> CashRewards;
|
||
|
public GameObject LoadingScreen;
|
||
|
public TextMeshProUGUI CashTxt;
|
||
|
|
||
|
[Header("Car Store")]
|
||
|
public List<CarItem> carItems;
|
||
|
public Sprite selectedSprite;
|
||
|
public Sprite unselectedSprite;
|
||
|
|
||
|
[Header("Car Info UI")]
|
||
|
public TextMeshProUGUI carNameText;
|
||
|
public List<Button> colorButtons;
|
||
|
public Image[] colorIndicators;
|
||
|
public TextMeshProUGUI nitroText;
|
||
|
public TextMeshProUGUI powerText;
|
||
|
public TextMeshProUGUI handlingText;
|
||
|
public TextMeshProUGUI tractionText;
|
||
|
[Header("Car Stat Bars")]
|
||
|
public Image nitroBar;
|
||
|
public Image powerBar;
|
||
|
public Image handlingBar;
|
||
|
public Image tractionBar;
|
||
|
|
||
|
void Start()
|
||
|
{
|
||
|
CashTxt.text = GameConstants.Cash.ToString();
|
||
|
SetupBuilder();
|
||
|
InitializeCarStore();
|
||
|
}
|
||
|
|
||
|
#region Unity IAP Setup
|
||
|
|
||
|
void SetupBuilder()
|
||
|
{
|
||
|
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
|
||
|
|
||
|
for (int i = 0; i < cItem.Count; i++)
|
||
|
{
|
||
|
builder.AddProduct(cItem[i].Id, ProductType.Consumable);
|
||
|
}
|
||
|
|
||
|
UnityPurchasing.Initialize(this, builder);
|
||
|
}
|
||
|
|
||
|
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
|
||
|
{
|
||
|
m_StoreController = controller;
|
||
|
Debug.Log("Unity IAP Initialized");
|
||
|
}
|
||
|
|
||
|
public void OnInitializeFailed(InitializationFailureReason error)
|
||
|
{
|
||
|
LoadingScreen.SetActive(false);
|
||
|
Debug.LogError("IAP Initialization Failed: " + error);
|
||
|
}
|
||
|
|
||
|
public void OnInitializeFailed(InitializationFailureReason error, string message)
|
||
|
{
|
||
|
LoadingScreen.SetActive(false);
|
||
|
Debug.LogError("IAP Initialization Failed: " + error + ", Message: " + message);
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Purchase Flow
|
||
|
|
||
|
public void BuyCashItem(int index)
|
||
|
{
|
||
|
if (index < cItem.Count)
|
||
|
{
|
||
|
LoadingScreen.SetActive(true);
|
||
|
m_StoreController.InitiatePurchase(cItem[index].Id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
|
||
|
{
|
||
|
LoadingScreen.SetActive(false);
|
||
|
var productId = args.purchasedProduct.definition.id;
|
||
|
|
||
|
for (int i = 0; i < cItem.Count; i++)
|
||
|
{
|
||
|
if (productId == cItem[i].Id)
|
||
|
{
|
||
|
AddCash(i);
|
||
|
Debug.Log("Cash Item Purchased: " + cItem[i].Name);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return PurchaseProcessingResult.Complete;
|
||
|
}
|
||
|
|
||
|
public void OnPurchaseFailed(Product product, PurchaseFailureReason reason)
|
||
|
{
|
||
|
LoadingScreen.SetActive(false);
|
||
|
Debug.LogWarning("Purchase Failed: " + product.definition.id + ", Reason: " + reason);
|
||
|
}
|
||
|
|
||
|
public void OnPurchaseFailed(Product product, PurchaseFailureDescription description)
|
||
|
{
|
||
|
LoadingScreen.SetActive(false);
|
||
|
Debug.LogWarning("Purchase Failed: " + description.message);
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Cash Logic
|
||
|
|
||
|
void AddCash(int index)
|
||
|
{
|
||
|
int amount = CashRewards[index];
|
||
|
int currentCash = GameConstants.Cash;
|
||
|
int newCash = currentCash + amount;
|
||
|
|
||
|
GameConstants.Cash = newCash;
|
||
|
StartCoroutine(AnimateCashChange(currentCash, newCash, 0.5f));
|
||
|
}
|
||
|
|
||
|
void SubtractCash(int amount)
|
||
|
{
|
||
|
int cash = GameConstants.Cash;
|
||
|
int newCash = cash - amount;
|
||
|
GameConstants.Cash = newCash;
|
||
|
StartCoroutine(AnimateCashChange(cash, newCash, 0.5f));
|
||
|
}
|
||
|
|
||
|
float val;
|
||
|
IEnumerator AnimateCashChange(int oldValue, int newValue, float duration)
|
||
|
{
|
||
|
float elapsed = 0f;
|
||
|
CashTxt.transform.DOShakePosition(0.5f);
|
||
|
|
||
|
while (elapsed < duration)
|
||
|
{
|
||
|
elapsed += Time.deltaTime;
|
||
|
float t = elapsed / duration;
|
||
|
val = Mathf.Lerp(oldValue, newValue, t);
|
||
|
CashTxt.text = ((int)(val)).ToString();
|
||
|
yield return null;
|
||
|
}
|
||
|
CashTxt.text = newValue.ToString();
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Car Store Logic
|
||
|
|
||
|
void InitializeCarStore()
|
||
|
{
|
||
|
int selectedIndex = GameConstants.CarSelected;
|
||
|
|
||
|
for (int i = 0; i < carItems.Count; i++)
|
||
|
{
|
||
|
int index = i;
|
||
|
CarItem item = carItems[i];
|
||
|
|
||
|
bool isUnlocked = GameConstants.IsCarUnlocked(index);
|
||
|
bool isSelected = (index == selectedIndex);
|
||
|
|
||
|
// Main car tile button (selects car if unlocked)
|
||
|
item.carButton.onClick.RemoveAllListeners();
|
||
|
item.carButton.onClick.AddListener(() => OnCarClicked(index));
|
||
|
|
||
|
// Price button (shown only if car is locked)
|
||
|
item.priceButton.gameObject.SetActive(!isUnlocked);
|
||
|
item.priceButton.onClick.RemoveAllListeners();
|
||
|
item.priceButton.onClick.AddListener(() => TryBuyCar(index));
|
||
|
item.priceText.text = item.price.ToString();
|
||
|
|
||
|
// Lock icon
|
||
|
item.lockIcon.SetActive(!isUnlocked);
|
||
|
|
||
|
// Selected highlight
|
||
|
item.selectedHighlight.SetActive(isSelected);
|
||
|
|
||
|
// Background sprite
|
||
|
item.backgroundImage.sprite = isSelected ? selectedSprite : unselectedSprite;
|
||
|
}
|
||
|
|
||
|
UpdateCarInfo(selectedIndex);
|
||
|
}
|
||
|
|
||
|
void OnCarClicked(int index)
|
||
|
{
|
||
|
bool isUnlocked = GameConstants.IsCarUnlocked(index);
|
||
|
int selected = GameConstants.CarSelected;
|
||
|
|
||
|
// Ignore if already selected
|
||
|
if (index == selected)
|
||
|
return;
|
||
|
|
||
|
// Only allow selecting unlocked cars
|
||
|
if (isUnlocked)
|
||
|
{
|
||
|
SelectCar(index);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.Log("Car is locked. Click the price button to buy.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SelectCar(int index)
|
||
|
{
|
||
|
for (int i = 0; i < carItems.Count; i++)
|
||
|
{
|
||
|
bool isUnlocked = GameConstants.IsCarUnlocked(i);
|
||
|
bool isSelected = (i == index);
|
||
|
|
||
|
carItems[i].selectedHighlight.SetActive(isSelected);
|
||
|
carItems[i].backgroundImage.sprite = isSelected ? selectedSprite : unselectedSprite;
|
||
|
}
|
||
|
|
||
|
GameConstants.CarSelected = index;
|
||
|
UpdateCarInfo(index);
|
||
|
}
|
||
|
|
||
|
void UpdateCarInfo(int index)
|
||
|
{
|
||
|
CarData data = carItems[index].carData;
|
||
|
if (data == null)
|
||
|
{
|
||
|
Debug.LogWarning("Missing CarData for car index: " + index);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
carNameText.text = data.carName;
|
||
|
nitroText.text = data.nitro.ToString("0.00");
|
||
|
powerText.text = data.power.ToString();
|
||
|
handlingText.text = data.handling.ToString();
|
||
|
tractionText.text = data.traction.ToString("0.00");
|
||
|
|
||
|
// Update fill amounts using normalized values
|
||
|
nitroBar.fillAmount = Mathf.InverseLerp(0.1f, 2f, data.nitro);
|
||
|
powerBar.fillAmount = Mathf.InverseLerp(500f, 2000f, data.power);
|
||
|
handlingBar.fillAmount = Mathf.InverseLerp(3f, 10f, data.handling);
|
||
|
tractionBar.fillAmount = Mathf.InverseLerp(3f, 10f, data.traction);
|
||
|
|
||
|
HighlightSelectedColor(GameConstants.CarColorIndex);
|
||
|
}
|
||
|
|
||
|
void TryBuyCar(int index)
|
||
|
{
|
||
|
int cash = GameConstants.Cash;
|
||
|
int price = carItems[index].price;
|
||
|
|
||
|
if (cash >= price)
|
||
|
{
|
||
|
SubtractCash(price);
|
||
|
GameConstants.UnlockCar(index);
|
||
|
SelectCar(index);
|
||
|
InitializeCarStore(); // Refresh visuals
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.Log("Not enough cash to buy car.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void OnColorSelected(int colorIndex)
|
||
|
{
|
||
|
GameConstants.CarColorIndex = colorIndex;
|
||
|
HighlightSelectedColor(colorIndex);
|
||
|
Debug.Log("Color selected: " + colorIndex);
|
||
|
}
|
||
|
|
||
|
void HighlightSelectedColor(int colorIndex)
|
||
|
{
|
||
|
for (int i = 0; i < colorIndicators.Length; i++)
|
||
|
{
|
||
|
colorIndicators[i].enabled = (i == colorIndex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
}
|