This commit is contained in:
Ali Sharoz 2025-10-18 03:26:16 +05:00
parent c15e5ce868
commit 7ed85b882f
17 changed files with 11832 additions and 278 deletions

154
Assets/GameShop.cs Normal file
View File

@ -0,0 +1,154 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System;
using System.Collections;
using System.Collections.Generic;
using TPSBR;
public class GameShop : MonoBehaviour
{
[Serializable]
public class ShopItem
{
public Button buyButton;
public TMP_Text buyLabel;
public TMP_Text nameLabel;
public Image iconImage;
public string id;
public int price;
}
public AgentSettings agentSettings;
public string shopKey = "Characters";
public List<ShopItem> items = new();
public event Action<string> OnPurchaseSuccess;
public event Action<string> OnPurchaseFail;
string WalletAddress => PlayerPrefs.GetString("WALLET_ADDRESS", "");
void Start()
{
ApplyCatalogIfPresent();
EnsureFirstUnlocked();
RefreshUI();
}
void ApplyCatalogIfPresent()
{
if (agentSettings == null || agentSettings.Agents == null || agentSettings.Agents.Length == 0)
{
for (int i = 0; i < items.Count; i++)
if (string.IsNullOrWhiteSpace(items[i].id)) items[i].id = $"Item{i + 1}";
return;
}
int count = Mathf.Min(items.Count, agentSettings.Agents.Length);
for (int i = 0; i < count; i++)
{
var a = agentSettings.Agents[i];
var slot = items[i];
slot.id = a.ID;
slot.price = a.Price;
if (slot.nameLabel) slot.nameLabel.text = string.IsNullOrEmpty(a.DisplayName) ? a.ID : a.DisplayName;
if (slot.iconImage) slot.iconImage.sprite = a.Icon;
}
for (int i = count; i < items.Count; i++)
if (string.IsNullOrWhiteSpace(items[i].id)) items[i].id = $"Item{i + 1}";
}
void EnsureFirstUnlocked()
{
if (items.Count == 0) return;
var id = string.IsNullOrWhiteSpace(items[0].id) ? "Item1" : items[0].id;
ShopUnlocks.EnsureUnlocked(id, shopKey);
}
public void TryBuy(string id)
{
int idx = items.FindIndex(s => s.id == id);
if (idx < 0) return;
if (ShopUnlocks.IsUnlocked(id, shopKey)) return;
//if (string.IsNullOrEmpty(WalletAddress))
//{
// OnPurchaseFail?.Invoke(id);
// return;
//}
StartCoroutine(SimPurchase(idx));
}
long currentPrice;
public async void GetCurrency()
{
try
{
var rec = await GameDb.GetCurrencyAsync(PlayerPrefs.GetString("WALLET_ADDRESS"));
currentPrice = rec;
Debug.Log(rec.ToString());
}
catch (System.Exception e)
{
Debug.LogError($"[Runtime] ❌ Ensure failed: {e.Message}");
}
}
IEnumerator SimPurchase(int idx)
{
yield return new WaitForSeconds(0.6f);
var id = items[idx].id;
bool ok = true;
Debug.Log("CurrentPrice: " + currentPrice);
if (items[idx].price > currentPrice)
{
ok = false;
}
if (ok)
{
ShopUnlocks.Unlock(id, shopKey);
RefreshUI();
OnPurchaseSuccess?.Invoke(id);
}
else
{
OnPurchaseFail?.Invoke(id);
}
}
void RefreshUI()
{
for (int i = 0; i < items.Count; i++)
{
var slot = items[i];
bool owned = !string.IsNullOrWhiteSpace(slot.id) && ShopUnlocks.IsUnlocked(slot.id, shopKey);
if (slot.buyButton)
{
if (i == 0)
{
slot.buyButton.gameObject.SetActive(false);
}
else
{
slot.buyButton.onClick.RemoveAllListeners();
slot.buyButton.gameObject.SetActive(!owned);
if (!owned)
{
var label = slot.buyLabel ? slot.buyLabel : slot.buyButton.GetComponentInChildren<TMP_Text>(true);
if (label) label.text = $"BUY {slot.price}";
string captured = slot.id;
slot.buyButton.onClick.AddListener(() => TryBuy(captured));
}
}
}
//if (slot.lockIcon) slot.lockIcon.SetActive(!owned);
}
}
[ContextMenu("Reset Unlocks")]
void ResetUnlocks()
{
ShopUnlocks.Reset(shopKey);
EnsureFirstUnlocked();
RefreshUI();
}
}

2
Assets/GameShop.cs.meta Normal file
View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1b835a5fa377df241b3fbd1bafa29e3f

View File

@ -0,0 +1,109 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d671857a3d898af44a6648a7fb09ec93, type: 3}
m_Name: AgentSettings
m_EditorClassIdentifier:
_agents:
- _id: Agent.Murica
_displayName: Agent Murica
_description: Nobody knows where Soldier 66 came from. There are rumors that
he was a high profile hitman before undergoing a series of experimental operations
to become half human and half machine. He is famous for not following any sort
of rules which makes him particularly dangerous... thing.
_icon: {fileID: 21300000, guid: de96ec25bc0cde44da577c80ea1f82ba, type: 3}
_agentPrefab:
RawGuidValue: 25bcc93b9af98714db0c016d73cdf473
_menuAgentPrefab: {fileID: 2529299778790674133, guid: c9914cf34da803d49b5e31f50065d2a8, type: 3}
<<<<<<< Updated upstream
=======
_price: 0
>>>>>>> Stashed changes
- _id: Agent.Chill
_displayName: Chill Guy 69
_description: Nobody knows where Soldier 66 came from. There are rumors that
he was a high profile hitman before undergoing a series of experimental operations
to become half human and half machine. He is famous for not following any sort
of rules which makes him particularly dangerous... thing.
_icon: {fileID: 21300000, guid: 7db05483dc3839c4883ca3e2b66df14d, type: 3}
_agentPrefab:
RawGuidValue: 93ce630958493824d9666ef32598805a
_menuAgentPrefab: {fileID: 2529299778790674133, guid: 4d7cd885811c2de41929ce728130362a, type: 3}
<<<<<<< Updated upstream
=======
_price: 0
>>>>>>> Stashed changes
- _id: Agent.Giga
_displayName: Agent Giga
_description: Nobody knows where Soldier 66 came from. There are rumors that
he was a high profile hitman before undergoing a series of experimental operations
to become half human and half machine. He is famous for not following any sort
of rules which makes him particularly dangerous... thing.
_icon: {fileID: 21300000, guid: 928a858e2d7bc4240ab755a303f80754, type: 3}
_agentPrefab:
RawGuidValue: f5e09845b4019b54c8e01d74fb2a0aad
_menuAgentPrefab: {fileID: 2529299778790674133, guid: 8aa7b8ab6c55f8c4daf5cd89dbd56ed6, type: 3}
_price: 0
- _id: Agent.Ibiza
_displayName: Agent Ibiza
_description: Nobody knows where Soldier 66 came from. There are rumors that
he was a high profile hitman before undergoing a series of experimental operations
to become half human and half machine. He is famous for not following any sort
of rules which makes him particularly dangerous... thing.
_icon: {fileID: 21300000, guid: e220f8fe51b977a44b56b8d591031523, type: 3}
_agentPrefab:
RawGuidValue: 8921d406664cf914cb61b178d44a29f6
_menuAgentPrefab: {fileID: 2529299778790674133, guid: b314a16b062b9e344bb98658202d47ea, type: 3}
_price: 0
- _id: Agent.Pengu
_displayName: 'The Pengu '
_description: Nobody knows where Soldier 66 came from. There are rumors that
he was a high profile hitman before undergoing a series of experimental operations
to become half human and half machine. He is famous for not following any sort
of rules which makes him particularly dangerous... thing.
_icon: {fileID: 21300000, guid: b586dceca1f89ae48b7b20796e2a7efe, type: 3}
_agentPrefab:
RawGuidValue: 968b88cacf761be438f090ab6c312eeb
_menuAgentPrefab: {fileID: 2529299778790674133, guid: f798ef3c64f2c0947ac23690465302d1, type: 3}
_price: 0
- _id: Agent.Shiba
_displayName: Agent.Shiba 69
_description: Nobody knows where Soldier 66 came from. There are rumors that
he was a high profile hitman before undergoing a series of experimental operations
to become half human and half machine. He is famous for not following any sort
of rules which makes him particularly dangerous... thing.
_icon: {fileID: 21300000, guid: 9c635e9c55e3d9e409cec904852cc362, type: 3}
_agentPrefab:
RawGuidValue: bc5d02ffcf614c642a5423f0330ab4e7
_menuAgentPrefab: {fileID: 2529299778790674133, guid: 70258e6ed9efedf45b2d169ecfee5be7, type: 3}
_price: 0
- _id: Agent.UFD
_displayName: Agent UFD
_description: Nobody knows where Soldier 66 came from. There are rumors that
he was a high profile hitman before undergoing a series of experimental operations
to become half human and half machine. He is famous for not following any sort
of rules which makes him particularly dangerous... thing.
_icon: {fileID: 21300000, guid: ee947c4b89d84c644ad4523d07e9182a, type: 3}
_agentPrefab:
RawGuidValue: 926a6549963ce944cad146ee2ff1b35b
_menuAgentPrefab: {fileID: 2529299778790674133, guid: be89f8a6c7f67974b9059935e9777637, type: 3}
_price: 0
- _id: Agent.Labubu
_displayName: Agent.Shiba 69
_description: Nobody knows where Soldier 66 came from. There are rumors that
he was a high profile hitman before undergoing a series of experimental operations
to become half human and half machine. He is famous for not following any sort
of rules which makes him particularly dangerous... thing.
_icon: {fileID: 21300000, guid: 1ba05e07e079e2a449992e3a311da9ea, type: 3}
_agentPrefab:
RawGuidValue: 7fca5f30246801846aae5cc6618d32d6
_menuAgentPrefab: {fileID: 2529299778790674133, guid: 29b91992f24646a478fe434046a51132, type: 3}
_price: 0

View File

@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: bc0d3b3598b234945b6595818b535e11
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 226753
packageName: BR200 - Battle Royale Multiplayer - Photon Fusion
packageVersion: 2.0.2
assetPath: Assets/TPSBR/Resources/Settings/AgentSettings.asset
uploadId: 718661

View File

@ -23,6 +23,7 @@ MonoBehaviour:
_agentPrefab:
RawGuidValue: 25bcc93b9af98714db0c016d73cdf473
_menuAgentPrefab: {fileID: 2529299778790674133, guid: c9914cf34da803d49b5e31f50065d2a8, type: 3}
_price: 0
- _id: Agent.Chill
_displayName: Chill Guy 69
_description: Nobody knows where Soldier 66 came from. There are rumors that
@ -33,6 +34,7 @@ MonoBehaviour:
_agentPrefab:
RawGuidValue: 93ce630958493824d9666ef32598805a
_menuAgentPrefab: {fileID: 2529299778790674133, guid: 4d7cd885811c2de41929ce728130362a, type: 3}
_price: 0
- _id: Agent.Giga
_displayName: Agent Giga
_description: Nobody knows where Soldier 66 came from. There are rumors that
@ -43,6 +45,7 @@ MonoBehaviour:
_agentPrefab:
RawGuidValue: f5e09845b4019b54c8e01d74fb2a0aad
_menuAgentPrefab: {fileID: 2529299778790674133, guid: 8aa7b8ab6c55f8c4daf5cd89dbd56ed6, type: 3}
_price: 0
- _id: Agent.Ibiza
_displayName: Agent Ibiza
_description: Nobody knows where Soldier 66 came from. There are rumors that
@ -53,6 +56,7 @@ MonoBehaviour:
_agentPrefab:
RawGuidValue: 8921d406664cf914cb61b178d44a29f6
_menuAgentPrefab: {fileID: 2529299778790674133, guid: b314a16b062b9e344bb98658202d47ea, type: 3}
_price: 0
- _id: Agent.Pengu
_displayName: 'The Pengu '
_description: Nobody knows where Soldier 66 came from. There are rumors that
@ -63,6 +67,7 @@ MonoBehaviour:
_agentPrefab:
RawGuidValue: 968b88cacf761be438f090ab6c312eeb
_menuAgentPrefab: {fileID: 2529299778790674133, guid: f798ef3c64f2c0947ac23690465302d1, type: 3}
_price: 0
- _id: Agent.Shiba
_displayName: Agent.Shiba 69
_description: Nobody knows where Soldier 66 came from. There are rumors that
@ -73,6 +78,7 @@ MonoBehaviour:
_agentPrefab:
RawGuidValue: bc5d02ffcf614c642a5423f0330ab4e7
_menuAgentPrefab: {fileID: 2529299778790674133, guid: 70258e6ed9efedf45b2d169ecfee5be7, type: 3}
_price: 0
- _id: Agent.UFD
_displayName: Agent UFD
_description: Nobody knows where Soldier 66 came from. There are rumors that
@ -83,6 +89,7 @@ MonoBehaviour:
_agentPrefab:
RawGuidValue: 926a6549963ce944cad146ee2ff1b35b
_menuAgentPrefab: {fileID: 2529299778790674133, guid: be89f8a6c7f67974b9059935e9777637, type: 3}
_price: 0
- _id: Agent.Labubu
_displayName: Agent.Shiba 69
_description: Nobody knows where Soldier 66 came from. There are rumors that
@ -93,3 +100,4 @@ MonoBehaviour:
_agentPrefab:
RawGuidValue: 7fca5f30246801846aae5cc6618d32d6
_menuAgentPrefab: {fileID: 2529299778790674133, guid: 29b91992f24646a478fe434046a51132, type: 3}
_price: 0

View File

@ -28,24 +28,23 @@ MonoBehaviour:
m_EditorClassIdentifier:
debugShaders:
debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3}
hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3}
probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3}
probeVolumeResources:
probeVolumeDebugShader: {fileID: 0}
probeVolumeFragmentationDebugShader: {fileID: 0}
probeVolumeOffsetDebugShader: {fileID: 0}
probeVolumeSamplingDebugShader: {fileID: 0}
probeSamplingDebugMesh: {fileID: 0}
probeSamplingDebugTexture: {fileID: 0}
probeVolumeBlendStatesCS: {fileID: 0}
m_RendererFeatures:
- {fileID: -1559360831169181237}
m_RendererFeatureMap: cbc980fd95095cea
m_UseNativeRenderPass: 0
xrSystemData: {fileID: 0}
postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
shaders:
blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3}
copyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3}
screenSpaceShadowPS: {fileID: 4800000, guid: 0f854b35a0cf61a429bd5dcfea30eddd, type: 3}
samplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3}
stencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3}
fallbackErrorPS: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3}
materialErrorPS: {fileID: 4800000, guid: 5fd9a8feb75a4b5894c241777f519d4e, type: 3}
coreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3}
coreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3}
cameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3}
objectMotionVector: {fileID: 4800000, guid: 7b3ede40266cd49a395def176e1bc486, type: 3}
m_AssetVersion: 1
m_AssetVersion: 2
m_OpaqueLayerMask:
serializedVersion: 2
m_Bits: 4294967295
@ -62,7 +61,8 @@ MonoBehaviour:
m_ShadowTransparentReceive: 0
m_RenderingMode: 0
m_DepthPrimingMode: 0
m_CopyDepthMode: 0
m_DepthAttachmentFormat: 0
m_DepthTextureFormat: 0
m_AccurateGbufferNormals: 0
m_ClusteredRendering: 0
m_TileSize: 32
m_IntermediateTextureMode: 1

File diff suppressed because it is too large Load Diff

View File

@ -67,5 +67,8 @@ namespace TPSBR
private NetworkPrefabRef _agentPrefab;
[SerializeField]
private GameObject _menuAgentPrefab;
}
[SerializeField]
private int _price = 0;
public int Price => _price;
}
}

View File

@ -4,111 +4,76 @@ using UnityEngine.UI;
namespace TPSBR.UI
{
public sealed class UIListItem : UIListItemBase<MonoBehaviour>
{
}
public sealed class UIListItem : UIListItemBase<MonoBehaviour> { }
public abstract class UIListItemBase<T> : UIBehaviour where T : MonoBehaviour
{
// PUBLIC MEMBERS
public abstract class UIListItemBase<T> : UIBehaviour where T : MonoBehaviour
{
public int ID { get; set; }
public T Content => _content;
public bool IsSelectable => _button != null;
public bool IsSelected { get { return _isSelected; } set { SetIsSelected(value); } }
public bool IsInteractable { get { return GetIsInteractable(); } set { SetIsInteractable(value); } }
public Action<int> Clicked;
public int ID { get; set; }
public T Content => _content;
public bool IsSelectable => _button != null;
public bool IsSelected { get { return _isSelected; } set { SetIsSelected(value); } }
public bool IsInteractable { get { return GetIsInteractable(); } set { SetIsInteractable(value); } }
[SerializeField] private Button _button;
[SerializeField] private Animator _animator;
[SerializeField] private T _content;
[SerializeField] private string _selectedAnimatorParameter = "IsSelected";
[SerializeField] private CanvasGroup _selectedGroup;
[SerializeField] private CanvasGroup _deselectedGroup;
[SerializeField] private GameObject _lockGO; // <— assign your LockOverlay here
public Action<int> Clicked;
private bool _isSelected;
// PRIVATE MEMBERS
protected virtual void Awake()
{
SetIsSelected(false, true);
if (_button != null) _button.onClick.AddListener(OnClick);
if (_button != null && _button.transition == Selectable.Transition.Animation) _animator = _button.animator;
}
[SerializeField]
private Button _button;
[SerializeField]
private Animator _animator;
[SerializeField]
private T _content;
[SerializeField]
private string _selectedAnimatorParameter = "IsSelected";
[SerializeField]
private CanvasGroup _selectedGroup;
[SerializeField]
private CanvasGroup _deselectedGroup;
protected virtual void OnDestroy()
{
Clicked = null;
if (_button != null) _button.onClick.RemoveListener(OnClick);
}
private bool _isSelected;
public void SetLocked(bool locked)
{
IsInteractable = !locked; // locked => not interactable
if (_lockGO) _lockGO.SetActive(locked); // show lock when NOT bought
}
// MONOBEHAVIOR
private void SetIsSelected(bool value, bool force = false)
{
if (_isSelected == value && force == false) return;
_isSelected = value;
_selectedGroup.SetVisibility(value);
_deselectedGroup.SetVisibility(value == false);
UpdateAnimator();
}
protected virtual void Awake()
{
SetIsSelected(false, true);
private bool GetIsInteractable()
{
return _button != null ? _button.interactable : false;
}
if (_button != null)
{
_button.onClick.AddListener(OnClick);
}
private void SetIsInteractable(bool value)
{
if (_button == null) return;
_button.interactable = value;
}
if (_button != null && _button.transition == Selectable.Transition.Animation)
{
_animator = _button.animator;
}
}
private void OnClick()
{
Clicked?.Invoke(ID);
}
protected virtual void OnDestroy()
{
Clicked = null;
if (_button != null)
{
_button.onClick.RemoveListener(OnClick);
}
}
// PRIVATE METHODS
private void SetIsSelected(bool value, bool force = false)
{
if (_isSelected == value && force == false)
return;
_isSelected = value;
_selectedGroup.SetVisibility(value);
_deselectedGroup.SetVisibility(value == false);
UpdateAnimator();
}
private bool GetIsInteractable()
{
return _button != null ? _button.interactable : false;
}
private void SetIsInteractable(bool value)
{
if (_button == null)
return;
_button.interactable = value;
}
private void OnClick()
{
Clicked?.Invoke(ID);
}
private void UpdateAnimator()
{
if (_animator == null)
return;
if (_selectedAnimatorParameter.HasValue() == false)
return;
if (_animator != null)
{
_animator.SetBool(_selectedAnimatorParameter, _isSelected);
}
}
}
private void UpdateAnimator()
{
if (_animator == null) return;
if (_selectedAnimatorParameter.HasValue() == false) return;
_animator.SetBool(_selectedAnimatorParameter, _isSelected);
}
}
}

View File

@ -2,146 +2,274 @@ using System;
using TMPro;
using UnityEngine;
using Cinemachine;
using System.Collections;
namespace TPSBR.UI
{
public class UIAgentSelectionView : UICloseView
{
// PRIVATE MEMBERS
public class UIAgentSelectionView : UICloseView
{
[SerializeField] private CinemachineVirtualCamera _camera;
[SerializeField] private UIList _agentList;
[SerializeField] private UIButton _selectButton;
[SerializeField] private TextMeshProUGUI _agentName;
[SerializeField] private TextMeshProUGUI _agentDescription;
[SerializeField] private string _agentNameFormat = "{0}";
[SerializeField] private UIBehaviour _selectedAgentGroup;
[SerializeField] private UIBehaviour _selectedEffect;
[SerializeField] private AudioSetup _selectedSound;
[SerializeField] private float _closeDelayAfterSelection = 0.5f;
[SerializeField]
private CinemachineVirtualCamera _camera;
[SerializeField]
private UIList _agentList;
[SerializeField]
private UIButton _selectButton;
[SerializeField]
private TextMeshProUGUI _agentName;
[SerializeField]
private TextMeshProUGUI _agentDescription;
[SerializeField]
private string _agentNameFormat = "{0}";
[SerializeField]
private UIBehaviour _selectedAgentGroup;
[SerializeField]
private UIBehaviour _selectedEffect;
[SerializeField]
private AudioSetup _selectedSound;
[SerializeField]
private float _closeDelayAfterSelection = 0.5f;
private string _previewAgent;
private const string ShopKey = "Characters";
private string _previewAgent;
protected override void OnInitialize()
{
base.OnInitialize();
_agentList.SelectionChanged += OnSelectionChanged;
_agentList.UpdateContent += OnListUpdateContent;
_selectButton.onClick.AddListener(OnSelectButton);
}
// UIView INTERFACE
private void OnListUpdateContent(int index, MonoBehaviour content)
{
StartCoroutine(OnListUpdateContentRoutine(index,content));
}
IEnumerator OnListUpdateContentRoutine(int index, MonoBehaviour content)
{
yield return new WaitForSeconds(0.2f);
var behaviour = content as UIBehaviour;
var setup = Context.Settings.Agent.Agents[index];
behaviour.Image.sprite = setup.Icon;
protected override void OnInitialize()
{
base.OnInitialize();
bool owned = index == 0 || ShopUnlocks.IsUnlocked(setup.ID, ShopKey);
var item = content.GetComponentInParent<UIListItem>();
if (item != null) item.SetLocked(!owned); // lockGO active when NOT bought
}
protected override void OnOpen()
{
base.OnOpen();
_camera.enabled = true;
_selectedEffect.SetActive(false);
_agentList.SelectionChanged += OnSelectionChanged;
_agentList.UpdateContent += OnListUpdateContent;
var agents = Context.Settings.Agent.Agents;
if (agents != null && agents.Length > 0)
ShopUnlocks.EnsureUnlocked(agents[0].ID, ShopKey); // first is free
_selectButton.onClick.AddListener(OnSelectButton);
}
_previewAgent = Context.PlayerData.AgentID;
_agentList.Refresh(agents.Length, false);
UpdateAgent();
}
private void OnListUpdateContent(int index, MonoBehaviour content)
{
var behaviour = content as UIBehaviour;
var setup = Context.Settings.Agent.Agents[index];
protected override void OnClose()
{
_camera.enabled = false;
Context.PlayerPreview.ShowAgent(Context.PlayerData.AgentID);
base.OnClose();
}
behaviour.Image.sprite = setup.Icon;
}
protected override void OnDeinitialize()
{
_agentList.SelectionChanged -= OnSelectionChanged;
_agentList.UpdateContent -= OnListUpdateContent;
_selectButton.onClick.RemoveListener(OnSelectButton);
base.OnDeinitialize();
}
protected override void OnOpen()
{
base.OnOpen();
private void OnSelectionChanged(int index)
{
var setup = Context.Settings.Agent.Agents[index];
bool owned = index == 0 || ShopUnlocks.IsUnlocked(setup.ID, ShopKey);
if (!owned) return; // block selecting locked
_previewAgent = setup.ID;
UpdateAgent();
}
_camera.enabled = true;
_selectedEffect.SetActive(false);
private void OnSelectButton()
{
bool isSame = Context.PlayerData.AgentID == _previewAgent;
if (isSame == false)
{
Context.PlayerData.AgentID = _previewAgent;
_selectedEffect.SetActive(false);
_selectedEffect.SetActive(true);
PlaySound(_selectedSound);
UpdateAgent();
Invoke("CloseWithBack", _closeDelayAfterSelection);
}
else
{
CloseWithBack();
}
}
_previewAgent = Context.PlayerData.AgentID;
private void UpdateAgent()
{
var agentSetups = Context.Settings.Agent.Agents;
_agentList.Selection = Array.FindIndex(agentSetups, t => t.ID == _previewAgent);
_agentList.Refresh(Context.Settings.Agent.Agents.Length, false);
UpdateAgent();
}
if (_agentList.Selection < 0)
{
int firstOwned = Array.FindIndex(agentSetups, t => ShopUnlocks.IsUnlocked(t.ID, ShopKey));
_agentList.Selection = firstOwned >= 0 ? firstOwned : 0;
_previewAgent = agentSetups[_agentList.Selection].ID;
}
protected override void OnClose()
{
_camera.enabled = false;
if (_previewAgent.HasValue() == false)
{
Context.PlayerPreview.HideAgent();
_agentName.text = string.Empty;
_agentDescription.text = string.Empty;
_selectButton.interactable = false;
}
else
{
var setup = Context.Settings.Agent.GetAgentSetup(_previewAgent);
Context.PlayerPreview.ShowAgent(_previewAgent);
_agentName.text = string.Format(_agentNameFormat, setup.DisplayName);
_agentDescription.text = setup.Description;
_selectButton.interactable = ShopUnlocks.IsUnlocked(_previewAgent, ShopKey);
}
Context.PlayerPreview.ShowAgent(Context.PlayerData.AgentID);
base.OnClose();
}
protected override void OnDeinitialize()
{
_agentList.SelectionChanged -= OnSelectionChanged;
_agentList.UpdateContent -= OnListUpdateContent;
_selectButton.onClick.RemoveListener(OnSelectButton);
base.OnDeinitialize();
}
// PRIVATE METHODS
private void OnSelectionChanged(int index)
{
_previewAgent = Context.Settings.Agent.Agents[index].ID;
UpdateAgent();
}
private void OnSelectButton()
{
bool isSame = Context.PlayerData.AgentID == _previewAgent;
if (isSame == false)
{
Context.PlayerData.AgentID = _previewAgent;
_selectedEffect.SetActive(false);
_selectedEffect.SetActive(true);
PlaySound(_selectedSound);
UpdateAgent();
Invoke("CloseWithBack", _closeDelayAfterSelection);
}
else
{
CloseWithBack();
}
}
private void UpdateAgent()
{
var agentSetups = Context.Settings.Agent.Agents;
_agentList.Selection = Array.FindIndex(agentSetups, t => t.ID == _previewAgent);
if (_agentList.Selection < 0)
{
_agentList.Selection = 0;
_previewAgent = agentSetups[_agentList.Selection].ID;
}
if (_previewAgent.HasValue() == false)
{
Context.PlayerPreview.HideAgent();
_agentName.text = string.Empty;
_agentDescription.text = string.Empty;
}
else
{
var setup = Context.Settings.Agent.GetAgentSetup(_previewAgent);
Context.PlayerPreview.ShowAgent(_previewAgent);
_agentName.text = string.Format(_agentNameFormat, setup.DisplayName);
_agentDescription.text = setup.Description;
}
_selectedAgentGroup.SetActive(_previewAgent == Context.PlayerData.AgentID);
}
}
_selectedAgentGroup.SetActive(_previewAgent == Context.PlayerData.AgentID);
}
}
}
//using System;
//using TMPro;
//using UnityEngine;
//using Cinemachine;
//using System.Collections.Generic;
//using System.Collections;
//namespace TPSBR.UI
//{
// public class UIAgentSelectionView : UICloseView
// {
// [SerializeField] private CinemachineVirtualCamera _camera;
// [SerializeField] private UIList _agentList;
// [SerializeField] private UIButton _selectButton;
// [SerializeField] private TextMeshProUGUI _agentName;
// [SerializeField] private TextMeshProUGUI _agentDescription;
// [SerializeField] private string _agentNameFormat = "{0}";
// [SerializeField] private UIBehaviour _selectedAgentGroup;
// [SerializeField] private UIBehaviour _selectedEffect;
// [SerializeField] private AudioSetup _selectedSound;
// [SerializeField] private float _closeDelayAfterSelection = 0.5f;
// private string _previewAgent;
// private const string ShopKey = "Characters";
// protected override void OnInitialize()
// {
// base.OnInitialize();
// _agentList.SelectionChanged += OnSelectionChanged;
// _agentList.UpdateContent += OnListUpdateContent;
// _selectButton.onClick.AddListener(OnSelectButton);
// }
// private void OnListUpdateContent(int index, MonoBehaviour content)
// {
// StartCoroutine(OnListUpdateContentRoutine(index, content));
// }
// IEnumerator OnListUpdateContentRoutine(int index, MonoBehaviour content)
// {
// yield return new WaitForSeconds(0.1f);
// var behaviour = content as UIBehaviour;
// var setup = Context.Settings.Agent.Agents[index];
// behaviour.Image.sprite = setup.Icon;
// bool unlocked = index == 0 || ShopUnlocks.IsUnlocked(setup.ID, ShopKey);
// var item = content.GetComponentInParent<UIListItem>();
// if (item != null) item.SetLocked(!unlocked);
// }
// protected override void OnOpen()
// {
// base.OnOpen();
// _camera.enabled = true;
// _selectedEffect.SetActive(false);
// var agents = Context.Settings.Agent.Agents;
// if (agents != null && agents.Length > 0)
// ShopUnlocks.EnsureUnlocked(agents[0].ID, ShopKey);
// _previewAgent = Context.PlayerData.AgentID;
// _agentList.Refresh(agents.Length, false);
// UpdateAgent();
// }
// protected override void OnClose()
// {
// _camera.enabled = false;
// Context.PlayerPreview.ShowAgent(Context.PlayerData.AgentID);
// base.OnClose();
// }
// protected override void OnDeinitialize()
// {
// _agentList.SelectionChanged -= OnSelectionChanged;
// _agentList.UpdateContent -= OnListUpdateContent;
// _selectButton.onClick.RemoveListener(OnSelectButton);
// base.OnDeinitialize();
// }
// private void OnSelectionChanged(int index)
// {
// var setup = Context.Settings.Agent.Agents[index];
// bool unlocked = index == 0 || ShopUnlocks.IsUnlocked(setup.ID, ShopKey);
// if (!unlocked) return;
// _previewAgent = setup.ID;
// UpdateAgent();
// }
// private void OnSelectButton()
// {
// bool isSame = Context.PlayerData.AgentID == _previewAgent;
// if (isSame == false)
// {
// Context.PlayerData.AgentID = _previewAgent;
// _selectedEffect.SetActive(false);
// _selectedEffect.SetActive(true);
// PlaySound(_selectedSound);
// UpdateAgent();
// Invoke("CloseWithBack", _closeDelayAfterSelection);
// }
// else
// {
// CloseWithBack();
// }
// }
// private void UpdateAgent()
// {
// var agentSetups = Context.Settings.Agent.Agents;
// _agentList.Selection = Array.FindIndex(agentSetups, t => t.ID == _previewAgent);
// if (_agentList.Selection < 0)
// {
// int firstUnlocked = Array.FindIndex(agentSetups, t => ShopUnlocks.IsUnlocked(t.ID, ShopKey));
// _agentList.Selection = firstUnlocked >= 0 ? firstUnlocked : 0;
// _previewAgent = agentSetups[_agentList.Selection].ID;
// }
// if (_previewAgent.HasValue() == false)
// {
// Context.PlayerPreview.HideAgent();
// _agentName.text = string.Empty;
// _agentDescription.text = string.Empty;
// _selectButton.interactable = false;
// }
// else
// {
// var setup = Context.Settings.Agent.GetAgentSetup(_previewAgent);
// Context.PlayerPreview.ShowAgent(_previewAgent);
// _agentName.text = string.Format(_agentNameFormat, setup.DisplayName);
// _agentDescription.text = setup.Description;
// _selectButton.interactable = ShopUnlocks.IsUnlocked(_previewAgent, ShopKey);
// }
// _selectedAgentGroup.SetActive(_previewAgent == Context.PlayerData.AgentID);
// }
// }
//}

View File

@ -11,7 +11,9 @@ namespace TPSBR.UI
private UIButton _playButton;
[SerializeField]
private UIButton _settingsButton;
[SerializeField]
[SerializeField]
private UIButton _shopButton;
[SerializeField]
private UIButton _creditsButton;
[SerializeField]
private UIButton _changeNicknameButton;
@ -47,6 +49,8 @@ namespace TPSBR.UI
_settingsButton.onClick.AddListener(OnSettingsButton);
_playButton.onClick.AddListener(OnPlayButton);
_creditsButton.onClick.AddListener(OnCreditsButton);
_shopButton.onClick.AddListener(OnShopButton);
_changeNicknameButton.onClick.AddListener(OnChangeNicknameButton);
_quitButton.onClick.AddListener(OnQuitButton);
_playerButton.onClick.AddListener(OnPlayerButton);
@ -112,8 +116,11 @@ namespace TPSBR.UI
{
Open<UICreditsView>();
}
private void OnChangeNicknameButton()
private void OnShopButton()
{
Open<UIShopView>();
}
private void OnChangeNicknameButton()
{
var changeNicknameView = Open<UIChangeNicknameView>();
changeNicknameView.SetData("CHANGE NICKNAME", false);

View File

@ -0,0 +1,10 @@
using TPSBR.UI;
using UnityEngine;
namespace TPSBR
{
public class UIShopView : UICloseView
{
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a38625793bc96b64f92f7e92d70cde3d

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
using UnityEngine;
public static class ShopUnlocks
{
static string Key(string shop) => $"ShopUnlocks_{shop}";
public static bool IsUnlocked(string id, string shop)
{
if (string.IsNullOrEmpty(id)) return false;
var data = PlayerPrefs.GetString(Key(shop), "");
if (string.IsNullOrEmpty(data)) return false;
var parts = data.Split(',');
for (int i = 0; i < parts.Length; i++) if (parts[i] == id) return true;
return false;
}
public static void Unlock(string id, string shop)
{
if (string.IsNullOrEmpty(id)) return;
var list = new List<string>();
var data = PlayerPrefs.GetString(Key(shop), "");
if (!string.IsNullOrEmpty(data)) list.AddRange(data.Split(','));
if (!list.Contains(id)) list.Add(id);
PlayerPrefs.SetString(Key(shop), string.Join(",", list));
PlayerPrefs.Save();
}
public static void EnsureUnlocked(string id, string shop)
{
if (!IsUnlocked(id, shop)) Unlock(id, shop);
}
public static void Reset(string shop)
{
PlayerPrefs.DeleteKey(Key(shop));
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c66354f2e75f9ba409d04bb335fd6e1c

BIN
Assets/UI/lock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

156
Assets/UI/lock.png.meta Normal file
View File

@ -0,0 +1,156 @@
fileFormatVersion: 2
guid: f3be0a9c7364a3e40a2a1c19fbf4729c
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 2
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 128
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: iOS
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: WindowsStoreApps
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant: