import { _decorator, Animation, AnimationClip, Component, instantiate, Label, Node, Prefab, resources, Sprite, SpriteFrame, v3, tween, Vec3, ProgressBar, SpriteAtlas } from 'cc'; import { oops } from 'db://oops-framework/core/Oops'; import { getHeroList, getPreAttr, HeroConf, HeroInfo, HType, HTypeName } from '../common/config/heroSet'; import { smc } from '../common/SingletonModuleComp'; import { GameEvent } from '../common/config/GameEvent'; import { CCComp } from 'db://oops-framework/module/common/CCComp'; import { ecs } from 'db://oops-framework/libs/ecs/ECS'; import { SkillSet } from '../common/config/SkillSet'; import { mLogger } from '../common/Logger'; const { ccclass, property } = _decorator; @ccclass('HInfoComp') @ecs.register('HInfoComp', false) export class HInfoComp extends CCComp { debugMode: boolean = false; h_uuid:number=0 private uiconsAtlas: SpriteAtlas | null = null; name_node:any=null type_node:any=null ap_node:any=null hp_node:any=null def_node:any=null mp_node:any=null skill1_node:any=null skill2_node:any=null // 重新定义节点映射,使名称更清晰 // 当前显示的英雄节点数组(7个位置) heroNodes: (Node | null)[] = [null, null, null, null, null, null, null]; // 英雄位置定义 hero_pos:any={ 0:v3(500,0,0), // 不在屏幕内 1:v3(500,0,0), 2:v3(250,0,0), 3:v3(0,-30,0), 4:v3(-250,0,0), 5:v3(-500,0,0), 6:v3(-500,0,0), // 不在屏幕内 } // 动画锁定标志:防止快速点击导致的动画冲突 private isMoving: boolean = false; // 保存待处理的setTimeout句柄,用于取消前一个异步操作 private moveTimeoutId: any = null; protected onLoad(): void { // this.on(GameEvent.MissionStart,this.mission_start,this) } // 位置索引常量 private static center_pos = 3; /** * 根据位置索引获取英雄缩放值 * @param posIndex 位置索引 (0-6) * @returns Vec3 缩放向量 */ private getHeroScale(posIndex: number): Vec3 { switch(posIndex) { case 2: case 4: return v3(-2.2, 2.2, 1); // 2、4位置:1.5倍缩放 case 3: return v3(-2.5, 2.5, 1); // 3位置(中心):1.5倍缩放 default: return v3(-2.2, 2.2, 1); // 其他位置:1.8倍缩放 } } start() { this.name_node=this.node.getChildByName("hname").getChildByName("name") this.type_node=this.node.getChildByName("hname").getChildByName("type") this.hp_node=this.node.getChildByName("info").getChildByName("base").getChildByName("bgs").getChildByName("hp") this.mp_node=this.node.getChildByName("info").getChildByName("base").getChildByName("bgs").getChildByName("mp") this.ap_node=this.node.getChildByName("info").getChildByName("base").getChildByName("bgs").getChildByName("ap") this.def_node=this.node.getChildByName("info").getChildByName("base").getChildByName("bgs").getChildByName("def") this.skill1_node=this.node.getChildByName("info").getChildByName("base").getChildByName("skills").getChildByName("skill1") this.skill2_node=this.node.getChildByName("info").getChildByName("base").getChildByName("skills").getChildByName("skill2") this.h_uuid=smc.fight_hero this.update_data(this.h_uuid) this.load_all_hero(this.h_uuid) this.showInfo() this.close_buy() this.close_ranks() } update(deltaTime: number) { } update_data(uuid:number){ this.h_uuid=uuid let skill1=SkillSet[HeroInfo[uuid].skills[0]] let skill2=SkillSet[HeroInfo[uuid].skills[1]] this.skill1_node.getChildByName("info").getChildByName("Label").getComponent(Label).string=skill1.info this.skill1_node.getChildByName("info").getChildByName("name").getComponent(Label).string=skill1.name this.skill2_node.getChildByName("info").getChildByName("Label").getComponent(Label).string=skill2.info this.skill2_node.getChildByName("info").getChildByName("name").getComponent(Label).string=skill2.name this.name_node.getComponent(Label).string=HeroInfo[uuid].name this.type_node.getComponent(Label).string=HTypeName[HeroInfo[uuid].type] this.ap_node.getChildByName("num").getComponent(Label).string=HeroInfo[uuid].ap.toString() this.hp_node.getChildByName("num").getComponent(Label).string=HeroInfo[uuid].hp.toString() let bar_num=getPreAttr(uuid) this.ap_node.getChildByName("bar").getComponent(ProgressBar).progress=bar_num.ap this.hp_node.getChildByName("bar").getComponent(ProgressBar).progress=bar_num.hp // 更新技能图标 this.updateSkillIcon(this.skill1_node, skill1.icon); this.updateSkillIcon(this.skill2_node, skill2.icon); } /** * 更新技能图标 * @param node 技能节点 * @param iconId 图标ID */ private updateSkillIcon(node: Node, iconId: string) { if (!node || !iconId) return; mLogger.log(this.debugMode, 'HInfoComp', "iconId",iconId) const iconNode = node.getChildByName("icon"); mLogger.log(this.debugMode, 'HInfoComp', "iconNode",iconNode) if (!iconNode) return; const sprite = iconNode.getComponent(Sprite); mLogger.log(this.debugMode, 'HInfoComp', "sprite",sprite) if (!sprite) return; if (this.uiconsAtlas) { mLogger.log(this.debugMode, 'HInfoComp', "this.uiconsAtlas",this.uiconsAtlas) const frame = this.uiconsAtlas.getSpriteFrame(iconId); if (frame) { sprite.spriteFrame = frame; } } else { // 加载图集 resources.load("gui/uicons", SpriteAtlas, (err, atlas) => { if (err) { mLogger.log(this.debugMode, 'HInfoComp', "[HInfoComp] Failed to load uicons atlas", err); return; } this.uiconsAtlas = atlas; mLogger.log(this.debugMode, 'HInfoComp', "atlas",atlas) const frame = atlas.getSpriteFrame(iconId); if (frame) { sprite.spriteFrame = frame; } }); } } load_all_hero(uuid:number){ // 清除之前的英雄节点 this.claear_hero(); // 获取英雄列表(优先显示拥有的英雄) let heros = getHeroList(); let currentIndex = heros.indexOf(uuid); // 载入7个英雄节点(当前英雄及前后各3个) for(let i = 0; i < 7; i++) { // 计算索引位置(考虑循环) let indexOffset = i - 3; // -3, -2, -1, 0, 1, 2, 3 let heroIndex = currentIndex + indexOffset; // 处理循环边界 if(heroIndex < 0) { heroIndex = heros.length + heroIndex; } else if(heroIndex >= heros.length) { heroIndex = heroIndex - heros.length; } // 获取英雄UUID let heroUuid = heros[heroIndex]; // 载入英雄预制体并设置位置 this.heroNodes[i] = this.load_hui(heroUuid, i); // 添加初始缩放动画,根据位置设置不同的缩放值 if (this.heroNodes[i]) { let targetScale = this.getHeroScale(i); tween(this.heroNodes[i]) .to(0.2, { scale: targetScale }) .start(); } } this.show_lock() } load_hui(uuid:number, pos_index: number){ var path = "game/gui/hui"; var prefab: Prefab = oops.res.get(path, Prefab)!; var node = instantiate(prefab); // 将节点添加到父节点下 this.node.getChildByName("hero").addChild(node); // 设置节点位置 node.setPosition(this.hero_pos[pos_index]); // node.setSiblingIndex(0); // 根据位置设置不同的缩放值 node.setScale(this.getHeroScale(pos_index)); // 加载并播放动画 let anm_path=HeroInfo[uuid].path; resources.load("game/heros/hero/"+anm_path+"/idle", AnimationClip, (err, clip) => { if (!err && clip) { let animComponent = node.getComponent(Animation); if(animComponent) { animComponent.addClip(clip); animComponent.play("idle"); } } else { mLogger.log(this.debugMode, 'HInfoComp', ` Failed to load animation for hero ${uuid}`, err); } }); return node; } mission_start(){ this.claear_hero() } is_own(){ return smc.heros.includes(this.h_uuid) } show_lock(){ this.node.getChildByName("buy").active=!this.is_own() } showInfo(){ this.node.getChildByName("info").active=smc.data.showInfo this.node.getChildByName("hname").getChildByName("more").getChildByName("no").active=smc.data.showInfo } btnShowInfo(){ smc.data.showInfo=!smc.data.showInfo this.showInfo() } claear_hero(){ for (let i = 0; i < this.heroNodes.length; i++) { if (this.heroNodes[i]) { this.heroNodes[i].destroy(); this.heroNodes[i] = null; } } } next_hero(){ // 检查是否正在动画中,防止快速点击导致的冲突 if (this.isMoving) return; // 获取英雄列表(优先显示拥有的英雄) let heros = getHeroList(); let index = heros.indexOf(this.h_uuid); index++; if(index == heros.length) index = 0; let nextHero = heros[index]; // 更新数据 this.h_uuid = nextHero; this.update_data(nextHero); // 执行平滑移动动画 this.moveHeroesRight(); this.show_lock() } prev_hero(){ // 检查是否正在动画中,防止快速点击导致的冲突 if (this.isMoving) return; // 获取英雄列表(优先显示拥有的英雄) let heros = getHeroList(); let index = heros.indexOf(this.h_uuid); index--; if(index == -1) index = heros.length - 1; let prevHero = heros[index]; // 更新数据 this.h_uuid = prevHero; this.update_data(prevHero); // 执行平滑移动动画 this.moveHeroesLeft(); this.show_lock() } show_buy(){ this.node.getChildByName("unlock").active=true } close_buy(){ this.node.getChildByName("unlock").active=false } show_ranks(){ this.node.getChildByName("ranks").active=true } close_ranks(){ this.node.getChildByName("ranks").active=false } buy_hero(){ mLogger.log(this.debugMode, 'HInfoComp', "buy_hero",this.h_uuid) if(smc.data.gold < HeroConf.COST) { oops.gui.toast("金币不足") return } smc.addHero(this.h_uuid) this.load_all_hero(this.h_uuid) this.show_lock() this.close_buy() } moveHeroesLeft() { // 取消前一个待处理的异步操作 if (this.moveTimeoutId !== null) { clearTimeout(this.moveTimeoutId); } // 设置动画锁定 this.isMoving = true; // 在动画开始前,直接销毁hero_pos[6]上的节点 mLogger.log(this.debugMode, 'HInfoComp', "hero_pos[6]",this.hero_pos[6]) if (this.heroNodes[6]) { this.heroNodes[6].destroy(); this.heroNodes[6] = null; } // 移动所有现有节点向左(除了已销毁的heroNodes[6]) for (let i = 0; i < 6; i++) { if (this.heroNodes[i]) { mLogger.log(this.debugMode, 'HInfoComp', "i",i) // 计算目标位置:向左移动 let targetPos = this.hero_pos[i + 1]; // 使用Tween执行平滑移动和缩放动画 let targetScale = this.getHeroScale(i + 1); tween(this.heroNodes[i]) .to(0.2, { position: targetPos, scale: targetScale }) .start(); } } // 延迟重排数组和创建新节点,等待动画完成 this.moveTimeoutId = setTimeout(() => { // 移动数组元素(向后平移) for (let i = 6; i > 0; i--) { mLogger.log(this.debugMode, 'HInfoComp', "i",i) this.heroNodes[i] = this.heroNodes[i - 1]; } // 创建新节点放在hero_pos[0]位置 let heros = getHeroList(); mLogger.log(this.debugMode, 'HInfoComp', "heros",heros) let currentIndex = heros.indexOf(this.h_uuid); let newIndex = currentIndex - 3; // 新的最左侧英雄索引 // 处理循环边界 if (newIndex < 0) { newIndex = heros.length + newIndex; } this.heroNodes[0] = this.load_hui(heros[newIndex], 0); // 确保新创建的节点使用正确的缩放值 if (this.heroNodes[0]) { mLogger.log(this.debugMode, 'HInfoComp', "this.heroNodes[0]",this.heroNodes[0]) this.heroNodes[0].setScale(this.getHeroScale(0)); } // 动画完成,解除锁定 this.isMoving = false; this.moveTimeoutId = null; }, 200); // 与动画时间保持一致 } moveHeroesRight() { // 取消前一个待处理的异步操作 if (this.moveTimeoutId !== null) { clearTimeout(this.moveTimeoutId); } // 设置动画锁定 this.isMoving = true; // 在动画开始前,直接销毁hero_pos[0]上的节点 if (this.heroNodes[0]) { this.heroNodes[0].destroy(); this.heroNodes[0] = null; } // 移动所有现有节点向右(除了已销毁的heroNodes[0]) for (let i = 1; i < this.heroNodes.length; i++) { if (this.heroNodes[i]) { // 计算目标位置:向右移动 let targetPos = this.hero_pos[i - 1]; // 使用Tween执行平滑移动和缩放动画 let targetScale = this.getHeroScale(i - 1); tween(this.heroNodes[i]) .to(0.2, { position: targetPos, scale: targetScale }) .start(); } } // 延迟重排数组和创建新节点,等待动画完成 this.moveTimeoutId = setTimeout(() => { // 移动数组元素(向前平移) for (let i = 0; i < 6; i++) { this.heroNodes[i] = this.heroNodes[i + 1]; } // 创建新节点放在hero_pos[6]位置 let heros = getHeroList(); let currentIndex = heros.indexOf(this.h_uuid); let newIndex = currentIndex + 3; // 新的最右侧英雄索引 // 处理循环边界 if (newIndex >= heros.length) { newIndex = newIndex - heros.length; } this.heroNodes[6] = this.load_hui(heros[newIndex], 6); // 确保新创建的节点使用正确的缩放值 if (this.heroNodes[6]) { this.heroNodes[6].setScale(this.getHeroScale(6)); } // 动画完成,解除锁定 this.isMoving = false; this.moveTimeoutId = null; }, 200); // 与动画时间保持一致 } reset() { this.node.destroy() } }