| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826 |
- import { _decorator, Component, Node, Prefab, resources, instantiate, Label, Sprite, SpriteFrame, Button, ProgressBar, ScrollView, Vec2, Vec3, UITransform, tween, Color } from 'cc';
- import { PersistentSkillManager } from './PersistentSkillManager';
- import { SaveDataManager } from '../../LevelSystem/SaveDataManager';
- import { SkillConfigManager } from './SkillConfigManager';
- import EventBus, { GameEvents } from '../../Core/EventBus';
- import { Audio } from '../../AudioManager/AudioManager';
- const { ccclass, property } = _decorator;
- /**
- * 技能节点数据接口
- */
- interface SkillNodeData {
- node: Node;
- group: number;
- skillIndex: number;
- cost: number;
- isUnlocked: boolean; // 本地记录的解锁状态
- backgroundSprite: Sprite;
- iconSprite: Sprite;
- }
- /**
- * 技能节点生成器
- * 自动生成12组技能节点,每组包含3个技能类型
- * 支持技能点亮状态管理和图片切换
- */
- @ccclass('SkillNodeGenerator')
- export class SkillNodeGenerator extends Component {
- @property(Prefab)
- skillNode1Prefab: Prefab = null!; // Damage
-
- @property(Prefab)
- skillNode2Prefab: Prefab = null!; // Ball Speed
-
- @property(Prefab)
- skillNode3Prefab: Prefab = null!; // Crit Damage
-
- // 图片资源
- @property(SpriteFrame)
- backgroundNormal: SpriteFrame = null!; // an001.png - 未点亮状态
-
- @property(SpriteFrame)
- backgroundUnlocked: SpriteFrame = null!; // an000.png - 点亮状态
-
- @property(SpriteFrame)
- iconNormal: SpriteFrame = null!; // tb002.png - 未点亮状态
-
- @property(SpriteFrame)
- iconUnlocked: SpriteFrame = null!; // tb001.png - 点亮状态
- @property(ProgressBar)
- progressBar: ProgressBar = null!; // 进度条
-
- @property(ScrollView)
- scrollView: ScrollView = null!; // 滚动视图
-
- @property(Node)
- diamondNumberNode: Node = null!; // 钻石数量显示节点
-
- // 技能节点数据存储(一维数组)
- private skillNodes: SkillNodeData[] = [];
-
- // 当前解锁到的节点索引
- private currentUnlockIndex: number = -1;
-
- // 持久化技能管理器
- private skillManager: PersistentSkillManager | null = null;
-
- // 保存数据管理器引用
- private saveDataManager: SaveDataManager | null = null;
-
- // 技能配置管理器
- private skillConfigManager: SkillConfigManager | null = null;
-
- // 闪烁动画相关
- private blinkingNodes: Set<Node> = new Set(); // 正在闪烁的节点集合
-
- async start() {
- console.log('SkillNodeGenerator 初始化开始');
- this.skillManager = PersistentSkillManager.getInstance();
- this.saveDataManager = SaveDataManager.getInstance();
- this.skillConfigManager = SkillConfigManager.getInstance();
-
- // 监听货币变化事件
- EventBus.getInstance().on(GameEvents.CURRENCY_CHANGED, this.onCurrencyChanged, this);
-
- // 等待技能配置加载完成
- if (this.skillConfigManager) {
- await this.skillConfigManager.waitForLoad();
- console.log('技能配置加载完成');
- }
-
- // 生成所有技能节点
- this.generateSkillNodes();
- console.log(`技能节点生成完成,共 ${this.skillNodes.length} 个节点`);
-
- // 加载已解锁的技能状态
- this.loadUnlockedSkills();
-
- // 更新进度条
- this.updateProgressBar();
-
- // 更新钻石UI显示
- this.updateDiamondUI();
-
- // 初始化闪烁状态
- this.updateBlinkingNodes();
-
- console.log('SkillNodeGenerator 初始化完成');
- }
-
- /**
- * 生成技能节点
- */
- private generateSkillNodes() {
- if (!this.skillConfigManager) {
- console.error('SkillConfigManager not initialized');
- return;
- }
- // 技能节点预制体数组
- const prefabs = [
- this.skillNode1Prefab, // Damage
- this.skillNode2Prefab, // Ball Speed
- this.skillNode3Prefab // Crit Damage
- ];
-
- const totalGroups = this.skillConfigManager.getTotalGroups();
- const skillsPerGroup = this.skillConfigManager.getSkillsPerGroup();
-
- // 生成技能节点,按顺序存储到一维数组中
- for (let group = 1; group <= totalGroups; group++) {
- const skillGroupConfig = this.skillConfigManager.getSkillGroupConfig(group);
- if (!skillGroupConfig) {
- console.error(`Failed to get skill group config for group ${group}`);
- continue;
- }
-
- // 每组生成指定数量的技能节点
- for (let skillIndex = 0; skillIndex < skillsPerGroup; skillIndex++) {
- // 计算节点在一维数组中的索引
- const arrayIndex = (group - 1) * skillsPerGroup + skillIndex;
-
- const skillName = this.skillConfigManager.getSkillName(skillIndex, group);
- const skillCost = this.skillConfigManager.getSkillCost(group);
-
- this.createSkillNode(
- prefabs[skillIndex],
- skillName,
- skillCost.toString(),
- group,
- skillIndex,
- arrayIndex
- );
- }
- }
- }
-
- /**
- * 创建技能节点
- */
- private createSkillNode(
- prefab: Prefab,
- skillName: string,
- cost: string,
- group: number,
- skillIndex: number,
- totalIndex: number
- ) {
- if (!prefab) {
- console.error(`Prefab is null for skill index: ${skillIndex}`);
- return;
- }
-
- // 实例化预制体
- const skillNode = instantiate(prefab);
-
- // 设置节点名称
- skillNode.name = `SkillNode${skillIndex + 1}_Group${group}`;
-
- // 查找并设置NameLabel
- const nameLabel = skillNode.getChildByName('NameLabel');
- if (nameLabel) {
- const labelComponent = nameLabel.getComponent(Label);
- if (labelComponent) {
- labelComponent.string = skillName;
- }
- }
-
- // 查找并设置CostLabel
- const costLabel = skillNode.getChildByName('CostLabel');
- if (costLabel) {
- const labelComponent = costLabel.getComponent(Label);
- if (labelComponent) {
- labelComponent.string = cost;
- }
- }
-
- // 添加到当前节点(content节点)
- this.node.addChild(skillNode);
-
- // 获取Background和Icon的Sprite组件
- const backgroundNode = skillNode.getChildByName('Background');
- const iconNode = skillNode.getChildByName('Icon');
-
- const backgroundSprite = backgroundNode?.getComponent(Sprite);
- const iconSprite = iconNode?.getComponent(Sprite);
-
- if (!backgroundSprite || !iconSprite) {
- console.error(`Failed to get sprite components for skill node: ${skillName}`);
- return;
- }
-
- // 创建技能节点数据
- const skillNodeData: SkillNodeData = {
- node: skillNode,
- group: group,
- skillIndex: skillIndex,
- cost: parseInt(cost),
- isUnlocked: false, // 初始化为未解锁状态
- backgroundSprite: backgroundSprite,
- iconSprite: iconSprite
- };
-
- // 存储技能节点数据
- this.skillNodes.push(skillNodeData);
-
- // 添加点击事件
- const buttonComponent = skillNode.getChildByName('Background').getComponent(Button);
- if (buttonComponent) {
- buttonComponent.node.on(Button.EventType.CLICK, () => {
- this.onSkillNodeClick(skillNodeData);
- }, this);
- }
-
- // 初始化为未点亮状态
- this.updateSkillNodeVisual(skillNodeData);
- }
-
- /**
- * 技能节点点击事件处理
- */
- private onSkillNodeClick(skillNodeData: SkillNodeData) {
-
- // 延迟一帧后滚动到最新解锁的技能节点,确保所有节点都已正确布局
- this.scheduleOnce(() => {
- this.scrollToLatestUnlockedSkill();
- }, 1);
-
- // 计算当前节点的索引
- const nodeIndex = (skillNodeData.group - 1) * 3 + skillNodeData.skillIndex;
-
- // 只允许按顺序解锁,必须是下一个待解锁的节点
- if (nodeIndex !== this.currentUnlockIndex + 1) {
- console.log(`必须按顺序解锁技能,当前可解锁索引: ${this.currentUnlockIndex + 1}`);
- return;
- }
-
- // 如果已经点亮,则不处理
- if (skillNodeData.isUnlocked) {
- console.log(`技能已点亮: ${this.getSkillTypeString(skillNodeData.skillIndex)} Group ${skillNodeData.group}`);
- return;
- }
-
- // 获取技能类型和效果百分比
- const skillInfo = this.getSkillInfo(skillNodeData);
- if (!skillInfo) {
- console.error('无法获取技能信息');
- return;
- }
-
- // 检查玩家是否有足够的钻石
- const currentDiamonds = this.saveDataManager ? this.saveDataManager.getDiamonds() : 0;
- if (currentDiamonds < skillNodeData.cost) {
- console.log(`钻石不足Need: ${skillNodeData.cost}, Have: ${currentDiamonds}`);
- // 发送Toast提示事件
- EventBus.getInstance().emit(GameEvents.SHOW_RESOURCE_TOAST, {
- message: `钻石不足,需要${skillNodeData.cost}钻石`,
- duration: 2.0
- });
- return;
- }
-
- // 验证是否可以解锁(由 SkillNodeGenerator 负责验证)
- // 这里已经通过 nodeIndex === this.currentUnlockIndex + 1 验证了顺序
-
- if (!this.skillManager) {
- console.error('SkillManager not initialized');
- return;
- }
-
- // 将解锁数据传递给 PersistentSkillManager
- const unlockResult = this.skillManager.unlockSkill(skillInfo.skillType, skillNodeData.group, skillInfo.effectPercent);
- if (!unlockResult.success) {
- // 这里主要处理技能类型无效或已解锁的情况
- console.log(unlockResult.message);
- return;
- }
-
- // 扣除钻石
- if (this.saveDataManager && !this.saveDataManager.spendDiamonds(skillNodeData.cost)) {
- return;
- }
-
- // 播放升级成功音效
- Audio.playUISound('data/弹球音效/level up 2');
-
- // 更新解锁索引
- this.currentUnlockIndex = nodeIndex;
-
- // 更新UI状态
- skillNodeData.isUnlocked = true;
- this.updateSkillNodeVisual(skillNodeData);
- this.updateProgressBar();
- this.updateDiamondUI();
-
- // 延迟更新闪烁状态,确保所有状态更新完成
- this.scheduleOnce(() => {
- this.updateBlinkingNodes();
- }, 0.1);
-
- // 输出技能解锁信息,包含数组索引
- console.log(`技能已解锁: ${this.getSkillTypeString(skillNodeData.skillIndex)} Group ${skillNodeData.group}, 索引[${nodeIndex}/${this.skillNodes.length-1}]`);
-
- // 输出已解锁技能的数组信息
- this.logUnlockedSkills();
-
- // 滚动到最新点亮的技能节点
- this.scheduleOnce(() => {
- this.scrollToLatestUnlockedSkill();
- }, 0.1);
-
- const remainingDiamonds = this.saveDataManager ? this.saveDataManager.getDiamonds() : 0;
- console.log(`${unlockResult.message}, Remaining diamonds: ${remainingDiamonds}`);
- }
-
- /**
- * 更新技能节点的视觉效果
- * 使用本地的 isUnlocked 状态来更新节点视觉效果
- */
- private updateSkillNodeVisual(skillNodeData: SkillNodeData) {
- if (skillNodeData.isUnlocked) {
- // 点亮状态:使用an000.png和tb001.png
- if (this.backgroundUnlocked) {
- skillNodeData.backgroundSprite.spriteFrame = this.backgroundUnlocked;
- }
- if (this.iconUnlocked) {
- skillNodeData.iconSprite.spriteFrame = this.iconUnlocked;
- }
- } else {
- // 未点亮状态:使用an001.png和tb002.png
- if (this.backgroundNormal) {
- skillNodeData.backgroundSprite.spriteFrame = this.backgroundNormal;
- }
- if (this.iconNormal) {
- skillNodeData.iconSprite.spriteFrame = this.iconNormal;
- }
- }
- }
-
- /**
- * 获取当前钻石数量
- */
- public getDiamonds(): number {
- return this.saveDataManager ? this.saveDataManager.getDiamonds() : 0;
- }
-
- /**
- * 设置钻石数量(用于测试或外部系统集成)
- */
- public setDiamonds(amount: number) {
- if (this.saveDataManager) {
- const playerData = this.saveDataManager.getPlayerData();
- if (playerData) {
- playerData.diamonds = amount;
- this.saveDataManager.savePlayerData();
- this.updateDiamondUI();
-
- // 更新闪烁状态
- this.updateBlinkingNodes();
- }
- }
- }
-
- /**
- * 更新UI显示的钻石数量
- */
- private updateDiamondUI() {
- // 使用装饰器属性更新主界面的钻石显示
- if (this.diamondNumberNode) {
- const label = this.diamondNumberNode.getComponent(Label);
- if (label && this.saveDataManager) {
- const diamonds = this.saveDataManager.getDiamonds();
- label.string = diamonds >= 1000000 ? (diamonds / 1e6).toFixed(1) + 'M' :
- diamonds >= 1000 ? (diamonds / 1e3).toFixed(1) + 'K' :
- diamonds.toString();
- }
- } else {
- console.warn('Diamond number node not assigned in inspector');
- }
-
- // 更新闪烁状态
- this.updateBlinkingNodes();
- }
-
- /**
- * 加载已解锁的技能状态
- */
- private loadUnlockedSkills() {
- if (!this.skillManager) {
- console.warn('SkillManager not initialized');
- return;
- }
-
- // 遍历所有技能节点,按顺序检查解锁状态
- let lastUnlockedIndex = -1;
-
- for (let i = 0; i < this.skillNodes.length; i++) {
- const skillNodeData = this.skillNodes[i];
- const skillInfo = this.getSkillInfo(skillNodeData);
- if (!skillInfo) continue;
-
- // 检查该技能是否已解锁
- const isUnlocked = this.skillManager.isSkillUnlocked(skillInfo.skillType, skillNodeData.group);
- if (isUnlocked) {
- // 更新本地解锁状态
- skillNodeData.isUnlocked = true;
- this.updateSkillNodeVisual(skillNodeData);
- lastUnlockedIndex = i;
- } else {
- // 一旦遇到未解锁的技能,就停止检查
- skillNodeData.isUnlocked = false;
- break;
- }
- }
-
- // 更新当前解锁索引
- this.currentUnlockIndex = lastUnlockedIndex;
-
- // 更新进度条
- this.updateProgressBar();
-
- // 输出已解锁技能的数组信息
- this.logUnlockedSkills();
- }
-
- /**
- * 重置所有技能节点状态
- */
- public resetAllSkills() {
- // 通过技能管理器重置技能数据
- if (this.skillManager) {
- this.skillManager.resetAllSkills();
- }
-
- // 重置UI状态和本地解锁状态
- this.skillNodes.forEach(skillNodeData => {
- // 重置本地解锁状态
- skillNodeData.isUnlocked = false;
-
- // 通过 skillManager 重置技能状态
- if (this.skillManager) {
- const skillInfo = this.getSkillInfo(skillNodeData);
- if (skillInfo) {
- this.skillManager.unlockSkill(skillInfo.skillType, skillNodeData.group, 0); // 将效果值设为0来重置技能
- }
- }
- this.updateSkillNodeVisual(skillNodeData);
- });
-
- // 重置当前解锁索引
- this.currentUnlockIndex = -1;
-
- // 更新进度条
- this.updateProgressBar();
-
- console.log('All skills have been reset');
- }
-
- /**
- * 清除技能点亮状态存档(包括持久化数据和UI状态)
- */
- public clearSkillSaveData() {
- // 清除持久化技能数据
- if (this.skillManager) {
- this.skillManager.resetAllSkills();
- }
-
- // 重置UI状态和本地解锁状态
- for (const skillNodeData of this.skillNodes) {
- // 重置本地解锁状态
- skillNodeData.isUnlocked = false;
-
- // 通过 skillManager 重置技能状态
- const skillInfo = this.getSkillInfo(skillNodeData);
- if (skillInfo && this.skillManager) {
- this.skillManager.unlockSkill(skillInfo.skillType, skillNodeData.group, 0);
- }
- this.updateSkillNodeVisual(skillNodeData);
- }
-
- // 重置当前解锁索引
- this.currentUnlockIndex = -1;
-
- // 更新进度条
- this.updateProgressBar();
-
- // 更新钻石UI显示
- this.updateDiamondUI();
- }
-
- /**
- * 更新进度条
- */
- private updateProgressBar() {
- if (!this.progressBar) {
- console.warn('ProgressBar not found');
- return;
- }
-
- // 使用当前解锁索引计算进度
- const totalNodes = this.skillNodes.length;
- const currentProgress = totalNodes > 0 ? (this.currentUnlockIndex + 1) / totalNodes : 0;
-
- // 更新进度条
- this.progressBar.progress = currentProgress;
-
- // 通知连接线组件更新进度
- this.updateConnectionLineProgress(currentProgress);
-
- // 输出当前解锁进度信息
- if (this.currentUnlockIndex >= 0) {
- console.log(`技能解锁进度: ${this.currentUnlockIndex + 1}/${totalNodes} (${Math.round(currentProgress * 100)}%)`);
- } else {
- console.log(`技能解锁进度: 0/${totalNodes} (0%)`);
- }
- }
-
- /**
- * 更新连接线进度
- */
- private updateConnectionLineProgress(progress: number) {
- // 查找连接线组件
- const connectionLine = this.node.parent?.parent?.getChildByName('ConnectionLine');
- if (connectionLine) {
- const connectionLineComp = connectionLine.getComponent('SkillConnectionLine') as any;
- if (connectionLineComp && typeof connectionLineComp.updateProgress === 'function') {
- connectionLineComp.updateProgress(progress);
- }
- }
- }
-
-
- /**
- * 滚动到最新解锁的技能节点
- * 使用本地的 isUnlocked 状态来查找最新解锁的技能节点
- */
- private scrollToLatestUnlockedSkill() {
- // 找到最新解锁技能的索引
- let latestUnlockedIndex = -1;
-
- for (let i = 0; i < this.skillNodes.length; i++) {
- const skillNode = this.skillNodes[i];
- // 使用本地的 isUnlocked 状态来判断节点是否解锁
- if (skillNode.isUnlocked) {
- latestUnlockedIndex = i;
- }
- }
-
- console.log('滚动到最新的未解锁技能节点或最底部');
-
- // 延迟一帧执行,确保节点布局完成
- this.scheduleOnce(() => {
- // 使用ScrollView的百分比滚动方法
- if (this.scrollView) {
- if (latestUnlockedIndex >= 0) {
- // 根据最新解锁技能的索引计算滚动比例
- const totalNodes = this.skillNodes.length;
- const scrollProgress = latestUnlockedIndex / (totalNodes - 1);
-
- // 使用ScrollView的scrollToPercentVertical方法设置滚动位置
- // 参数:百分比(0-1), 滚动时间(秒), 是否衰减
- this.scrollView.scrollToPercentVertical(scrollProgress, 0.3, true);
-
- console.log(`滚动到索引 ${latestUnlockedIndex}/${totalNodes - 1}, 滚动进度: ${scrollProgress.toFixed(2)}`);
- } else {
- // 如果没有解锁技能,滚动到顶部
- this.scrollView.scrollToPercentVertical(0, 0.3, true);
- console.log('滚动到底部');
- }
- } else {
- console.warn('ScrollView not assigned in inspector');
- }
- }, 0);
- }
-
- /**
- * 获取最新解锁的节点位置
- * @returns 最新解锁节点的Y坐标位置,如果没有解锁节点则返回0
- */
- public getLatestUnlockedNodePosition(): number {
- // 找到最新点亮的技能节点(如果有)
- let latestUnlockedNode: SkillNodeData | null = null;
- let maxIndex = -1;
-
- for (const skillNode of this.skillNodes) {
- const skillInfo = this.getSkillInfo(skillNode);
- if (skillInfo && this.skillManager?.isSkillUnlocked(skillInfo.skillType, skillNode.group)) {
- const totalIndex = (skillNode.group - 1) * 3 + skillNode.skillIndex;
- if (totalIndex > maxIndex) {
- maxIndex = totalIndex;
- latestUnlockedNode = skillNode;
- }
- }
- }
-
- if (latestUnlockedNode) {
- // 返回节点的Y坐标位置(负值)
- return -latestUnlockedNode.node.position.y;
- }
-
- return 0;
- }
-
- /**
- * 获取当前解锁进度
- * @returns 解锁进度(0-1之间)
- */
- public getUnlockProgress(): number {
- const unlockedCount = this.skillNodes.filter(node => {
- // 使用本地的 isUnlocked 状态来判断节点是否解锁
- return node.isUnlocked;
- }).length;
- const totalNodes = this.skillNodes.length;
- return totalNodes > 0 ? unlockedCount / totalNodes : 0;
- }
-
- /**
- * 输出已解锁技能的数组信息
- * 使用本地的 isUnlocked 状态来记录解锁的技能
- */
- private logUnlockedSkills(): void {
- // 创建一个表示所有技能节点状态的数组
- const skillStatusArray = this.skillNodes.map((node, index) => {
- return {
- index,
- group: node.group,
- skillType: this.getSkillTypeString(node.skillIndex),
- isUnlocked: node.isUnlocked // 使用本地的 isUnlocked 状态
- };
- });
-
- // 输出已解锁的技能节点
- console.log('已解锁技能节点:');
- const unlockedNodes = skillStatusArray.filter(node => node.isUnlocked);
- unlockedNodes.forEach(node => {
- console.log(`[${node.index}] ${node.skillType} Group ${node.group}`);
- });
-
- // 输出下一个待解锁的节点
- const nextNode = skillStatusArray.find(node => !node.isUnlocked);
- if (nextNode) {
- console.log(`下一个待解锁节点: [${nextNode.index}] ${nextNode.skillType} Group ${nextNode.group}`);
- } else {
- console.log('所有技能节点已解锁!');
- }
-
- // 输出解锁进度
- console.log(`解锁进度: ${unlockedNodes.length}/${skillStatusArray.length} (${Math.round(this.getUnlockProgress() * 100)}%)`);
- }
-
- /**
- * 获取技能信息
- * @param skillNodeData 技能节点数据
- * @returns 技能信息对象,包含技能类型和效果百分比
- */
- private getSkillInfo(skillNodeData: SkillNodeData): {skillType: string, effectPercent: number} | null {
- if (!this.skillConfigManager) {
- console.error('SkillConfigManager not initialized');
- return null;
- }
- // 从配置管理器获取技能类型
- const skillType = this.skillConfigManager.getSkillType(skillNodeData.skillIndex);
- if (skillType === 'unknown') {
- console.error(`未知的技能索引: ${skillNodeData.skillIndex}`);
- return null;
- }
-
- // 从配置管理器获取效果百分比
- const effectPercent = this.skillConfigManager.getSkillEffectPercent(skillNodeData.group);
-
- return {
- skillType: skillType,
- effectPercent: effectPercent
- };
- }
-
- /**
- * 根据技能索引获取技能类型字符串
- * @param skillIndex 技能索引 (0: Damage, 1: Ball Speed, 2: Crit Damage)
- * @returns 技能类型字符串
- */
- private getSkillTypeString(skillIndex: number): string {
- if (!this.skillConfigManager) {
- return '未知技能';
- }
- return this.skillConfigManager.getSkillDisplayName(skillIndex);
- }
-
- /**
- * 更新闪烁节点状态
- * 检查哪些节点可以升级并开始闪烁动画
- */
- private updateBlinkingNodes() {
- // 停止所有当前的闪烁动画
- this.stopAllBlinking();
-
- // 获取当前钻石数量
- const currentDiamonds = this.saveDataManager ? this.saveDataManager.getDiamonds() : 0;
-
- // 找到下一个可解锁的节点
- const nextUnlockIndex = this.currentUnlockIndex + 1;
-
- if (nextUnlockIndex < this.skillNodes.length) {
- const nextNode = this.skillNodes[nextUnlockIndex];
- console.log(`[闪烁检查] 下一个节点 - 组别: ${nextNode.group}, 技能: ${this.getSkillTypeString(nextNode.skillIndex)}, 费用: ${nextNode.cost}, 已解锁: ${nextNode.isUnlocked}, 当前钻石: ${currentDiamonds}`);
-
- // 检查是否有足够钻石且节点未解锁
- if (!nextNode.isUnlocked && currentDiamonds >= nextNode.cost) {
- this.startBlinking(nextNode.node);
- } else {
- console.log(`[闪烁检查] 节点不满足闪烁条件`);
- }
- } else {
- console.log(`[闪烁检查] 已达到最后一个节点,无需闪烁`);
- }
- }
-
- /**
- * 开始节点闪烁动画
- * @param node 要闪烁的节点
- */
- private startBlinking(node: Node) {
- if (this.blinkingNodes.has(node)) {
- return; // 已经在闪烁中
- }
-
- this.blinkingNodes.add(node);
-
- // 创建闪烁动画:透明度在0.5和1.0之间循环
- const blinkTween = tween(node)
- .to(0.5, { scale: new Vec3(1.1, 1.1, 1.1) }, { easing: 'sineInOut' })
- .to(0.5, { scale: new Vec3(1.0, 1.0, 1.0) }, { easing: 'sineInOut' })
- .union()
- .repeatForever();
-
- blinkTween.start();
-
- // 将tween存储到节点上,方便后续停止
- node['_blinkTween'] = blinkTween;
- }
-
- /**
- * 停止节点闪烁动画
- * @param node 要停止闪烁的节点
- */
- private stopBlinking(node: Node) {
- if (!this.blinkingNodes.has(node)) {
- return; // 没有在闪烁
- }
-
- this.blinkingNodes.delete(node);
-
- // 停止tween动画
- if (node['_blinkTween']) {
- node['_blinkTween'].stop();
- node['_blinkTween'] = null;
- }
-
- // 重置节点状态
- node.setScale(1, 1, 1);
- }
-
- /**
- * 停止所有闪烁动画
- */
- private stopAllBlinking() {
- for (const node of this.blinkingNodes) {
- if (node['_blinkTween']) {
- node['_blinkTween'].stop();
- node['_blinkTween'] = null;
- }
- node.setScale(1, 1, 1);
- }
- this.blinkingNodes.clear();
- }
-
- /**
- * 当钻石数量变化时调用,更新闪烁状态
- */
- public onDiamondsChanged() {
- this.updateBlinkingNodes();
- }
-
- /**
- * 货币变化事件处理
- */
- private onCurrencyChanged() {
- console.log('[SkillNodeGenerator] 检测到货币变化,更新钻石UI和闪烁状态');
- this.updateDiamondUI();
- }
-
- /**
- * 组件销毁时清理资源
- */
- onDestroy() {
- // 取消事件监听
- EventBus.getInstance().off(GameEvents.CURRENCY_CHANGED, this.onCurrencyChanged, this);
-
- // 停止所有闪烁动画
- this.stopAllBlinking();
- }
- }
|