import { _decorator, Component, Node, Prefab, instantiate, Vec3, find, JsonAsset, Sprite, Color, SpriteFrame, resources, UITransform } from 'cc'; import { ConfigManager, WeaponConfig } from '../Core/ConfigManager'; const { ccclass, property } = _decorator; /** * 武器方块测试脚本 * 用于自动生成所有武器和方块形状的组合,使用自适应缩放和居中逻辑 */ @ccclass('WeaponBlockTestScript') export class WeaponBlockTestScript extends Component { @property({ type: Node, tooltip: '测试容器节点,用于放置生成的测试方块' }) public testContainer: Node = null; @property([Prefab]) public blockPrefabs: Prefab[] = []; @property({ type: JsonAsset, tooltip: '武器和方块配置JSON文件' }) public weaponsConfigAsset: JsonAsset = null; // 所有武器类型 private readonly WEAPON_TYPES = [ 'pea_shooter', 'sharp_carrot', 'saw_grass', 'watermelon_bomb', 'boomerang_plant', 'hot_pepper', 'cactus_shotgun', 'okra_missile', 'mace_club' ]; // 所有方块形状 private readonly BLOCK_SHAPES = [ 'I', 'H-I', 'L', 'L2', 'L3', 'L4', 'S', 'S-F', 'D-T', 'T' ]; // 稀有度列表 private readonly RARITIES = ['common', 'uncommon', 'rare', 'epic', 'legendary']; private configManager: ConfigManager = null; private weaponsConfig: any = null; private blockSizesConfig: any = null; start() { this.initializeComponents(); this.loadConfigurations(); // 配置加载完成后自动生成武器方块组合 this.scheduleOnce(() => { this.generateAllWeaponBlockCombinations(); }, 0.1); } private initializeComponents() { // 查找组件引用 if (!this.testContainer) { this.testContainer = find('TestContainer'); } // 移除 blockManager 初始化 this.configManager = ConfigManager.getInstance(); this.updateStatus('组件初始化完成'); } private loadConfigurations() { try { this.updateStatus('加载配置文件中...'); // 从装饰器挂载的资源加载武器和方块配置 if (this.weaponsConfigAsset) { const configData = this.weaponsConfigAsset.json; console.log('[WeaponBlockTestScript] 原始配置数据:', configData); console.log('[WeaponBlockTestScript] configData类型:', typeof configData); console.log('[WeaponBlockTestScript] configData.weapons存在:', !!configData.weapons); console.log('[WeaponBlockTestScript] configData.weapons类型:', typeof configData.weapons); console.log('[WeaponBlockTestScript] configData.weapons长度:', configData.weapons?.length); // 直接使用configData,因为weapons.json的结构是 {weapons: [...], blockSizes: [...]} this.weaponsConfig = configData; this.blockSizesConfig = configData; console.log('[WeaponBlockTestScript] 设置后的武器配置:', this.weaponsConfig); console.log('[WeaponBlockTestScript] 设置后的方块配置:', this.blockSizesConfig); console.log('[WeaponBlockTestScript] 预制体数量:', this.blockPrefabs?.length || 0); // 验证第一个武器配置 if (configData.weapons && configData.weapons.length > 0) { console.log('[WeaponBlockTestScript] 第一个武器配置:', configData.weapons[0]); console.log('[WeaponBlockTestScript] 第一个武器ID:', configData.weapons[0].id); } } else { console.warn('[WeaponBlockTestScript] 武器和方块配置资源未挂载'); } this.updateStatus('配置文件加载完成'); } catch (error) { console.error('[WeaponBlockTestScript] 加载配置失败:', error); this.updateStatus('配置文件加载失败: ' + error.message); } } /** * 生成所有武器方块组合 */ public async generateAllWeaponBlockCombinations() { console.log('[WeaponBlockTestScript] 开始生成武器方块组合'); console.log('[WeaponBlockTestScript] 武器配置状态:', !!this.weaponsConfig); console.log('[WeaponBlockTestScript] 方块配置状态:', !!this.blockSizesConfig); console.log('[WeaponBlockTestScript] 容器节点状态:', !!this.testContainer); if (!this.weaponsConfig || !this.blockSizesConfig) { console.error('[WeaponBlockTestScript] 配置未加载,无法生成测试方块'); this.updateStatus('配置未加载,无法生成测试方块'); return; } if (!this.testContainer) { console.error('[WeaponBlockTestScript] 测试容器节点未找到'); this.updateStatus('测试容器节点未找到'); return; } if (!this.blockPrefabs || this.blockPrefabs.length === 0) { console.error('[WeaponBlockTestScript] 没有可用的方块预制体'); this.updateStatus('没有可用的方块预制体'); return; } this.clearTestContainer(); this.updateStatus('开始生成所有武器方块组合...'); let totalGenerated = 0; const startX = -500; const startY = 300; const spacingX = 120; const spacingY = 150; const itemsPerRow = 10; for (let weaponIndex = 0; weaponIndex < this.WEAPON_TYPES.length; weaponIndex++) { const weaponType = this.WEAPON_TYPES[weaponIndex]; for (let shapeIndex = 0; shapeIndex < this.BLOCK_SHAPES.length; shapeIndex++) { const shapeId = this.BLOCK_SHAPES[shapeIndex]; // 计算位置 const row = Math.floor(totalGenerated / itemsPerRow); const col = totalGenerated % itemsPerRow; const posX = startX + col * spacingX; const posY = startY - row * spacingY; // 生成测试方块 await this.generateTestBlock(weaponType, shapeId, new Vec3(posX, posY, 0)); totalGenerated++; // 更新状态 this.updateStatus(`生成进度: ${totalGenerated}/${this.WEAPON_TYPES.length * this.BLOCK_SHAPES.length}`); // 每生成10个方块暂停一帧,避免卡顿 if (totalGenerated % 10 === 0) { await this.waitOneFrame(); } } } this.updateStatus(`生成完成!共生成 ${totalGenerated} 个测试方块`); } /** * 生成特定武器和形状的测试方块 */ private async generateTestBlock(weaponType: string, shapeId: string, position: Vec3) { try { // 获取武器配置 const weaponConfig = this.getWeaponConfig(weaponType); if (!weaponConfig) { console.warn(`[WeaponBlockTestScript] 未找到武器配置: ${weaponType}`); return; } // 获取形状配置 const shapeConfig = this.getShapeConfig(shapeId); if (!shapeConfig) { console.warn(`[WeaponBlockTestScript] 未找到形状配置: ${shapeId}`); return; } // 查找匹配的预制体 const prefab = this.findMatchingPrefab(shapeConfig); if (!prefab) { console.warn(`[WeaponBlockTestScript] 未找到匹配的预制体: ${shapeId}`); return; } // 实例化方块 const block = instantiate(prefab); block.setParent(this.testContainer); block.setPosition(position); // 设置武器配置 this.setupBlockWeapon(block, weaponConfig); // 设置形状信息 this.setupBlockShape(block, shapeConfig); // 设置稀有度(固定使用common) const rarity = 'common'; this.setupBlockRarity(block, rarity); } catch (error) { console.error(`[WeaponBlockTestScript] 生成测试方块失败 ${weaponType}-${shapeId}:`, error); } } private getWeaponConfig(weaponType: string): WeaponConfig | null { console.log(`[WeaponBlockTestScript] 查找武器配置: ${weaponType}`); console.log('[WeaponBlockTestScript] 当前武器配置结构:', this.weaponsConfig); if (!this.weaponsConfig) { console.warn('[WeaponBlockTestScript] 武器配置为空'); return null; } // weapons.json的结构是 {weapons: [...], blockSizes: [...]} // 所以我们需要访问 this.weaponsConfig.weapons let weaponsList = null; if (this.weaponsConfig.weapons && Array.isArray(this.weaponsConfig.weapons)) { weaponsList = this.weaponsConfig.weapons; console.log(`[WeaponBlockTestScript] 使用weapons数组,长度: ${weaponsList.length}`); } else if (Array.isArray(this.weaponsConfig)) { weaponsList = this.weaponsConfig; console.log(`[WeaponBlockTestScript] 直接使用配置数组,长度: ${weaponsList.length}`); } else { console.warn('[WeaponBlockTestScript] 无法识别的武器配置结构'); console.log('[WeaponBlockTestScript] weaponsConfig类型:', typeof this.weaponsConfig); console.log('[WeaponBlockTestScript] weaponsConfig.weapons存在:', !!this.weaponsConfig.weapons); return null; } console.log(`[WeaponBlockTestScript] 在${weaponsList.length}个武器中查找: ${weaponType}`); // 打印前几个武器的ID用于调试 if (weaponsList.length > 0) { console.log('[WeaponBlockTestScript] 前3个武器ID:', weaponsList.slice(0, 3).map((w: any) => w.id)); } const result = weaponsList.find((weapon: any) => weapon.id === weaponType) || null; console.log(`[WeaponBlockTestScript] 武器配置查找结果 ${weaponType}:`, result ? '找到' : '未找到'); if (result) { console.log(`[WeaponBlockTestScript] 找到的武器名称: ${result.name}`); } return result; } private getShapeConfig(shapeId: string): any { console.log(`[WeaponBlockTestScript] 查找形状配置: ${shapeId}`); console.log('[WeaponBlockTestScript] 当前方块配置结构:', this.blockSizesConfig); if (!this.blockSizesConfig) { console.warn('[WeaponBlockTestScript] 方块配置为空'); return null; } // 尝试不同的配置结构 let shapesList = null; if (this.blockSizesConfig.blockSizes) { shapesList = this.blockSizesConfig.blockSizes; } else if (Array.isArray(this.blockSizesConfig)) { shapesList = this.blockSizesConfig; } else { console.warn('[WeaponBlockTestScript] 无法识别的方块配置结构'); return null; } const result = shapesList.find((shape: any) => shape.id === shapeId) || null; console.log(`[WeaponBlockTestScript] 形状配置查找结果 ${shapeId}:`, result); return result; } private findMatchingPrefab(shapeConfig: any): Prefab | null { if (!this.blockPrefabs || this.blockPrefabs.length === 0) { console.warn('[WeaponBlockTestScript] 没有可用的方块预制体'); return null; } console.log(`[WeaponBlockTestScript] 查找预制体,形状: ${shapeConfig.id}, 网格数: ${shapeConfig.gridCount}`); console.log(`[WeaponBlockTestScript] 可用预制体数量: ${this.blockPrefabs.length}`); // 根据网格数量匹配预制体 const targetGridCount = shapeConfig.gridCount || 4; // 如果只有一个预制体,直接使用它 if (this.blockPrefabs.length === 1) { console.log('[WeaponBlockTestScript] 只有一个预制体,直接使用'); return this.blockPrefabs[0]; } // 尝试根据网格数量匹配 for (let i = 0; i < this.blockPrefabs.length; i++) { const prefab = this.blockPrefabs[i]; if (prefab) { console.log(`[WeaponBlockTestScript] 使用预制体索引: ${i}`); // 这里可以添加更精确的形状匹配逻辑 // 暂时根据索引循环使用不同的预制体 const shapeIndex = this.BLOCK_SHAPES.indexOf(shapeConfig.id); if (shapeIndex >= 0 && shapeIndex < this.blockPrefabs.length) { return this.blockPrefabs[shapeIndex]; } return prefab; } } return this.blockPrefabs[0] || null; } private setupBlockWeapon(block: Node, weaponConfig: WeaponConfig) { // 存储武器配置到方块节点 block['weaponConfig'] = weaponConfig; block['weaponId'] = weaponConfig.id; // 直接调用武器外观设置方法 this.setupBlockWeaponVisual(block, weaponConfig); } private setupBlockShape(block: Node, shapeConfig: any) { // 存储形状配置到方块节点 block['shapeConfig'] = shapeConfig; block['shapeId'] = shapeConfig.id; block['shapeName'] = shapeConfig.name; } private setupBlockRarity(block: Node, rarity: string) { // 存储稀有度到方块节点 block['rarity'] = rarity; // 直接调用稀有度颜色应用方法 this.applyBlockRarityColor(block, rarity); } // 设置方块的武器外观 private setupBlockWeaponVisual(block: Node, weaponConfig: WeaponConfig) { // 确保方块节点上也有 weaponConfig 属性 block['weaponConfig'] = weaponConfig; // 设置方块的稀有度颜色 this.applyBlockRarityColor(block, weaponConfig.rarity || 'common'); // 加载武器图标 this.loadWeaponIcon(block, weaponConfig); } // 应用方块稀有度颜色 private applyBlockRarityColor(block: Node, rarity: string) { // Add null safety check for block if (!block || !block.isValid) { return; } const sprite = block.getComponent(Sprite); if (!sprite || !sprite.isValid) { return; } // 根据稀有度设置颜色 let color: Color; switch (rarity) { case 'common': color = new Color(255, 255, 255); // 白色 break; case 'uncommon': color = new Color(0, 255, 0); // 绿色 break; case 'rare': color = new Color(0, 100, 255); // 蓝色 break; case 'epic': color = new Color(160, 32, 240); // 紫色 break; case 'legendary': color = new Color(255, 165, 0); // 橙色 break; default: color = new Color(255, 255, 255); // 默认白色 } sprite.color = color; console.log(`[WeaponBlockTestScript] 设置方块稀有度颜色: ${rarity}`, color); } // 加载武器图标 /** * 应用自适应缩放和居中逻辑 * 基于武器精灵的原始尺寸和方块的ContentSize自动计算缩放比例 * 并将武器图标居中显示 */ private applyAdaptiveScalingAndCentering(weaponNode: Node, block: Node): void { if (!weaponNode || !block) { console.warn('[WeaponBlockTestScript] applyAdaptiveScalingAndCentering: 无效的节点参数'); return; } const weaponTransform = weaponNode.getComponent(UITransform); const blockTransform = block.getComponent(UITransform); if (!weaponTransform || !blockTransform) { console.warn('[WeaponBlockTestScript] applyAdaptiveScalingAndCentering: 缺少UITransform组件'); return; } // 获取武器精灵的原始尺寸 const weaponSprite = weaponNode.getComponent(Sprite); if (!weaponSprite || !weaponSprite.spriteFrame) { console.warn('[WeaponBlockTestScript] applyAdaptiveScalingAndCentering: 武器精灵或SpriteFrame无效'); return; } const originalSize = weaponSprite.spriteFrame.originalSize; const blockContentSize = blockTransform.contentSize; // 计算缩放比例,保持10%的边距 const marginFactor = 0.9; // 90%的空间用于武器图标,10%作为边距 const scaleX = (blockContentSize.width * marginFactor) / originalSize.width; const scaleY = (blockContentSize.height * marginFactor) / originalSize.height; const finalScale = Math.min(scaleX, scaleY); // 使用较小的缩放比例以保持宽高比 // 应用缩放 weaponNode.setScale(finalScale, finalScale, 1); // 居中武器图标 weaponNode.setPosition(0, 0, 0); console.log(`[WeaponBlockTestScript] 自适应缩放应用: 原始尺寸(${originalSize.width}x${originalSize.height}), 方块尺寸(${blockContentSize.width}x${blockContentSize.height}), 最终缩放: ${finalScale.toFixed(3)}`); } private loadWeaponIcon(block: Node, weaponConfig: WeaponConfig) { // 根据预制体结构:WeaponBlock -> B1 -> Weapon const b1Node = block.getChildByName('B1'); if (!b1Node) { console.warn('[WeaponBlockTestScript] 找不到B1节点'); return; } const weaponNode = b1Node.getChildByName('Weapon'); if (!weaponNode) { console.warn('[WeaponBlockTestScript] 找不到Weapon节点'); return; } const weaponSprite = weaponNode.getComponent(Sprite); if (!weaponSprite) { console.warn('[WeaponBlockTestScript] Weapon节点上没有Sprite组件'); return; } // 获取武器配置中的图片路径 const spritePath = weaponConfig.visualConfig?.weaponSprites; if (!spritePath) { console.warn(`[WeaponBlockTestScript] 武器 ${weaponConfig.name} 没有配置图片信息`); return; } // 正确的SpriteFrame子资源路径 const spriteFramePath = `${spritePath}/spriteFrame`; // 加载SpriteFrame子资源 resources.load(spriteFramePath, SpriteFrame, (err, spriteFrame) => { if (err) { console.warn(`[WeaponBlockTestScript] 加载武器图片失败: ${spriteFramePath}`, err); return; } // Add comprehensive null safety checks before setting spriteFrame if (weaponSprite && weaponSprite.isValid && weaponNode && weaponNode.isValid && block && block.isValid && spriteFrame && spriteFrame.isValid) { weaponSprite.spriteFrame = spriteFrame; // 应用自适应缩放和居中逻辑 this.applyAdaptiveScalingAndCentering(weaponNode, block); console.log(`[WeaponBlockTestScript] 成功加载武器图标: ${weaponConfig.name}`); } }); } /** * 生成特定武器类型的所有形状组合 */ public async generateWeaponShapeCombinations(weaponType: string) { if (this.WEAPON_TYPES.indexOf(weaponType) === -1) { this.updateStatus(`无效的武器类型: ${weaponType}`); return; } this.clearTestContainer(); this.updateStatus(`生成武器 ${weaponType} 的所有形状组合...`); const startX = -400; const startY = 200; const spacingX = 100; const spacingY = 120; const itemsPerRow = 5; for (let i = 0; i < this.BLOCK_SHAPES.length; i++) { const shapeId = this.BLOCK_SHAPES[i]; const row = Math.floor(i / itemsPerRow); const col = i % itemsPerRow; const posX = startX + col * spacingX; const posY = startY - row * spacingY; await this.generateTestBlock(weaponType, shapeId, new Vec3(posX, posY, 0)); this.updateStatus(`生成进度: ${i + 1}/${this.BLOCK_SHAPES.length}`); if ((i + 1) % 5 === 0) { await this.waitOneFrame(); } } this.updateStatus(`${weaponType} 的所有形状组合生成完成!`); } /** * 生成特定形状的所有武器组合 */ public async generateShapeWeaponCombinations(shapeId: string) { if (this.BLOCK_SHAPES.indexOf(shapeId) === -1) { this.updateStatus(`无效的形状ID: ${shapeId}`); return; } this.clearTestContainer(); this.updateStatus(`生成形状 ${shapeId} 的所有武器组合...`); const startX = -400; const startY = 200; const spacingX = 100; const spacingY = 120; const itemsPerRow = 3; for (let i = 0; i < this.WEAPON_TYPES.length; i++) { const weaponType = this.WEAPON_TYPES[i]; const row = Math.floor(i / itemsPerRow); const col = i % itemsPerRow; const posX = startX + col * spacingX; const posY = startY - row * spacingY; await this.generateTestBlock(weaponType, shapeId, new Vec3(posX, posY, 0)); this.updateStatus(`生成进度: ${i + 1}/${this.WEAPON_TYPES.length}`); if ((i + 1) % 3 === 0) { await this.waitOneFrame(); } } this.updateStatus(`形状 ${shapeId} 的所有武器组合生成完成!`); } /** * 清空测试容器 */ public clearTestContainer() { if (this.testContainer) { this.testContainer.removeAllChildren(); } } /** * 更新状态显示 */ private updateStatus(message: string) { console.log(`[WeaponBlockTestScript] ${message}`); } /** * 等待一帧 */ private waitOneFrame(): Promise { return new Promise(resolve => { this.scheduleOnce(() => { resolve(); }, 0); }); } /** * 导出当前测试结果为JSON(用于调试) */ public exportTestResults(): string { const results = { timestamp: new Date().toISOString(), weaponTypes: this.WEAPON_TYPES, blockShapes: this.BLOCK_SHAPES, rarities: this.RARITIES, totalCombinations: this.WEAPON_TYPES.length * this.BLOCK_SHAPES.length, generatedBlocks: this.testContainer ? this.testContainer.children.length : 0 }; const jsonString = JSON.stringify(results, null, 2); console.log('[WeaponBlockTestScript] 测试结果:', jsonString); return jsonString; } }