import { _decorator, Component, Label, Node, RichText, sp, Sprite, SpriteFrame, Tween, tween, Vec3, Button } from 'cc'; import { GBundle, GPath, UIID } from '../../game/ConfigRes'; import { SpriteLoad } from 'db://assets/mx/components/SpriteLoad'; import { GEvent } from 'db://assets/mx/module/event/GEvent'; import { BattleType } from '../../manager/ChapterDataManager'; import MTools from 'db://assets/mx/tools/MTools'; import { BattleResLoader } from '../../game/BattleResLoader'; const { ccclass, property } = _decorator; @ccclass('SkillSelectItem') export class SkillSelectItem extends Component { bgAnim: sp.Skeleton = null; sicon: Sprite = null; typeIcon: Sprite = null; lbtag: Label = null; lbname: Label = null; rtdesc: RichText = null; newItem: Node = null; rtTNum: Label = null; rtbg: Node = null; bg: Sprite = null; sbg: Sprite = null; wbg: Sprite = null; bicon: Sprite = null; wicon: Sprite = null; protected onLoad(): void { this.bgAnim = this.node.find("bgAnim").getComponent(sp.Skeleton); this.sicon = this.node.find("sicon").getComponent(Sprite); this.typeIcon = this.node.find("typeIcon").getComponent(Sprite); this.lbtag = this.node.find("lbtag").getComponent(Label); this.lbname = this.node.find("lbname").getComponent(Label); this.rtdesc = this.node.find("rtdesc").getComponent(RichText); this.newItem = this.node.find("newItem"); this.rtbg = this.newItem?.find("rtbg") ?? this.node.find("rtbg"); this.bg = this.node.find("bg").getComponent(Sprite); this.sbg = this.node.find("sbg").getComponent(Sprite); this.wbg = this.node.find("wbg").getComponent(Sprite); this.bicon = this.node.find("bicon").getComponent(Sprite); this.wicon = this.node.find("wicon").getComponent(Sprite); this.rtTNum = this.node.find("rtTNum").getComponent(Label); // 预制体 Button 为 SCALE(0.9),鼠标悬停会与 playFlipRefresh 缩放 tween 冲突导致 item 突然缩小 const btn = this.node.getComponent(Button); if (btn) { btn.transition = Button.Transition.NONE; } // 技能选项统一不吃历史缩放,基准始终为 1,1,1 this.ensureNormalizedBaseScale(); } protected onEnable(): void { this.node.on(Node.EventType.TOUCH_END, this.onClick, this); } protected onDisable(): void { this.node.off(Node.EventType.TOUCH_END, this.onClick, this); // 面板关闭/节点回收时,避免 tween 中断后残留到中间缩放 Tween.stopAllByTarget(this.node); if (this.node?.isValid) { this.node.setScale(this._baseScale.x, this._baseScale.y, this._baseScale.z); } } Skill: ITableSkill = null; Weapon: ITableWeapon2 = null; /**动画品质皮肤 */ animSkin = ["绿", "蓝", "紫", "黄"]; private _baseScaleInited: boolean = false; private _baseScale: Vec3 = new Vec3(1, 1, 1); private readonly _normalizedScale: Vec3 = new Vec3(1, 1, 1); private ensureNormalizedBaseScale(): void { this._baseScale = this._normalizedScale.clone(); this._baseScaleInited = true; if (this.node?.isValid) { this.node.setScale(this._baseScale.x, this._baseScale.y, this._baseScale.z); } } getBaseScale(): Vec3 { if (!this._baseScaleInited) this.ensureNormalizedBaseScale(); return this._baseScale.clone(); } resetScale(): void { if (!this.node?.isValid) return; if (!this._baseScaleInited) this.ensureNormalizedBaseScale(); Tween.stopAllByTarget(this.node); this.node.setScale(this._baseScale.x, this._baseScale.y, this._baseScale.z); } private _isSkill: boolean = true; private _quality: number = 0; private _iconId: number | string = 0; private _tag: string = ""; private _itemName: string = ""; private _desc: string = ""; private _new: boolean = false; private _tetriType: number = 0; /** 救救我鸭:对应 jiujiuwoyaWeaponCarriers 下标 */ private _carrierIndex = -1; /** 三选一底部:相对当前面板的 DPS 变化(与主界面秒伤同源公式) */ private _dpsDelta: number = 0; private playFlipRefresh() { if (!this.node?.isValid) return; // 复用节点/快速刷新时,确保以基准缩放开始/结束,避免残留到中间值 this.resetScale(); // tween 目标 Vec3 用 clone,避免对象被 tween 内部复用导致基准缩放被污染 const base = this._baseScale.clone(); const scale0 = new Vec3(0, base.y, base.z); tween(this.node) .to(0.3, { scale: scale0 }) .call(() => this.updateUI()) .to(0.3, { scale: base }, { easing: "smooth" }) .call(() => this.node?.isValid && this.node.setScale(this._baseScale.x, this._baseScale.y, this._baseScale.z)) .start(); } setSkill(skill: ITableSkill) { this.Skill = skill; this._isSkill = true; this.Weapon = null; this._quality = skill.quality - 1; this._iconId = skill.icon; this._tag = gg.lang.get(skill.icon_desc); this._itemName = skill.name; this._desc = skill.desc; this._new = false; this._dpsDelta = gg.game.CurentBattle.getSkillSelectDpsDeltaForSkill(skill); this.playFlipRefresh(); } setWeapon(weapon: ITableWeapon2, tetriTypeOrCarrierIndex: number) { this.Weapon = weapon; let itemData = gg.data.table.getItemData(weapon.itemID) this._isSkill = false; this.Skill = null; this._quality = weapon.quality - 1; this._iconId = itemData.icon; this._tag = ""; this._itemName = weapon.name; this._desc = weapon.desc; this._new = true; const ya = gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Ya; if (ya) { this._carrierIndex = tetriTypeOrCarrierIndex; const carriers = gg.game.CurentBattle.jiujiuwoyaWeaponCarriers ?? []; this._tetriType = carriers[this._carrierIndex]?.getWeapontype() ?? 1; } else { this._carrierIndex = -1; this._tetriType = tetriTypeOrCarrierIndex; } this._dpsDelta = gg.game.CurentBattle.getSkillSelectDpsDeltaForWeapon(weapon, this._tetriType); this.playFlipRefresh(); } updateUI() { this.bgAnim.node.active = false; this.sbg.node.active = false; this.wbg.node.active = false; this.bicon.node.active = false; this.wicon.node.active = false; this.sicon.node.active = false; this.typeIcon.node.active = false; this.bg.node.getOrAddComponent(SpriteLoad).setSprite(GPath.texture(`bg_${this._quality + 1}`), GBundle.SkillSelect); if (this._quality >= 2) { this.bgAnim.node.active = true; this.bgAnim.setSkin(this.animSkin[this._quality]); //this.bgAnim.setAnimation(0, "play", false); //this.bgAnim.setCompleteListener(this.endAnim.bind(this)); } if (this._isSkill) { this.sbg.node.active = true; this.sicon.node.active = true; this.sbg.node.getOrAddComponent(SpriteLoad).setSprite(GPath.texture(`sb_${this._quality + 1}`), GBundle.SkillSelect); this.sicon.getComponent(SpriteLoad).setSprite(GPath.SkillItem(this._iconId), GBundle.Items); } else { this.wbg.node.active = true; this.wicon.node.active = true; this.bicon.node.active = true; this.typeIcon.node.active = true; this.wbg.node.getOrAddComponent(SpriteLoad).setSprite(GPath.texture(`wb_${this._quality + 1}`), GBundle.SkillSelect); this.bicon.node.getOrAddComponent(SpriteLoad).setSprite(GPath.texture(`b_${this._tetriType}`), GBundle.SkillSelect); this.wicon.getComponent(SpriteLoad).setSprite(GPath.Item(this._iconId), GBundle.Items); this.typeIcon.getComponent(SpriteLoad).setSprite(GPath.WeaponType(`武器属性_${this.Weapon.type}`), GBundle.BattleGameWeapon); } this.lbtag.string = gg.lang.get(this._tag); this.lbname.string = gg.lang.get(this._itemName); this.rtdesc.string = gg.lang.get(this._desc); this.newItem.active = this._new; const d = this._dpsDelta; const showDps = d >= 0; if (this.rtbg?.isValid) this.rtbg.active = showDps; if (this.rtTNum?.node?.isValid) { this.rtTNum.node.active = showDps; if (showDps) { const signStr = (d >= 0 ? '+' : '-') + MTools.formatChineseUnit({ num: Math.abs(d) }); this.rtTNum.string = gg.lang.get(`秒伤{1}`, [signStr]); } } } onClick() { console.log("点击选择了技能或者武器"); if (this._dpsDelta < 0) { gg.game.CurentBattle.skipNextDpsFlyAnim = true; } if (this.Skill) { gg.game.CurentBattle.addCurRogueSkillTimes(); gg.game.CurentBattle.addCurHaveSkillArr([this.Skill]); //判断是抽卡副本 if (gg.game.CurentBattle.BattleType == BattleType.GachaMode) { GEvent.Ins.emit(GEvent.AddSkillIcon, [this.Skill]); } } else if (this.Weapon) { if (gg.game.CurentBattle.BattleType == BattleType.SpeedMode || gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Dan) { //首次给武器无法选择 return } else { gg.game.CurentBattle.addCurRogueWeaponTimes(); if (gg.game.CurentBattle.BattleType == BattleType.OrangeWeaponMode_Ya) { gg.game.CurentBattle.changeJiujiuwoyaWeapon(this._carrierIndex, this.Weapon.weaponid); } else { gg.game.CurentBattle.changeTetriWeaponConfig(this._tetriType, this.Weapon.weaponid); } //判断是抽卡副本 if (gg.game.CurentBattle.BattleType == BattleType.GachaMode) { GEvent.Ins.emit(GEvent.AddWeaponIcon, [this.Weapon.weaponid]); } // 选中后预热该武器子弹 + hitEffect 爆炸特效 void BattleResLoader.preloadWeaponCombatAssets(this.Weapon); } if (gg.game.CurentBattle.ChapterId == 1 && gg.game.CurentBattle.CurUseWeaponArr.length == 2) { gg.sdk.reportDY("inLevel", `章节${gg.game.CurentBattle.getReportDYChapterId()}_${gg.game.CurentBattle.CurentWaveNum}-武器选择成功`) } } gg.ui.closePanel(UIID.SkillSelect, 2); } endAnim() { this.bgAnim.setAnimation(0, "idle", true); this.bgAnim.setCompleteListener(null); } }