From c8c39ddbc8eb312015f6fcb675b0803a23cd4def Mon Sep 17 00:00:00 2001 From: "DESKTOP-VVOCIJO\\PC" Date: Thu, 23 Apr 2026 15:44:45 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B3=84=EC=82=B0=EB=8C=80=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=A4=91=EA=B0=84=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/01_Scenes/MyProject/GameScene.unity | 4 +- Assets/02_Scripts/Data/Player.meta | 8 +++ Assets/02_Scripts/Data/Player/PlayerWallet.cs | 28 +++++++++ .../Data/Player/PlayerWallet.cs.meta | 2 + Assets/02_Scripts/Player/PlayerController.cs | 60 +++++++++++++++++++ Assets/02_Scripts/Shopping/CheckoutMachine.cs | 38 +++++++++--- Assets/02_Scripts/UI/CheckoutProductionRow.cs | 3 + Assets/02_Scripts/UI/CheckoutVRButton.cs | 25 ++++++++ Assets/02_Scripts/UI/CheckoutVRButton.cs.meta | 2 + Assets/02_Scripts/UI/ShoppingOrderView.cs | 2 + 10 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 Assets/02_Scripts/Data/Player.meta create mode 100644 Assets/02_Scripts/Data/Player/PlayerWallet.cs create mode 100644 Assets/02_Scripts/Data/Player/PlayerWallet.cs.meta create mode 100644 Assets/02_Scripts/UI/CheckoutVRButton.cs create mode 100644 Assets/02_Scripts/UI/CheckoutVRButton.cs.meta diff --git a/Assets/01_Scenes/MyProject/GameScene.unity b/Assets/01_Scenes/MyProject/GameScene.unity index d155cc79..c291b083 100644 --- a/Assets/01_Scenes/MyProject/GameScene.unity +++ b/Assets/01_Scenes/MyProject/GameScene.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4574f161dffa2c2e5d23312aa7a9ae935fab250704c43b9be30dd1f6a1d5a7c2 -size 13289838 +oid sha256:4dbd856032861dce25163f4b1daed549fc2568d2facaae6b193ab160078d3006 +size 13292854 diff --git a/Assets/02_Scripts/Data/Player.meta b/Assets/02_Scripts/Data/Player.meta new file mode 100644 index 00000000..2310ccbc --- /dev/null +++ b/Assets/02_Scripts/Data/Player.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53d3a05a555fad549ba0b9efb1fefe43 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/02_Scripts/Data/Player/PlayerWallet.cs b/Assets/02_Scripts/Data/Player/PlayerWallet.cs new file mode 100644 index 00000000..e6dceefb --- /dev/null +++ b/Assets/02_Scripts/Data/Player/PlayerWallet.cs @@ -0,0 +1,28 @@ +using UnityEngine; + +namespace VRShopping.Player +{ + public class PlayerWallet : MonoBehaviour + { + //예산 + [Min(0)] public int Budget; + + public bool PayMoney(int cost) + { + bool successFlag; + + //예산이 비용보다 많을시 + if(Budget >= cost) + { + Budget -= cost; + successFlag = true; + } + else //예산 부족 + { + successFlag = false; + } + + return successFlag; + } + } +} diff --git a/Assets/02_Scripts/Data/Player/PlayerWallet.cs.meta b/Assets/02_Scripts/Data/Player/PlayerWallet.cs.meta new file mode 100644 index 00000000..bd87b372 --- /dev/null +++ b/Assets/02_Scripts/Data/Player/PlayerWallet.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ea3bbbc8e3d11ec4d8c5d376e1844ab8 \ No newline at end of file diff --git a/Assets/02_Scripts/Player/PlayerController.cs b/Assets/02_Scripts/Player/PlayerController.cs index 01c247b5..421100e4 100644 --- a/Assets/02_Scripts/Player/PlayerController.cs +++ b/Assets/02_Scripts/Player/PlayerController.cs @@ -1,4 +1,9 @@ +using System.Collections.Generic; using UnityEngine; +using VRShopping.Interact; +using VRShopping.Items; +using VRShopping.Player; +using VRShopping.Shopping; using VRShopping.UI; public class PlayerController : MonoBehaviour,ITransScenePossible @@ -9,6 +14,7 @@ public class PlayerController : MonoBehaviour,ITransScenePossible private bool _controlPositive = true; [SerializeField] private ShoppingOrderView _shoppingOrderView; + [SerializeField] private PlayerWallet playerWallet; private void Awake() { @@ -35,4 +41,58 @@ public async void ToggleShoppingOrderList() await _shoppingOrderView.ToggleShoppingOrderList(); _controlPositive = true; } + + public void Checkout(CheckoutMachine checkoutMachine) + { + List checkoutList = checkoutMachine.GetCheckoutList(); + + if(playerWallet.PayMoney(checkoutMachine.CheckoutSum)) + { + Debug.Log("결제완료"); + + if (ShoppingOrderMissionClearCheck(checkoutList, out var missing)) + { + Debug.Log("게임 클리어"); + } + else + { + var parts = new List(missing.Count); + foreach (var (group, shortage) in missing) parts.Add($"{group} x{shortage}"); + Debug.Log($"장보기 목록 미충족 — 부족: {string.Join(", ", parts)}"); + } + } + else + { + Debug.Log("예산 부족으로 결제 불가"); + } + } + + //계산한 품목이 장보기 목록을 모두 충족하는지 검사 (더 많은 건 허용) + //missing: 부족한 ProductGroup과 부족 수량 목록 + private bool ShoppingOrderMissionClearCheck(List checkoutList, out List<(ProductGroup group, int shortage)> missing) + { + missing = new List<(ProductGroup, int)>(); + + ShoppingOrderList orderList = _shoppingOrderView != null ? _shoppingOrderView.OrderList : null; + if (orderList == null) return true; + + //구매한 품목을 ProductGroup 기준으로 집계 + var boughtByGroup = new Dictionary(); + foreach (var row in checkoutList) + { + if (row.Item == null) continue; + boughtByGroup.TryGetValue(row.Item.ProductGroup, out int count); + boughtByGroup[row.Item.ProductGroup] = count + row.Quantity; + } + + //목록의 각 항목을 전부 확인해서 부족분 수집 + foreach (var entry in orderList.Entries) + { + boughtByGroup.TryGetValue(entry.ProductGroup, out int count); + int shortage = entry.RequiredQuantity - count; + if (shortage > 0) missing.Add((entry.ProductGroup, shortage)); + } + + return missing.Count == 0; + } } diff --git a/Assets/02_Scripts/Shopping/CheckoutMachine.cs b/Assets/02_Scripts/Shopping/CheckoutMachine.cs index f472c91c..152524d1 100644 --- a/Assets/02_Scripts/Shopping/CheckoutMachine.cs +++ b/Assets/02_Scripts/Shopping/CheckoutMachine.cs @@ -1,7 +1,10 @@ using System.Collections.Generic; using TMPro; using UnityEngine; +using UnityEngine.UI; using VRShopping.Items; +using VRShopping.Player; +using VRShopping.Shopping; using VRShopping.UI; namespace VRShopping.Interact @@ -12,20 +15,24 @@ public class CheckoutMachine : MonoBehaviour [SerializeField] private Transform _rowContainer; [SerializeField] private CheckoutProductionRow _rowPrefab; - private readonly Dictionary _rowByItemId = new(); + private int _nextOrderNum = 1; [SerializeField] private TMP_Text _checkoutSumField; + private void Start() + { + UpdateSumUI(); + } + public void UpdateSumUI() { - _checkoutSumField.text = CheckoutSum.ToString("N0"); + if (_checkoutSumField != null) + _checkoutSumField.text = CheckoutSum.ToString("N0"); } public void AddCheckoutProduction(ItemData itemData) { - Debug.Log("추가버튼 누름"); - if (itemData == null) return; if (_rowByItemId.TryGetValue(itemData.ItemId, out CheckoutProductionRow row)) @@ -35,19 +42,27 @@ public void AddCheckoutProduction(ItemData itemData) else { row = Instantiate(_rowPrefab, _rowContainer); + row.gameObject.SetActive(false); // OnEnable 지연 + row.Bind(itemData, 1); + row.SetOrderNum(_nextOrderNum++); + + Canvas.ForceUpdateCanvases(); + LayoutRebuilder.ForceRebuildLayoutImmediate(_rowContainer as RectTransform); + + row.gameObject.SetActive(true); // 바운드 확정 후 OnEnable row.OnAddClicked += AddCheckoutProduction; row.OnRemoveClicked += RemoveCheckoutProduction; - row.Bind(itemData, 1); + _rowByItemId[itemData.ItemId] = row; } CheckoutSum += itemData.FinalPrice; + + UpdateSumUI(); } public void RemoveCheckoutProduction(ItemData itemData) { - Debug.Log("감소버튼 누름"); - if (itemData == null) return; if (!_rowByItemId.TryGetValue(itemData.ItemId, out CheckoutProductionRow row)) return; @@ -62,6 +77,15 @@ public void RemoveCheckoutProduction(ItemData itemData) { row.Bind(itemData, row.Quantity - 1); } + + UpdateSumUI(); + } + + public List GetCheckoutList() + { + var list = new List(_rowByItemId.Values); + list.Sort((a, b) => a.OrderNum.CompareTo(b.OrderNum)); + return list; } } } diff --git a/Assets/02_Scripts/UI/CheckoutProductionRow.cs b/Assets/02_Scripts/UI/CheckoutProductionRow.cs index d6aaf154..ef92e250 100644 --- a/Assets/02_Scripts/UI/CheckoutProductionRow.cs +++ b/Assets/02_Scripts/UI/CheckoutProductionRow.cs @@ -16,10 +16,13 @@ public class CheckoutProductionRow : MonoBehaviour public ItemData Item { get; private set; } public int Quantity { get; private set; } + public int OrderNum { get; private set; } = 1; public event Action OnAddClicked; public event Action OnRemoveClicked; + public void SetOrderNum(int orderNum) => OrderNum = orderNum; + private void Awake() { if (_addButton != null) _addButton.onClick.AddListener(() => OnAddClicked?.Invoke(Item)); diff --git a/Assets/02_Scripts/UI/CheckoutVRButton.cs b/Assets/02_Scripts/UI/CheckoutVRButton.cs new file mode 100644 index 00000000..cb04390b --- /dev/null +++ b/Assets/02_Scripts/UI/CheckoutVRButton.cs @@ -0,0 +1,25 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.XR.Interaction.Toolkit.UI; +using VRShopping.Interact; + +public class CheckoutVRButton : MonoBehaviour, IPointerClickHandler +{ + public void OnPointerClick(PointerEventData eventData) + { + GameObject whatWasClicked = eventData.pointerPress; + + if (eventData is not TrackedDeviceEventData trackedData) return; + + var interactorMB = trackedData.interactor as MonoBehaviour; + if (interactorMB == null) return; + GameObject whoClicked = interactorMB.gameObject; + + PlayerController clickPlayer = whoClicked.GetComponentInParent(); + CheckoutMachine checkoutMachine = whatWasClicked.GetComponentInParent(); + + if (clickPlayer == null || checkoutMachine == null) return; + + clickPlayer.Checkout(checkoutMachine); + } +} diff --git a/Assets/02_Scripts/UI/CheckoutVRButton.cs.meta b/Assets/02_Scripts/UI/CheckoutVRButton.cs.meta new file mode 100644 index 00000000..aa8806da --- /dev/null +++ b/Assets/02_Scripts/UI/CheckoutVRButton.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4b57c28251a9ae24ea3f54a09201a948 \ No newline at end of file diff --git a/Assets/02_Scripts/UI/ShoppingOrderView.cs b/Assets/02_Scripts/UI/ShoppingOrderView.cs index 7b92a585..76edff46 100644 --- a/Assets/02_Scripts/UI/ShoppingOrderView.cs +++ b/Assets/02_Scripts/UI/ShoppingOrderView.cs @@ -11,6 +11,8 @@ public class ShoppingOrderView : MonoBehaviour [SerializeField] private Animator _anim; [SerializeField] private GameObject _paper; + public ShoppingOrderList OrderList => _orderList; + private bool _visibleShoppingOrderList = false; private void Start()