ShopManager.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. import { _decorator, sys } from 'cc';
  2. import { ConfigManager, WeaponConfig } from '../Core/ConfigManager';
  3. import { BaseSingleton } from '../Core/BaseSingleton';
  4. const { ccclass, property } = _decorator;
  5. /**
  6. * 商店物品接口
  7. */
  8. export interface ShopItem {
  9. id: string;
  10. name: string;
  11. type: 'weapon' | 'upgrade' | 'consumable';
  12. price: number;
  13. currency: 'coin' | 'gem';
  14. weaponId?: string; // 如果是武器类型
  15. description: string;
  16. icon: string;
  17. available: boolean;
  18. purchased: boolean;
  19. maxPurchases?: number; // 最大购买次数,-1为无限
  20. currentPurchases?: number; // 当前购买次数
  21. }
  22. /**
  23. * 商店管理器
  24. * 负责商店物品的购买、货币管理等功能
  25. */
  26. @ccclass('ShopManager')
  27. export class ShopManager extends BaseSingleton {
  28. // 仅用于类型声明,实例由 BaseSingleton 维护
  29. public static _instance: ShopManager;
  30. private coins: number = 0;
  31. private gems: number = 0;
  32. private purchaseHistory: any = {};
  33. private itemPurchaseCounts: any = {};
  34. private initialized: boolean = false;
  35. private shopItems: ShopItem[] = [];
  36. private purchasedItems: string[] = [];
  37. /**
  38. * BaseSingleton 首次实例化回调
  39. */
  40. protected init() {
  41. if (!this.initialized) {
  42. this.loadShopData();
  43. this.initializeShopItems();
  44. this.initialized = true;
  45. }
  46. }
  47. // 初始化商店物品
  48. private initializeShopItems() {
  49. // 基础武器商店物品
  50. this.shopItems = [
  51. {
  52. id: 'weapon_basic_gun',
  53. name: '基础手枪',
  54. type: 'weapon',
  55. price: 50,
  56. currency: 'coin',
  57. weaponId: 'basic_gun',
  58. description: '基础的射击武器,伤害适中',
  59. icon: 'shop/weapon_basic_gun',
  60. available: true,
  61. purchased: false,
  62. maxPurchases: 1,
  63. currentPurchases: 0
  64. },
  65. {
  66. id: 'weapon_sniper',
  67. name: '狙击枪',
  68. type: 'weapon',
  69. price: 150,
  70. currency: 'coin',
  71. weaponId: 'sniper_rifle',
  72. description: '高伤害远程武器',
  73. icon: 'shop/weapon_sniper',
  74. available: true,
  75. purchased: false,
  76. maxPurchases: 1,
  77. currentPurchases: 0
  78. },
  79. {
  80. id: 'weapon_rocket',
  81. name: '火箭筒',
  82. type: 'weapon',
  83. price: 5,
  84. currency: 'gem',
  85. weaponId: 'rocket_launcher',
  86. description: '范围爆炸伤害武器',
  87. icon: 'shop/weapon_rocket',
  88. available: true,
  89. purchased: false,
  90. maxPurchases: 1,
  91. currentPurchases: 0
  92. },
  93. {
  94. id: 'upgrade_damage',
  95. name: '伤害提升',
  96. type: 'upgrade',
  97. price: 100,
  98. currency: 'coin',
  99. description: '永久增加所有武器10%伤害',
  100. icon: 'shop/upgrade_damage',
  101. available: true,
  102. purchased: false,
  103. maxPurchases: 5,
  104. currentPurchases: 0
  105. },
  106. {
  107. id: 'consumable_health_potion',
  108. name: '生命药水',
  109. type: 'consumable',
  110. price: 20,
  111. currency: 'coin',
  112. description: '恢复50点生命值',
  113. icon: 'shop/health_potion',
  114. available: true,
  115. purchased: false,
  116. maxPurchases: -1, // 无限购买
  117. currentPurchases: 0
  118. }
  119. ];
  120. }
  121. // 加载商店数据
  122. private loadShopData() {
  123. const savedData = sys.localStorage.getItem('shopData');
  124. if (savedData) {
  125. try {
  126. const data = JSON.parse(savedData);
  127. this.coins = data.coins || 0;
  128. this.gems = data.gems || 0;
  129. this.purchaseHistory = data.purchaseHistory || {};
  130. this.itemPurchaseCounts = data.itemPurchaseCounts || {};
  131. this.purchasedItems = data.purchasedItems || [];
  132. } catch (error) {
  133. this.resetShopData();
  134. }
  135. } else {
  136. this.resetShopData();
  137. }
  138. }
  139. // 保存商店数据
  140. private saveShopData() {
  141. const data = {
  142. coins: this.coins,
  143. gems: this.gems,
  144. purchaseHistory: this.purchaseHistory,
  145. itemPurchaseCounts: this.itemPurchaseCounts,
  146. purchasedItems: this.purchasedItems,
  147. shopItems: this.shopItems.map(item => ({
  148. id: item.id,
  149. purchased: item.purchased,
  150. currentPurchases: item.currentPurchases
  151. }))
  152. };
  153. try {
  154. sys.localStorage.setItem('shopData', JSON.stringify(data));
  155. } catch (error) {
  156. // 静默处理保存错误
  157. }
  158. }
  159. // 重置商店数据
  160. private resetShopData() {
  161. this.coins = 100;
  162. this.gems = 10;
  163. this.purchaseHistory = {};
  164. this.itemPurchaseCounts = {};
  165. this.purchasedItems = [];
  166. this.saveShopData();
  167. }
  168. // 获取金币数量
  169. public getCoins(): number {
  170. return this.coins;
  171. }
  172. // 获取宝石数量
  173. public getGems(): number {
  174. return this.gems;
  175. }
  176. // 添加金币
  177. public addCoins(amount: number) {
  178. this.coins += amount;
  179. this.saveShopData();
  180. }
  181. // 添加宝石
  182. public addGems(amount: number) {
  183. this.gems += amount;
  184. this.saveShopData();
  185. }
  186. // 消费金币
  187. public spendCoins(amount: number): boolean {
  188. if (this.coins >= amount) {
  189. this.coins -= amount;
  190. this.saveShopData();
  191. return true;
  192. }
  193. return false;
  194. }
  195. // 消费宝石
  196. public spendGems(amount: number): boolean {
  197. if (this.gems >= amount) {
  198. this.gems -= amount;
  199. this.saveShopData();
  200. return true;
  201. }
  202. return false;
  203. }
  204. // 获取所有商店物品
  205. public getShopItems(): ShopItem[] {
  206. return this.shopItems.filter(item => item.available);
  207. }
  208. // 获取特定类型的商店物品
  209. public getShopItemsByType(type: 'weapon' | 'upgrade' | 'consumable'): ShopItem[] {
  210. return this.shopItems.filter(item => item.type === type && item.available);
  211. }
  212. // 获取单个商店物品
  213. public getShopItem(itemId: string): ShopItem | null {
  214. return this.shopItems.find(item => item.id === itemId) || null;
  215. }
  216. // 购买物品
  217. public purchaseItem(itemId: string, price: number, currency: 'coins' | 'gems' = 'coins', maxPurchases: number = -1): boolean {
  218. // 检查购买次数限制
  219. if (maxPurchases > 0) {
  220. const currentCount = this.itemPurchaseCounts[itemId] || 0;
  221. if (currentCount >= maxPurchases) {
  222. return false;
  223. }
  224. }
  225. // 检查货币并扣除
  226. let success = false;
  227. if (currency === 'coins') {
  228. success = this.spendCoins(price);
  229. } else {
  230. success = this.spendGems(price);
  231. }
  232. if (success) {
  233. // 记录购买历史
  234. if (!this.purchaseHistory[itemId]) {
  235. this.purchaseHistory[itemId] = [];
  236. }
  237. this.purchaseHistory[itemId].push({
  238. price: price,
  239. currency: currency,
  240. timestamp: Date.now()
  241. });
  242. // 更新购买次数
  243. this.itemPurchaseCounts[itemId] = (this.itemPurchaseCounts[itemId] || 0) + 1;
  244. this.saveShopData();
  245. }
  246. return success;
  247. }
  248. // 获取物品购买次数
  249. public getItemPurchaseCount(itemId: string): number {
  250. return this.itemPurchaseCounts[itemId] || 0;
  251. }
  252. // 检查是否可以购买物品
  253. public canPurchaseItem(itemId: string, price: number, currency: 'coins' | 'gems' = 'coins', maxPurchases: number = -1): boolean {
  254. // 检查购买次数限制
  255. if (maxPurchases > 0) {
  256. const currentCount = this.itemPurchaseCounts[itemId] || 0;
  257. if (currentCount >= maxPurchases) {
  258. return false;
  259. }
  260. }
  261. // 检查货币是否足够
  262. if (currency === 'coins') {
  263. return this.coins >= price;
  264. } else {
  265. return this.gems >= price;
  266. }
  267. }
  268. // 获取购买历史
  269. public getPurchaseHistory(itemId?: string): any {
  270. if (itemId) {
  271. return this.purchaseHistory[itemId] || [];
  272. }
  273. return this.purchaseHistory;
  274. }
  275. // 重置所有购买数据
  276. public resetAllPurchases() {
  277. this.resetShopData();
  278. }
  279. // 调试用:添加大量货币
  280. public addDebugCurrency() {
  281. this.coins += 10000;
  282. this.gems += 1000;
  283. this.saveShopData();
  284. }
  285. // 检查物品是否已购买
  286. public isItemPurchased(itemId: string): boolean {
  287. return this.purchasedItems.indexOf(itemId) !== -1;
  288. }
  289. // 获取已购买的武器列表
  290. public getPurchasedWeapons(): string[] {
  291. const purchasedWeaponItems = this.shopItems.filter(item =>
  292. item.type === 'weapon' && this.isItemPurchased(item.id)
  293. );
  294. return purchasedWeaponItems.map(item => item.weaponId).filter(id => id);
  295. }
  296. // 重置所有购买记录(调试用)
  297. public resetPurchases() {
  298. this.shopItems.forEach(item => {
  299. item.purchased = false;
  300. item.currentPurchases = 0;
  301. });
  302. this.purchasedItems = [];
  303. this.saveShopData();
  304. }
  305. // 添加免费金币(调试用)
  306. public addFreeCoins(amount: number = 1000) {
  307. this.addCoins(amount);
  308. }
  309. // 添加免费宝石(调试用)
  310. public addFreeGems(amount: number = 100) {
  311. this.addGems(amount);
  312. }
  313. }