ShopManager.ts 10 KB

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