|
|
@@ -0,0 +1,360 @@
|
|
|
+import { _decorator, Component, sys } from 'cc';
|
|
|
+import { ConfigManager, WeaponConfig } from '../Core/ConfigManager';
|
|
|
+const { ccclass, property } = _decorator;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 商店物品接口
|
|
|
+ */
|
|
|
+export interface ShopItem {
|
|
|
+ id: string;
|
|
|
+ name: string;
|
|
|
+ type: 'weapon' | 'upgrade' | 'consumable';
|
|
|
+ price: number;
|
|
|
+ currency: 'coin' | 'gem';
|
|
|
+ weaponId?: string; // 如果是武器类型
|
|
|
+ description: string;
|
|
|
+ icon: string;
|
|
|
+ available: boolean;
|
|
|
+ purchased: boolean;
|
|
|
+ maxPurchases?: number; // 最大购买次数,-1为无限
|
|
|
+ currentPurchases?: number; // 当前购买次数
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 商店管理器
|
|
|
+ * 负责物品购买、货币管理等功能
|
|
|
+ */
|
|
|
+@ccclass('ShopManager')
|
|
|
+export class ShopManager extends Component {
|
|
|
+ private static instance: ShopManager = null;
|
|
|
+
|
|
|
+ private coins: number = 100; // 初始金币
|
|
|
+ private gems: number = 10; // 初始宝石
|
|
|
+ private shopItems: ShopItem[] = [];
|
|
|
+ private purchasedItems: string[] = [];
|
|
|
+
|
|
|
+ onLoad() {
|
|
|
+ if (ShopManager.instance === null) {
|
|
|
+ ShopManager.instance = this;
|
|
|
+ this.loadShopData();
|
|
|
+ this.initializeShopItems();
|
|
|
+ } else if (ShopManager.instance !== this) {
|
|
|
+ this.destroy();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ onDestroy() {
|
|
|
+ if (ShopManager.instance === this) {
|
|
|
+ ShopManager.instance = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static getInstance(): ShopManager {
|
|
|
+ return ShopManager.instance;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化商店物品
|
|
|
+ private initializeShopItems() {
|
|
|
+ // 基础武器商店物品
|
|
|
+ this.shopItems = [
|
|
|
+ {
|
|
|
+ id: 'weapon_basic_gun',
|
|
|
+ name: '基础手枪',
|
|
|
+ type: 'weapon',
|
|
|
+ price: 50,
|
|
|
+ currency: 'coin',
|
|
|
+ weaponId: 'basic_gun',
|
|
|
+ description: '基础的射击武器,伤害适中',
|
|
|
+ icon: 'shop/weapon_basic_gun',
|
|
|
+ available: true,
|
|
|
+ purchased: false,
|
|
|
+ maxPurchases: 1,
|
|
|
+ currentPurchases: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'weapon_sniper',
|
|
|
+ name: '狙击枪',
|
|
|
+ type: 'weapon',
|
|
|
+ price: 150,
|
|
|
+ currency: 'coin',
|
|
|
+ weaponId: 'sniper_rifle',
|
|
|
+ description: '高伤害远程武器',
|
|
|
+ icon: 'shop/weapon_sniper',
|
|
|
+ available: true,
|
|
|
+ purchased: false,
|
|
|
+ maxPurchases: 1,
|
|
|
+ currentPurchases: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'weapon_rocket',
|
|
|
+ name: '火箭筒',
|
|
|
+ type: 'weapon',
|
|
|
+ price: 5,
|
|
|
+ currency: 'gem',
|
|
|
+ weaponId: 'rocket_launcher',
|
|
|
+ description: '范围爆炸伤害武器',
|
|
|
+ icon: 'shop/weapon_rocket',
|
|
|
+ available: true,
|
|
|
+ purchased: false,
|
|
|
+ maxPurchases: 1,
|
|
|
+ currentPurchases: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'upgrade_damage',
|
|
|
+ name: '伤害提升',
|
|
|
+ type: 'upgrade',
|
|
|
+ price: 100,
|
|
|
+ currency: 'coin',
|
|
|
+ description: '永久增加所有武器10%伤害',
|
|
|
+ icon: 'shop/upgrade_damage',
|
|
|
+ available: true,
|
|
|
+ purchased: false,
|
|
|
+ maxPurchases: 5,
|
|
|
+ currentPurchases: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'consumable_health_potion',
|
|
|
+ name: '生命药水',
|
|
|
+ type: 'consumable',
|
|
|
+ price: 20,
|
|
|
+ currency: 'coin',
|
|
|
+ description: '恢复50点生命值',
|
|
|
+ icon: 'shop/health_potion',
|
|
|
+ available: true,
|
|
|
+ purchased: false,
|
|
|
+ maxPurchases: -1, // 无限购买
|
|
|
+ currentPurchases: 0
|
|
|
+ }
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载商店数据
|
|
|
+ private loadShopData() {
|
|
|
+ const savedData = sys.localStorage.getItem('shopData');
|
|
|
+ if (savedData) {
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(savedData);
|
|
|
+ this.coins = data.coins || 100;
|
|
|
+ this.gems = data.gems || 10;
|
|
|
+ this.purchasedItems = data.purchasedItems || [];
|
|
|
+ console.log('商店数据加载成功');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('商店数据解析失败:', error);
|
|
|
+ this.resetShopData();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存商店数据
|
|
|
+ private saveShopData() {
|
|
|
+ const data = {
|
|
|
+ coins: this.coins,
|
|
|
+ gems: this.gems,
|
|
|
+ purchasedItems: this.purchasedItems,
|
|
|
+ shopItems: this.shopItems.map(item => ({
|
|
|
+ id: item.id,
|
|
|
+ purchased: item.purchased,
|
|
|
+ currentPurchases: item.currentPurchases
|
|
|
+ }))
|
|
|
+ };
|
|
|
+
|
|
|
+ try {
|
|
|
+ sys.localStorage.setItem('shopData', JSON.stringify(data));
|
|
|
+ console.log('商店数据保存成功');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('商店数据保存失败:', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置商店数据
|
|
|
+ private resetShopData() {
|
|
|
+ this.coins = 100;
|
|
|
+ this.gems = 10;
|
|
|
+ this.purchasedItems = [];
|
|
|
+ this.saveShopData();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取金币数量
|
|
|
+ public getCoins(): number {
|
|
|
+ return this.coins;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取宝石数量
|
|
|
+ public getGems(): number {
|
|
|
+ return this.gems;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加金币
|
|
|
+ public addCoins(amount: number) {
|
|
|
+ this.coins += amount;
|
|
|
+ this.saveShopData();
|
|
|
+ console.log(`获得 ${amount} 金币,总计: ${this.coins}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加宝石
|
|
|
+ public addGems(amount: number) {
|
|
|
+ this.gems += amount;
|
|
|
+ this.saveShopData();
|
|
|
+ console.log(`获得 ${amount} 宝石,总计: ${this.gems}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 消费金币
|
|
|
+ public spendCoins(amount: number): boolean {
|
|
|
+ if (this.coins >= amount) {
|
|
|
+ this.coins -= amount;
|
|
|
+ this.saveShopData();
|
|
|
+ console.log(`消费 ${amount} 金币,剩余: ${this.coins}`);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ console.warn(`金币不足,需要 ${amount},当前 ${this.coins}`);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 消费宝石
|
|
|
+ public spendGems(amount: number): boolean {
|
|
|
+ if (this.gems >= amount) {
|
|
|
+ this.gems -= amount;
|
|
|
+ this.saveShopData();
|
|
|
+ console.log(`消费 ${amount} 宝石,剩余: ${this.gems}`);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ console.warn(`宝石不足,需要 ${amount},当前 ${this.gems}`);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取所有商店物品
|
|
|
+ public getShopItems(): ShopItem[] {
|
|
|
+ return this.shopItems.filter(item => item.available);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取特定类型的商店物品
|
|
|
+ public getShopItemsByType(type: 'weapon' | 'upgrade' | 'consumable'): ShopItem[] {
|
|
|
+ return this.shopItems.filter(item => item.type === type && item.available);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取单个商店物品
|
|
|
+ public getShopItem(itemId: string): ShopItem | null {
|
|
|
+ return this.shopItems.find(item => item.id === itemId) || null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否可以购买物品
|
|
|
+ public canPurchaseItem(itemId: string): boolean {
|
|
|
+ const item = this.getShopItem(itemId);
|
|
|
+ if (!item || !item.available) return false;
|
|
|
+
|
|
|
+ // 检查购买次数限制
|
|
|
+ if (item.maxPurchases !== -1 && item.currentPurchases >= item.maxPurchases) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查货币是否足够
|
|
|
+ if (item.currency === 'coin') {
|
|
|
+ return this.coins >= item.price;
|
|
|
+ } else if (item.currency === 'gem') {
|
|
|
+ return this.gems >= item.price;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 购买物品
|
|
|
+ public purchaseItem(itemId: string): boolean {
|
|
|
+ const item = this.getShopItem(itemId);
|
|
|
+ if (!item || !this.canPurchaseItem(itemId)) {
|
|
|
+ console.warn(`无法购买物品: ${itemId}`);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 消费货币
|
|
|
+ let success = false;
|
|
|
+ if (item.currency === 'coin') {
|
|
|
+ success = this.spendCoins(item.price);
|
|
|
+ } else if (item.currency === 'gem') {
|
|
|
+ success = this.spendGems(item.price);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (success) {
|
|
|
+ // 更新购买状态
|
|
|
+ item.currentPurchases = (item.currentPurchases || 0) + 1;
|
|
|
+
|
|
|
+ if (item.maxPurchases !== -1 && item.currentPurchases >= item.maxPurchases) {
|
|
|
+ item.purchased = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加到已购买列表
|
|
|
+ if (this.purchasedItems.indexOf(itemId) === -1) {
|
|
|
+ this.purchasedItems.push(itemId);
|
|
|
+ }
|
|
|
+
|
|
|
+ this.saveShopData();
|
|
|
+ console.log(`成功购买: ${item.name}`);
|
|
|
+
|
|
|
+ // 处理购买后的效果
|
|
|
+ this.applyItemEffect(item);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 应用物品效果
|
|
|
+ private applyItemEffect(item: ShopItem) {
|
|
|
+ switch (item.type) {
|
|
|
+ case 'weapon':
|
|
|
+ // 武器类型:解锁武器
|
|
|
+ console.log(`解锁武器: ${item.weaponId}`);
|
|
|
+ // 这里可以通知其他系统武器已解锁
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'upgrade':
|
|
|
+ // 升级类型:应用永久效果
|
|
|
+ console.log(`应用升级: ${item.name}`);
|
|
|
+ // 这里可以修改全局属性
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'consumable':
|
|
|
+ // 消耗品类型:立即使用
|
|
|
+ console.log(`使用消耗品: ${item.name}`);
|
|
|
+ // 这里可以应用临时效果
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查物品是否已购买
|
|
|
+ public isItemPurchased(itemId: string): boolean {
|
|
|
+ return this.purchasedItems.indexOf(itemId) !== -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取已购买的武器列表
|
|
|
+ public getPurchasedWeapons(): string[] {
|
|
|
+ const purchasedWeaponItems = this.shopItems.filter(item =>
|
|
|
+ item.type === 'weapon' && this.isItemPurchased(item.id)
|
|
|
+ );
|
|
|
+ return purchasedWeaponItems.map(item => item.weaponId).filter(id => id);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置所有购买记录(调试用)
|
|
|
+ public resetPurchases() {
|
|
|
+ this.shopItems.forEach(item => {
|
|
|
+ item.purchased = false;
|
|
|
+ item.currentPurchases = 0;
|
|
|
+ });
|
|
|
+ this.purchasedItems = [];
|
|
|
+ this.saveShopData();
|
|
|
+ console.log('所有购买记录已重置');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加免费金币(调试用)
|
|
|
+ public addFreeCoins(amount: number = 1000) {
|
|
|
+ this.addCoins(amount);
|
|
|
+ console.log(`添加免费金币: ${amount}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加免费宝石(调试用)
|
|
|
+ public addFreeGems(amount: number = 100) {
|
|
|
+ this.addGems(amount);
|
|
|
+ console.log(`添加免费宝石: ${amount}`);
|
|
|
+ }
|
|
|
+}
|