WeaponBlockTestScript.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. import { _decorator, Component, Node, Prefab, instantiate, Vec3, find, JsonAsset, Sprite, Color, SpriteFrame, resources, UITransform } from 'cc';
  2. import { ConfigManager, WeaponConfig } from '../Core/ConfigManager';
  3. const { ccclass, property } = _decorator;
  4. /**
  5. * 武器方块测试脚本
  6. * 用于自动生成所有武器和方块形状的组合,使用自适应缩放和居中逻辑
  7. */
  8. @ccclass('WeaponBlockTestScript')
  9. export class WeaponBlockTestScript extends Component {
  10. @property({
  11. type: Node,
  12. tooltip: '测试容器节点,用于放置生成的测试方块'
  13. })
  14. public testContainer: Node = null;
  15. @property([Prefab])
  16. public blockPrefabs: Prefab[] = [];
  17. @property({
  18. type: JsonAsset,
  19. tooltip: '武器和方块配置JSON文件'
  20. })
  21. public weaponsConfigAsset: JsonAsset = null;
  22. // 所有武器类型
  23. private readonly WEAPON_TYPES = [
  24. 'pea_shooter',
  25. 'sharp_carrot',
  26. 'saw_grass',
  27. 'watermelon_bomb',
  28. 'boomerang_plant',
  29. 'hot_pepper',
  30. 'cactus_shotgun',
  31. 'okra_missile',
  32. 'mace_club'
  33. ];
  34. // 所有方块形状
  35. private readonly BLOCK_SHAPES = [
  36. 'I', 'H-I', 'L', 'L2', 'L3', 'L4', 'S', 'S-F', 'D-T', 'T'
  37. ];
  38. // 稀有度列表
  39. private readonly RARITIES = ['common', 'uncommon', 'rare', 'epic'];
  40. private configManager: ConfigManager = null;
  41. private weaponsConfig: any = null;
  42. private blockSizesConfig: any = null;
  43. start() {
  44. this.initializeComponents();
  45. this.loadConfigurations();
  46. // 配置加载完成后自动生成武器方块组合
  47. this.scheduleOnce(() => {
  48. this.generateAllWeaponBlockCombinations();
  49. }, 0.1);
  50. }
  51. private initializeComponents() {
  52. // 查找组件引用
  53. if (!this.testContainer) {
  54. this.testContainer = find('TestContainer');
  55. }
  56. // 移除 blockManager 初始化
  57. this.configManager = ConfigManager.getInstance();
  58. this.updateStatus('组件初始化完成');
  59. }
  60. private loadConfigurations() {
  61. try {
  62. this.updateStatus('加载配置文件中...');
  63. // 从装饰器挂载的资源加载武器和方块配置
  64. if (this.weaponsConfigAsset) {
  65. const configData = this.weaponsConfigAsset.json;
  66. console.log('[WeaponBlockTestScript] 原始配置数据:', configData);
  67. console.log('[WeaponBlockTestScript] configData类型:', typeof configData);
  68. console.log('[WeaponBlockTestScript] configData.weapons存在:', !!configData.weapons);
  69. console.log('[WeaponBlockTestScript] configData.weapons类型:', typeof configData.weapons);
  70. console.log('[WeaponBlockTestScript] configData.weapons长度:', configData.weapons?.length);
  71. // 直接使用configData,因为weapons.json的结构是 {weapons: [...], blockSizes: [...]}
  72. this.weaponsConfig = configData;
  73. this.blockSizesConfig = configData;
  74. console.log('[WeaponBlockTestScript] 设置后的武器配置:', this.weaponsConfig);
  75. console.log('[WeaponBlockTestScript] 设置后的方块配置:', this.blockSizesConfig);
  76. console.log('[WeaponBlockTestScript] 预制体数量:', this.blockPrefabs?.length || 0);
  77. // 验证第一个武器配置
  78. if (configData.weapons && configData.weapons.length > 0) {
  79. console.log('[WeaponBlockTestScript] 第一个武器配置:', configData.weapons[0]);
  80. console.log('[WeaponBlockTestScript] 第一个武器ID:', configData.weapons[0].id);
  81. }
  82. } else {
  83. console.warn('[WeaponBlockTestScript] 武器和方块配置资源未挂载');
  84. }
  85. this.updateStatus('配置文件加载完成');
  86. } catch (error) {
  87. console.error('[WeaponBlockTestScript] 加载配置失败:', error);
  88. this.updateStatus('配置文件加载失败: ' + error.message);
  89. }
  90. }
  91. /**
  92. * 生成所有武器方块组合
  93. */
  94. public async generateAllWeaponBlockCombinations() {
  95. console.log('[WeaponBlockTestScript] 开始生成武器方块组合');
  96. console.log('[WeaponBlockTestScript] 武器配置状态:', !!this.weaponsConfig);
  97. console.log('[WeaponBlockTestScript] 方块配置状态:', !!this.blockSizesConfig);
  98. console.log('[WeaponBlockTestScript] 容器节点状态:', !!this.testContainer);
  99. if (!this.weaponsConfig || !this.blockSizesConfig) {
  100. console.error('[WeaponBlockTestScript] 配置未加载,无法生成测试方块');
  101. this.updateStatus('配置未加载,无法生成测试方块');
  102. return;
  103. }
  104. if (!this.testContainer) {
  105. console.error('[WeaponBlockTestScript] 测试容器节点未找到');
  106. this.updateStatus('测试容器节点未找到');
  107. return;
  108. }
  109. if (!this.blockPrefabs || this.blockPrefabs.length === 0) {
  110. console.error('[WeaponBlockTestScript] 没有可用的方块预制体');
  111. this.updateStatus('没有可用的方块预制体');
  112. return;
  113. }
  114. this.clearTestContainer();
  115. this.updateStatus('开始生成所有武器方块组合...');
  116. let totalGenerated = 0;
  117. const startX = -500;
  118. const startY = 300;
  119. const spacingX = 120;
  120. const spacingY = 150;
  121. const itemsPerRow = 10;
  122. for (let weaponIndex = 0; weaponIndex < this.WEAPON_TYPES.length; weaponIndex++) {
  123. const weaponType = this.WEAPON_TYPES[weaponIndex];
  124. for (let shapeIndex = 0; shapeIndex < this.BLOCK_SHAPES.length; shapeIndex++) {
  125. const shapeId = this.BLOCK_SHAPES[shapeIndex];
  126. // 计算位置
  127. const row = Math.floor(totalGenerated / itemsPerRow);
  128. const col = totalGenerated % itemsPerRow;
  129. const posX = startX + col * spacingX;
  130. const posY = startY - row * spacingY;
  131. // 生成测试方块
  132. await this.generateTestBlock(weaponType, shapeId, new Vec3(posX, posY, 0));
  133. totalGenerated++;
  134. // 更新状态
  135. this.updateStatus(`生成进度: ${totalGenerated}/${this.WEAPON_TYPES.length * this.BLOCK_SHAPES.length}`);
  136. // 每生成10个方块暂停一帧,避免卡顿
  137. if (totalGenerated % 10 === 0) {
  138. await this.waitOneFrame();
  139. }
  140. }
  141. }
  142. this.updateStatus(`生成完成!共生成 ${totalGenerated} 个测试方块`);
  143. }
  144. /**
  145. * 生成特定武器和形状的测试方块
  146. */
  147. private async generateTestBlock(weaponType: string, shapeId: string, position: Vec3) {
  148. try {
  149. // 获取武器配置
  150. const weaponConfig = this.getWeaponConfig(weaponType);
  151. if (!weaponConfig) {
  152. console.warn(`[WeaponBlockTestScript] 未找到武器配置: ${weaponType}`);
  153. return;
  154. }
  155. // 获取形状配置
  156. const shapeConfig = this.getShapeConfig(shapeId);
  157. if (!shapeConfig) {
  158. console.warn(`[WeaponBlockTestScript] 未找到形状配置: ${shapeId}`);
  159. return;
  160. }
  161. // 查找匹配的预制体
  162. const prefab = this.findMatchingPrefab(shapeConfig);
  163. if (!prefab) {
  164. console.warn(`[WeaponBlockTestScript] 未找到匹配的预制体: ${shapeId}`);
  165. return;
  166. }
  167. // 实例化方块
  168. const block = instantiate(prefab);
  169. block.setParent(this.testContainer);
  170. block.setPosition(position);
  171. // 设置武器配置
  172. this.setupBlockWeapon(block, weaponConfig);
  173. // 设置形状信息
  174. this.setupBlockShape(block, shapeConfig);
  175. // 设置稀有度(固定使用common)
  176. const rarity = 'common';
  177. this.setupBlockRarity(block, rarity);
  178. } catch (error) {
  179. console.error(`[WeaponBlockTestScript] 生成测试方块失败 ${weaponType}-${shapeId}:`, error);
  180. }
  181. }
  182. private getWeaponConfig(weaponType: string): WeaponConfig | null {
  183. console.log(`[WeaponBlockTestScript] 查找武器配置: ${weaponType}`);
  184. console.log('[WeaponBlockTestScript] 当前武器配置结构:', this.weaponsConfig);
  185. if (!this.weaponsConfig) {
  186. console.warn('[WeaponBlockTestScript] 武器配置为空');
  187. return null;
  188. }
  189. // weapons.json的结构是 {weapons: [...], blockSizes: [...]}
  190. // 所以我们需要访问 this.weaponsConfig.weapons
  191. let weaponsList = null;
  192. if (this.weaponsConfig.weapons && Array.isArray(this.weaponsConfig.weapons)) {
  193. weaponsList = this.weaponsConfig.weapons;
  194. console.log(`[WeaponBlockTestScript] 使用weapons数组,长度: ${weaponsList.length}`);
  195. } else if (Array.isArray(this.weaponsConfig)) {
  196. weaponsList = this.weaponsConfig;
  197. console.log(`[WeaponBlockTestScript] 直接使用配置数组,长度: ${weaponsList.length}`);
  198. } else {
  199. console.warn('[WeaponBlockTestScript] 无法识别的武器配置结构');
  200. console.log('[WeaponBlockTestScript] weaponsConfig类型:', typeof this.weaponsConfig);
  201. console.log('[WeaponBlockTestScript] weaponsConfig.weapons存在:', !!this.weaponsConfig.weapons);
  202. return null;
  203. }
  204. console.log(`[WeaponBlockTestScript] 在${weaponsList.length}个武器中查找: ${weaponType}`);
  205. // 打印前几个武器的ID用于调试
  206. if (weaponsList.length > 0) {
  207. console.log('[WeaponBlockTestScript] 前3个武器ID:', weaponsList.slice(0, 3).map((w: any) => w.id));
  208. }
  209. const result = weaponsList.find((weapon: any) => weapon.id === weaponType) || null;
  210. console.log(`[WeaponBlockTestScript] 武器配置查找结果 ${weaponType}:`, result ? '找到' : '未找到');
  211. if (result) {
  212. console.log(`[WeaponBlockTestScript] 找到的武器名称: ${result.name}`);
  213. }
  214. return result;
  215. }
  216. private getShapeConfig(shapeId: string): any {
  217. console.log(`[WeaponBlockTestScript] 查找形状配置: ${shapeId}`);
  218. console.log('[WeaponBlockTestScript] 当前方块配置结构:', this.blockSizesConfig);
  219. if (!this.blockSizesConfig) {
  220. console.warn('[WeaponBlockTestScript] 方块配置为空');
  221. return null;
  222. }
  223. // 尝试不同的配置结构
  224. let shapesList = null;
  225. if (this.blockSizesConfig.blockSizes) {
  226. shapesList = this.blockSizesConfig.blockSizes;
  227. } else if (Array.isArray(this.blockSizesConfig)) {
  228. shapesList = this.blockSizesConfig;
  229. } else {
  230. console.warn('[WeaponBlockTestScript] 无法识别的方块配置结构');
  231. return null;
  232. }
  233. const result = shapesList.find((shape: any) => shape.id === shapeId) || null;
  234. console.log(`[WeaponBlockTestScript] 形状配置查找结果 ${shapeId}:`, result);
  235. return result;
  236. }
  237. private findMatchingPrefab(shapeConfig: any): Prefab | null {
  238. if (!this.blockPrefabs || this.blockPrefabs.length === 0) {
  239. console.warn('[WeaponBlockTestScript] 没有可用的方块预制体');
  240. return null;
  241. }
  242. console.log(`[WeaponBlockTestScript] 查找预制体,形状: ${shapeConfig.id}, 网格数: ${shapeConfig.gridCount}`);
  243. console.log(`[WeaponBlockTestScript] 可用预制体数量: ${this.blockPrefabs.length}`);
  244. // 根据网格数量匹配预制体
  245. const targetGridCount = shapeConfig.gridCount || 4;
  246. // 如果只有一个预制体,直接使用它
  247. if (this.blockPrefabs.length === 1) {
  248. console.log('[WeaponBlockTestScript] 只有一个预制体,直接使用');
  249. return this.blockPrefabs[0];
  250. }
  251. // 尝试根据网格数量匹配
  252. for (let i = 0; i < this.blockPrefabs.length; i++) {
  253. const prefab = this.blockPrefabs[i];
  254. if (prefab) {
  255. console.log(`[WeaponBlockTestScript] 使用预制体索引: ${i}`);
  256. // 这里可以添加更精确的形状匹配逻辑
  257. // 暂时根据索引循环使用不同的预制体
  258. const shapeIndex = this.BLOCK_SHAPES.indexOf(shapeConfig.id);
  259. if (shapeIndex >= 0 && shapeIndex < this.blockPrefabs.length) {
  260. return this.blockPrefabs[shapeIndex];
  261. }
  262. return prefab;
  263. }
  264. }
  265. return this.blockPrefabs[0] || null;
  266. }
  267. private setupBlockWeapon(block: Node, weaponConfig: WeaponConfig) {
  268. // 存储武器配置到方块节点
  269. block['weaponConfig'] = weaponConfig;
  270. block['weaponId'] = weaponConfig.id;
  271. // 直接调用武器外观设置方法
  272. this.setupBlockWeaponVisual(block, weaponConfig);
  273. }
  274. private setupBlockShape(block: Node, shapeConfig: any) {
  275. // 存储形状配置到方块节点
  276. block['shapeConfig'] = shapeConfig;
  277. block['shapeId'] = shapeConfig.id;
  278. block['shapeName'] = shapeConfig.name;
  279. }
  280. private setupBlockRarity(block: Node, rarity: string) {
  281. // 存储稀有度到方块节点
  282. block['rarity'] = rarity;
  283. // 直接调用稀有度颜色应用方法
  284. this.applyBlockRarityColor(block, rarity);
  285. }
  286. // 设置方块的武器外观
  287. private setupBlockWeaponVisual(block: Node, weaponConfig: WeaponConfig) {
  288. // 确保方块节点上也有 weaponConfig 属性
  289. block['weaponConfig'] = weaponConfig;
  290. // 设置方块的稀有度颜色
  291. this.applyBlockRarityColor(block, weaponConfig.rarity || 'common');
  292. // 加载武器图标
  293. this.loadWeaponIcon(block, weaponConfig);
  294. }
  295. // 应用方块稀有度颜色
  296. private applyBlockRarityColor(block: Node, rarity: string) {
  297. // Add null safety check for block
  298. if (!block || !block.isValid) {
  299. return;
  300. }
  301. // 新的预制体结构:Sprite组件在Node子节点上
  302. const nodeChild = block.getChildByName('Node');
  303. if (!nodeChild) {
  304. console.warn('[WeaponBlockTestScript] 方块节点没有找到Node子节点');
  305. return;
  306. }
  307. const sprite = nodeChild.getComponent(Sprite);
  308. if (!sprite || !sprite.isValid) {
  309. console.warn('[WeaponBlockTestScript] Node子节点没有Sprite组件');
  310. return;
  311. }
  312. // 根据稀有度设置颜色
  313. let color: Color;
  314. switch (rarity) {
  315. case 'common':
  316. color = new Color(255, 255, 255); // 白色
  317. break;
  318. case 'uncommon':
  319. color = new Color(0, 255, 0); // 绿色
  320. break;
  321. case 'rare':
  322. color = new Color(0, 100, 255); // 蓝色
  323. break;
  324. case 'epic':
  325. color = new Color(160, 32, 240); // 紫色
  326. break;
  327. default:
  328. color = new Color(255, 255, 255); // 默认白色
  329. }
  330. sprite.color = color;
  331. console.log(`[WeaponBlockTestScript] 设置方块稀有度颜色: ${rarity}`, color);
  332. }
  333. // 加载武器图标
  334. private loadWeaponIcon(block: Node, weaponConfig: WeaponConfig) {
  335. // 根据预制体结构:WeaponBlock -> B1 -> Weapon
  336. const b1Node = block.getChildByName('B1');
  337. if (!b1Node) {
  338. console.warn('[WeaponBlockTestScript] 找不到B1节点');
  339. return;
  340. }
  341. const weaponNode = b1Node.getChildByName('Weapon');
  342. if (!weaponNode) {
  343. console.warn('[WeaponBlockTestScript] 找不到Weapon节点');
  344. return;
  345. }
  346. const weaponSprite = weaponNode.getComponent(Sprite);
  347. if (!weaponSprite) {
  348. console.warn('[WeaponBlockTestScript] Weapon节点上没有Sprite组件');
  349. return;
  350. }
  351. // 获取武器配置中的图片路径
  352. const spritePath = weaponConfig.visualConfig?.weaponSprites;
  353. if (!spritePath) {
  354. console.warn(`[WeaponBlockTestScript] 武器 ${weaponConfig.name} 没有配置图片信息`);
  355. return;
  356. }
  357. // 正确的SpriteFrame子资源路径
  358. const spriteFramePath = `${spritePath}/spriteFrame`;
  359. // 加载SpriteFrame子资源
  360. resources.load(spriteFramePath, SpriteFrame, (err, spriteFrame) => {
  361. if (err) {
  362. console.warn(`[WeaponBlockTestScript] 加载武器图片失败: ${spriteFramePath}`, err);
  363. return;
  364. }
  365. // Add comprehensive null safety checks before setting spriteFrame
  366. if (weaponSprite && weaponSprite.isValid &&
  367. weaponNode && weaponNode.isValid &&
  368. block && block.isValid &&
  369. spriteFrame && spriteFrame.isValid) {
  370. weaponSprite.spriteFrame = spriteFrame;
  371. console.log(`[WeaponBlockTestScript] 成功加载武器图标: ${weaponConfig.name}`);
  372. }
  373. });
  374. }
  375. /**
  376. * 生成特定武器类型的所有形状组合
  377. */
  378. public async generateWeaponShapeCombinations(weaponType: string) {
  379. if (this.WEAPON_TYPES.indexOf(weaponType) === -1) {
  380. this.updateStatus(`无效的武器类型: ${weaponType}`);
  381. return;
  382. }
  383. this.clearTestContainer();
  384. this.updateStatus(`生成武器 ${weaponType} 的所有形状组合...`);
  385. const startX = -400;
  386. const startY = 200;
  387. const spacingX = 100;
  388. const spacingY = 120;
  389. const itemsPerRow = 5;
  390. for (let i = 0; i < this.BLOCK_SHAPES.length; i++) {
  391. const shapeId = this.BLOCK_SHAPES[i];
  392. const row = Math.floor(i / itemsPerRow);
  393. const col = i % itemsPerRow;
  394. const posX = startX + col * spacingX;
  395. const posY = startY - row * spacingY;
  396. await this.generateTestBlock(weaponType, shapeId, new Vec3(posX, posY, 0));
  397. this.updateStatus(`生成进度: ${i + 1}/${this.BLOCK_SHAPES.length}`);
  398. if ((i + 1) % 5 === 0) {
  399. await this.waitOneFrame();
  400. }
  401. }
  402. this.updateStatus(`${weaponType} 的所有形状组合生成完成!`);
  403. }
  404. /**
  405. * 生成特定形状的所有武器组合
  406. */
  407. public async generateShapeWeaponCombinations(shapeId: string) {
  408. if (this.BLOCK_SHAPES.indexOf(shapeId) === -1) {
  409. this.updateStatus(`无效的形状ID: ${shapeId}`);
  410. return;
  411. }
  412. this.clearTestContainer();
  413. this.updateStatus(`生成形状 ${shapeId} 的所有武器组合...`);
  414. const startX = -400;
  415. const startY = 200;
  416. const spacingX = 100;
  417. const spacingY = 120;
  418. const itemsPerRow = 3;
  419. for (let i = 0; i < this.WEAPON_TYPES.length; i++) {
  420. const weaponType = this.WEAPON_TYPES[i];
  421. const row = Math.floor(i / itemsPerRow);
  422. const col = i % itemsPerRow;
  423. const posX = startX + col * spacingX;
  424. const posY = startY - row * spacingY;
  425. await this.generateTestBlock(weaponType, shapeId, new Vec3(posX, posY, 0));
  426. this.updateStatus(`生成进度: ${i + 1}/${this.WEAPON_TYPES.length}`);
  427. if ((i + 1) % 3 === 0) {
  428. await this.waitOneFrame();
  429. }
  430. }
  431. this.updateStatus(`形状 ${shapeId} 的所有武器组合生成完成!`);
  432. }
  433. /**
  434. * 清空测试容器
  435. */
  436. public clearTestContainer() {
  437. if (this.testContainer) {
  438. this.testContainer.removeAllChildren();
  439. }
  440. }
  441. /**
  442. * 更新状态显示
  443. */
  444. private updateStatus(message: string) {
  445. console.log(`[WeaponBlockTestScript] ${message}`);
  446. }
  447. /**
  448. * 等待一帧
  449. */
  450. private waitOneFrame(): Promise<void> {
  451. return new Promise(resolve => {
  452. this.scheduleOnce(() => {
  453. resolve();
  454. }, 0);
  455. });
  456. }
  457. /**
  458. * 导出当前测试结果为JSON(用于调试)
  459. */
  460. public exportTestResults(): string {
  461. const results = {
  462. timestamp: new Date().toISOString(),
  463. weaponTypes: this.WEAPON_TYPES,
  464. blockShapes: this.BLOCK_SHAPES,
  465. rarities: this.RARITIES,
  466. totalCombinations: this.WEAPON_TYPES.length * this.BLOCK_SHAPES.length,
  467. generatedBlocks: this.testContainer ? this.testContainer.children.length : 0
  468. };
  469. const jsonString = JSON.stringify(results, null, 2);
  470. console.log('[WeaponBlockTestScript] 测试结果:', jsonString);
  471. return jsonString;
  472. }
  473. }