ShoppingController.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. using Newtonsoft.Json;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using Unity.VisualScripting;
  6. using UnityEngine;
  7. using UnityEngine.SceneManagement;
  8. using UnityEngine.SocialPlatforms.Impl;
  9. using UnityEngine.UIElements;
  10. /* 这个controller 是用于控制 Shopping UI菜单的
  11. */
  12. public class ShoppingController : MonoBehaviour
  13. {
  14. // Start is called before the first frame update
  15. // 主页面元素
  16. private Button foodButton, toyButton, otherButton, backButton;
  17. private Label coinQty;
  18. private List<ItemInShop> shoppingItems = new();
  19. private VisualElement itemListView;
  20. //弹窗元素
  21. private Button yesButton, noButton;
  22. private Label msgBody;
  23. private VisualElement msgRoot, msgField;
  24. private TextField qtyField;
  25. int puchaseQty = 1; // 购买数量,默认1个
  26. // 选中的产品
  27. private string selectedItemId, selectedItemDesc, selectedItemPrice;
  28. void OnEnable()
  29. {
  30. // 基层元素获取
  31. var root = GetComponent<UIDocument>().rootVisualElement;
  32. var mainManu = root.Q<VisualElement>("mainManu");
  33. itemListView = root.Q<VisualElement>("itemListView");
  34. foodButton = mainManu.Q<Button>("food");
  35. foodButton.clicked += () => TabSwitch(foodButton);
  36. toyButton = mainManu.Q<Button>("toy");
  37. toyButton.clicked += () => TabSwitch(toyButton);
  38. otherButton = mainManu.Q<Button>("other");
  39. otherButton.clicked += () => TabSwitch(otherButton);
  40. var coinArea = root.Q<VisualElement>("coinArea");
  41. coinQty = coinArea.Q<Label>("coinQty");
  42. backButton = root.Q<Button>("back");
  43. // 绑定事件
  44. backButton.clicked += BackBtnClick;
  45. // 弹窗元素获取
  46. msgRoot = root.Q<VisualElement>("msgRoot");
  47. msgField = msgRoot.Q<VisualElement>("msgField");
  48. msgBody = msgField.Q<Label>("msgBody");
  49. yesButton = msgField.Q<Button>("msgYes");
  50. noButton = msgField.Q<Button>("msgNo");
  51. qtyField = msgField.Q<TextField>("qtyField");
  52. noButton.clicked += MsgNoClick;
  53. yesButton.clicked += MsgYesClick;
  54. qtyField.RegisterValueChangedCallback(OnQtyFieldValueChanged);
  55. //初始化设定
  56. LanguageSetting();
  57. DataLoading();
  58. GetItemList("food");
  59. foodButton.transform.scale = new Vector3(1.2f, 1.2f);
  60. InstallItems("food");
  61. }
  62. private void OnDisable()
  63. {
  64. shoppingItems.Clear(); // 因为启动时候调用OnEable数据会被重复加载
  65. }
  66. // Update is called once per frame
  67. //void Update()
  68. //{
  69. //}
  70. //菜单语言设定
  71. void LanguageSetting()
  72. {
  73. // 设置 shopping UI界面里面label和按键的语言显示
  74. string textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "shoppingUI", "button", "food", EnviromentSetting.languageCode });
  75. foodButton.text = textValue;
  76. textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "shoppingUI", "button", "toy", EnviromentSetting.languageCode });
  77. toyButton.text = textValue;
  78. textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "shoppingUI", "button", "other", EnviromentSetting.languageCode });
  79. otherButton.text = textValue;
  80. textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "shoppingUI", "button", "back", EnviromentSetting.languageCode });
  81. backButton.text = textValue;
  82. textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "shoppingUI", "button", "yes", EnviromentSetting.languageCode });
  83. yesButton.text = textValue;
  84. textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "shoppingUI", "button", "no", EnviromentSetting.languageCode });
  85. noButton.text = textValue;
  86. textValue = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "shoppingUI", "message_box", "qty", EnviromentSetting.languageCode });
  87. qtyField.label = textValue;
  88. }
  89. /*获取所有产品列表,切换商品分类之后,需要重新读取和加载
  90. */
  91. void GetItemList(string type)
  92. {
  93. // 按照类别获取shopping items
  94. shoppingItems.Clear();
  95. string itemRawData = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "item", type});
  96. Dictionary<string, object> itemDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(itemRawData);
  97. foreach (string _item in itemDict.Keys)
  98. {
  99. var itemDetail = JsonConvert.DeserializeObject<Dictionary<string, object>>(itemDict[_item].ToString());
  100. string price = itemDetail["price"].ToString();
  101. string picture = itemDetail["picture"].ToString();
  102. var desc = JsonConvert.DeserializeObject<Dictionary<string, object>>(itemDetail["description"].ToString());
  103. string description = desc[EnviromentSetting.languageCode].ToString();
  104. // 检测toy是否达到最大可以拥有的数量,如果达到就不再添加
  105. if (type == "toy")
  106. {
  107. if(!UserProperty.toy.TryGetValue(_item, out int qty))
  108. {
  109. // 如果用户没有这个道具,就商品里面添加这个道具
  110. ItemInShop SearchedItem = new(_item, description, price, picture);
  111. shoppingItems.Add(SearchedItem);
  112. }
  113. else
  114. {
  115. // 如果用户有这个,并且拥有数量小于最大值,就商品里面添加这个道具
  116. if (qty < int.Parse(itemDetail["max qty"].ToString()))
  117. {
  118. ItemInShop SearchedItem = new(_item, description, price, picture);
  119. shoppingItems.Add(SearchedItem);
  120. }
  121. }
  122. }
  123. // 检测food是否达到最大可以拥有的数量,如果达到就不再添加
  124. if (type == "food")
  125. {
  126. if (!UserProperty.food.TryGetValue(_item, out int qty))
  127. {
  128. // 如果用户没有这个道具,就商品里面添加这个道具
  129. ItemInShop SearchedItem = new(_item, description, price, picture);
  130. shoppingItems.Add(SearchedItem);
  131. }
  132. else
  133. {
  134. // 如果用户有这个,并且拥有数量小于最大值,就商品里面添加这个道具
  135. if (qty < int.Parse(itemDetail["max qty"].ToString()))
  136. {
  137. ItemInShop SearchedItem = new(_item, description, price, picture);
  138. shoppingItems.Add(SearchedItem);
  139. }
  140. }
  141. }
  142. // 检测other是否达到最大可以拥有的数量,如果达到就不再添加
  143. if (type == "other")
  144. {
  145. if (!UserProperty.other.TryGetValue(_item, out int qty))
  146. {
  147. // 如果用户没有这个道具,就商品里面添加这个道具
  148. ItemInShop SearchedItem = new(_item, description, price, picture);
  149. shoppingItems.Add(SearchedItem);
  150. }
  151. else
  152. {
  153. // 如果用户有这个,并且拥有数量小于最大值,就商品里面添加这个道具
  154. if (qty < int.Parse(itemDetail["max qty"].ToString()))
  155. {
  156. ItemInShop SearchedItem = new(_item, description, price, picture);
  157. shoppingItems.Add(SearchedItem);
  158. }
  159. }
  160. }
  161. }
  162. }
  163. // 将items装载到菜单中,切换商品分类之后,需要重新读取和加载
  164. void InstallItems(string type)
  165. {
  166. var root = GetComponent<UIDocument>().rootVisualElement;
  167. itemListView.Clear();
  168. VisualTreeAsset itemResource = Resources.Load<VisualTreeAsset>("Shopping/Item");
  169. List<ItemInShop> items = new();
  170. foreach(var item in shoppingItems)
  171. {
  172. var itemFrame = new VisualElement();
  173. itemFrame = itemResource.CloneTree();
  174. var description = itemFrame.Q<Label>("description");
  175. description.text = item.description;
  176. var price = itemFrame.Q<Label>("price");
  177. price.text = "$ "+item.price;
  178. var texture = Resources.Load<Texture2D>(item.picture);
  179. var picture = itemFrame.Q<VisualElement>("picture");
  180. picture.style.backgroundImage = new StyleBackground(texture);
  181. itemFrame.RegisterCallback<ClickEvent>(e => ItemClick(e, item.id, item.description, item.price));
  182. itemListView.Add(itemFrame);
  183. }
  184. }
  185. // 点击商品后跳出确认窗口
  186. void ItemClick(ClickEvent clickEvent, string itemId, string description, string price)
  187. {
  188. selectedItemId = itemId;
  189. selectedItemDesc = description;
  190. selectedItemPrice = price;
  191. msgBody.text = description;
  192. msgRoot.visible = true;
  193. qtyField.value = "1"; // 重置数量输入框
  194. puchaseQty = 1; // 重置购买数量
  195. }
  196. // 数据读取
  197. void DataLoading()
  198. {
  199. // 游戏金币数量读取
  200. coinQty.text = UserProperty.coin.ToString();
  201. }
  202. void TabSwitch(Button btn)
  203. {
  204. itemListView.style.backgroundColor = btn.resolvedStyle.backgroundColor;
  205. foodButton.transform.scale = new Vector3(1f, 1f, 1);
  206. toyButton.transform.scale = new Vector3(1f, 1f, 1);
  207. otherButton.transform.scale = new Vector3(1f, 1f, 1);
  208. btn.transform.scale = new Vector3(1.2f, 1.2f, 1);
  209. itemListView.Clear();
  210. HomeSoundEffectController.Instance.PlaySoundEffect(0);
  211. // 这里btn.name必须和json里面商品类别完全匹配
  212. GetItemList(btn.name);
  213. InstallItems(btn.name);
  214. }
  215. // msg no button 点击
  216. void MsgNoClick()
  217. {
  218. msgRoot.visible = false;
  219. }
  220. // msg yes button 点击
  221. void MsgYesClick()
  222. {
  223. Debug.Log("msg yes clicked");
  224. msgRoot.visible = false;
  225. // 检测用户金币是否足够
  226. if (UserProperty.coin > int.Parse(selectedItemPrice))
  227. {
  228. PurchaseItemRequest(selectedItemId);
  229. }
  230. else
  231. {
  232. string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "shoppingUI", "message", "not_enough_coin", EnviromentSetting.languageCode });
  233. MessageBoxController.ShowMessage(msg);
  234. }
  235. }
  236. void BackBtnClick()
  237. {
  238. HomeSoundEffectController.Instance.PlaySoundEffect(2);
  239. var uiPlaceholder = GameObject.Find("UI Placeholder");
  240. if (uiPlaceholder != null)
  241. {
  242. var shoppingUI = uiPlaceholder.transform.Find("ShoppingUI").gameObject;
  243. var vamUI = uiPlaceholder.transform.Find("VoiceAndMenu").gameObject;
  244. shoppingUI.SetActive(false);
  245. vamUI.SetActive(true);
  246. }
  247. }
  248. // 购物request
  249. void PurchaseItemRequest(string itemId)
  250. {
  251. Debug.Log("Purchase item request");
  252. string url = "/api/item/puchase/";
  253. WWWForm form = new();
  254. form.AddField("user_id", UserProperty.userId);
  255. form.AddField("item_id", itemId);
  256. form.AddField("qty", puchaseQty);
  257. StartCoroutine(WebController.PostRequest(url, form, callback: PurchaseItemCallback));
  258. }
  259. void PurchaseItemCallback(string json)
  260. {
  261. var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
  262. if (data != null && data["status"].ToString() == "success")
  263. {
  264. HomeSoundEffectController.Instance.PlaySoundEffect(3);
  265. // 重新写入用户数据
  266. string userInfo = data["user_info"].ToString();
  267. UserProperty.FreshUserInfo(userInfo);
  268. // TODO 然后重新写入道具数据
  269. UserProperty.food.Clear();
  270. UserProperty.toy.Clear();
  271. UserProperty.other.Clear();
  272. // 弹出窗户提示购买成功
  273. string msg = GameTool.GetValueAtPath(EnviromentSetting.languageData, new string[] { "shoppingUI", "message", "purchase_success", EnviromentSetting.languageCode });
  274. msg = msg.Replace("<<item_name>>", selectedItemDesc);
  275. MessageBoxController.ShowMessage(msg);
  276. }
  277. else
  278. {
  279. Debug.Log(data["message"]);
  280. }
  281. }
  282. private void OnQtyFieldValueChanged(ChangeEvent<string> evt)
  283. {
  284. // 尝试将输入内容转换为整数
  285. if (int.TryParse(evt.newValue, out int value))
  286. {
  287. // 检查是否在 1 到 999 的范围内
  288. if (value < 1)
  289. {
  290. qtyField.value = "1"; // 如果小于 1,自动修正为 1
  291. }
  292. else if (value > 99)
  293. {
  294. qtyField.value = "99"; // 如果大于 999,自动修正为 999
  295. }
  296. yesButton.SetEnabled(true); // 启用确认按钮
  297. puchaseQty = value; // 更新购买数量
  298. }
  299. else
  300. {
  301. // 如果输入不是有效的整数,清空或提示用户
  302. qtyField.value = ""; // 清空输入
  303. yesButton.SetEnabled(false); // 禁用确认按钮
  304. Debug.Log("请输入有效的整数!");
  305. }
  306. }
  307. }
  308. public class ItemInShop
  309. {
  310. public string id;
  311. public string description;
  312. public string picture;
  313. public string price;
  314. public ItemInShop(string id, string desc, string price, string picture) {
  315. this.id = id;
  316. this.description = desc;
  317. this.price = price;
  318. this.picture = picture;
  319. }
  320. }