WeaponBlockTestScript.ts 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  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. const sprite = block.getComponent(Sprite);
  302. if (!sprite || !sprite.isValid) {
  303. return;
  304. }
  305. // 根据稀有度设置颜色
  306. let color: Color;
  307. switch (rarity) {
  308. case 'common':
  309. color = new Color(255, 255, 255); // 白色
  310. break;
  311. case 'uncommon':
  312. color = new Color(0, 255, 0); // 绿色
  313. break;
  314. case 'rare':
  315. color = new Color(0, 100, 255); // 蓝色
  316. break;
  317. case 'epic':
  318. color = new Color(160, 32, 240); // 紫色
  319. break;
  320. default:
  321. color = new Color(255, 255, 255); // 默认白色
  322. }
  323. sprite.color = color;
  324. console.log(`[WeaponBlockTestScript] 设置方块稀有度颜色: ${rarity}`, color);
  325. }
  326. // 加载武器图标
  327. private loadWeaponIcon(block: Node, weaponConfig: WeaponConfig) {
  328. // 根据预制体结构:WeaponBlock -> B1 -> Weapon
  329. const b1Node = block.getChildByName('B1');
  330. if (!b1Node) {
  331. console.warn('[WeaponBlockTestScript] 找不到B1节点');
  332. return;
  333. }
  334. const weaponNode = b1Node.getChildByName('Weapon');
  335. if (!weaponNode) {
  336. console.warn('[WeaponBlockTestScript] 找不到Weapon节点');
  337. return;
  338. }
  339. const weaponSprite = weaponNode.getComponent(Sprite);
  340. if (!weaponSprite) {
  341. console.warn('[WeaponBlockTestScript] Weapon节点上没有Sprite组件');
  342. return;
  343. }
  344. // 获取武器配置中的图片路径
  345. const spritePath = weaponConfig.visualConfig?.weaponSprites;
  346. if (!spritePath) {
  347. console.warn(`[WeaponBlockTestScript] 武器 ${weaponConfig.name} 没有配置图片信息`);
  348. return;
  349. }
  350. // 正确的SpriteFrame子资源路径
  351. const spriteFramePath = `${spritePath}/spriteFrame`;
  352. // 加载SpriteFrame子资源
  353. resources.load(spriteFramePath, SpriteFrame, (err, spriteFrame) => {
  354. if (err) {
  355. console.warn(`[WeaponBlockTestScript] 加载武器图片失败: ${spriteFramePath}`, err);
  356. return;
  357. }
  358. // Add comprehensive null safety checks before setting spriteFrame
  359. if (weaponSprite && weaponSprite.isValid &&
  360. weaponNode && weaponNode.isValid &&
  361. block && block.isValid &&
  362. spriteFrame && spriteFrame.isValid) {
  363. weaponSprite.spriteFrame = spriteFrame;
  364. console.log(`[WeaponBlockTestScript] 成功加载武器图标: ${weaponConfig.name}`);
  365. }
  366. });
  367. }
  368. /**
  369. * 生成特定武器类型的所有形状组合
  370. */
  371. public async generateWeaponShapeCombinations(weaponType: string) {
  372. if (this.WEAPON_TYPES.indexOf(weaponType) === -1) {
  373. this.updateStatus(`无效的武器类型: ${weaponType}`);
  374. return;
  375. }
  376. this.clearTestContainer();
  377. this.updateStatus(`生成武器 ${weaponType} 的所有形状组合...`);
  378. const startX = -400;
  379. const startY = 200;
  380. const spacingX = 100;
  381. const spacingY = 120;
  382. const itemsPerRow = 5;
  383. for (let i = 0; i < this.BLOCK_SHAPES.length; i++) {
  384. const shapeId = this.BLOCK_SHAPES[i];
  385. const row = Math.floor(i / itemsPerRow);
  386. const col = i % itemsPerRow;
  387. const posX = startX + col * spacingX;
  388. const posY = startY - row * spacingY;
  389. await this.generateTestBlock(weaponType, shapeId, new Vec3(posX, posY, 0));
  390. this.updateStatus(`生成进度: ${i + 1}/${this.BLOCK_SHAPES.length}`);
  391. if ((i + 1) % 5 === 0) {
  392. await this.waitOneFrame();
  393. }
  394. }
  395. this.updateStatus(`${weaponType} 的所有形状组合生成完成!`);
  396. }
  397. /**
  398. * 生成特定形状的所有武器组合
  399. */
  400. public async generateShapeWeaponCombinations(shapeId: string) {
  401. if (this.BLOCK_SHAPES.indexOf(shapeId) === -1) {
  402. this.updateStatus(`无效的形状ID: ${shapeId}`);
  403. return;
  404. }
  405. this.clearTestContainer();
  406. this.updateStatus(`生成形状 ${shapeId} 的所有武器组合...`);
  407. const startX = -400;
  408. const startY = 200;
  409. const spacingX = 100;
  410. const spacingY = 120;
  411. const itemsPerRow = 3;
  412. for (let i = 0; i < this.WEAPON_TYPES.length; i++) {
  413. const weaponType = this.WEAPON_TYPES[i];
  414. const row = Math.floor(i / itemsPerRow);
  415. const col = i % itemsPerRow;
  416. const posX = startX + col * spacingX;
  417. const posY = startY - row * spacingY;
  418. await this.generateTestBlock(weaponType, shapeId, new Vec3(posX, posY, 0));
  419. this.updateStatus(`生成进度: ${i + 1}/${this.WEAPON_TYPES.length}`);
  420. if ((i + 1) % 3 === 0) {
  421. await this.waitOneFrame();
  422. }
  423. }
  424. this.updateStatus(`形状 ${shapeId} 的所有武器组合生成完成!`);
  425. }
  426. /**
  427. * 清空测试容器
  428. */
  429. public clearTestContainer() {
  430. if (this.testContainer) {
  431. this.testContainer.removeAllChildren();
  432. }
  433. }
  434. /**
  435. * 更新状态显示
  436. */
  437. private updateStatus(message: string) {
  438. console.log(`[WeaponBlockTestScript] ${message}`);
  439. }
  440. /**
  441. * 等待一帧
  442. */
  443. private waitOneFrame(): Promise<void> {
  444. return new Promise(resolve => {
  445. this.scheduleOnce(() => {
  446. resolve();
  447. }, 0);
  448. });
  449. }
  450. /**
  451. * 导出当前测试结果为JSON(用于调试)
  452. */
  453. public exportTestResults(): string {
  454. const results = {
  455. timestamp: new Date().toISOString(),
  456. weaponTypes: this.WEAPON_TYPES,
  457. blockShapes: this.BLOCK_SHAPES,
  458. rarities: this.RARITIES,
  459. totalCombinations: this.WEAPON_TYPES.length * this.BLOCK_SHAPES.length,
  460. generatedBlocks: this.testContainer ? this.testContainer.children.length : 0
  461. };
  462. const jsonString = JSON.stringify(results, null, 2);
  463. console.log('[WeaponBlockTestScript] 测试结果:', jsonString);
  464. return jsonString;
  465. }
  466. }