import { _decorator, Label, Node, sp, tween, UITransform, Sprite, SpriteFrame, Component } from 'cc';
import { GameEvent } from '../../GameEvent';
import { MainModel } from '../main/MainModel';
import { oops } from "../../../oops/core/Oops";
import { ProxyRewards } from '../rewards/ProxyRewards';
import ListView from '../../../gamebase/uicore/ListView';
import { JuQing_ZhangJieView } from './JuQing_ZhangJieView';
import { JuQing_ZhangJieModel } from './JuQing_ZhangJieModel';
import { ProxyJuQing_ZhangJie } from './ProxyJuQing_ZhangJie';
import { ResHelper } from '../../../gamebase/helper/ResHepler';
import { RewardsController } from '../rewards/RewardsController';
import { JuQingZhangJie } from '../../../gameproto/config/schema';
import { DataCache } from '../../../gamebase/datacache/DataCache';
import { UIController } from '../../../gamebase/uicore/UIController';
import { ModelManager } from '../../../gamebase/manager/ModelManager';
import { EffectManager } from "../../../gamebase/manager/EffectManager";
import { AudioManager } from '../../../oops/core/common/audio/AudioManager';
import { LocalizationManager } from '../../../gamebase/manager/LocalizationManager';
import { JuQing_ZhangJieItemController } from '../sub/juqing_zhangjieitem/JuQing_ZhangJieItemController';
const { ccclass, property } = _decorator;
/** 章节控制器 */
@ccclass('JuQing_ZhangJieController')
export class JuQing_ZhangJieController extends UIController<JuQing_ZhangJieView> {
//#region 初始化
public static NAME: string = "JuQing_ZhangJieController";
private zhangjieListView: ListView;
private zhangjiefgList: JuQingZhangJie[] = [];
private audioManager: AudioManager;
// 使用getter缓存常用模型引用
private get mainModel(): MainModel { return ModelManager.instance.MainModel; }
private get juQing_ZhangJieModel(): JuQing_ZhangJieModel { return ModelManager.instance.JuQing_ZhangJieModel; }
// 缓存常用UI组件引用
private _pangbaiLabel: Label;
private _zimuLabel: Label;
private _changjingBg: Sprite;
/** 顺序0 - 此处勿修改 */
protected OnSetView(): void {
super.OnSetView();
this.SetView(new JuQing_ZhangJieView(this.node));
// 缓存UI组件引用
this._pangbaiLabel = this.view.pangbaiLabel;
this._zimuLabel = this.view.zimuLabel;
this._changjingBg = this.view.changjingBg;
}
/** 顺序1 - 界面初始显示 */
protected OnInit(): void {
super.OnInit();
this.audioManager = this.node.getComponent(AudioManager) || this.node.addComponent(AudioManager);
this.audioManager.load();
}
/** 顺序2 - 在此注册UI控件事件 */
protected OnRegisterUIEvent(): void {
super.OnRegisterUIEvent();
this.view.BtnClose?.reg(this.onBtnCloseHandler.bind(this));
}
/** 顺序3 - 在此注册全局事件 */
protected OnRegisterMessage(): void {
super.OnRegisterMessage();
oops.message.on(GameEvent.RefreshJuJiList, this.updateUI, this);
}
protected OnDispose(): void {
super.OnDispose();
this.view.BtnClose?.unRegAll();
oops.message.off(GameEvent.RefreshJuJiList, this.updateUI, this);
this.audioManager.stopAll();
this._juqingEffects.clearAll();
}
/** 语言切换时触发 */
protected OnLanguageChanged(): void {
super.OnLanguageChanged();
this.updateUI();
}
private getPanelViewName(path: string): string {
return ProxyJuQing_ZhangJie.PrefixPath + path;
}
//#endregion
//#region events
private onBtnCloseHandler() {
if (this.isFreeze) return;
ProxyJuQing_ZhangJie.Close();
}
//#endregion
private _gushiId: number;
public setJuQingId(gushiId: number): void {
this._gushiId = gushiId;
this.zhangjiefgList = DataCache.tables.TbJuQingZhangJie.getDataList().filter(item => item.gushiid === this._gushiId);
this.zhangjieListView = this.view.listView.getComponent(ListView);
this.zhangjieListView.onLoad();
this.zhangjieListView.onItemRender = this.onItemRender.bind(this);
this.zhangjieListView.numItems = this.zhangjiefgList.length;
this._juqingEffects.setController(this);
this.updateUI();
}
// 使用私有类替代立即执行函数
private _juqingEffects = new (class extends Component {
private _effectMap = new Map<number, Node>();
private _controller: JuQing_ZhangJieController;
private _pendingRemoval: number | null = null;
private beishu = 1;
// 标记是否已显示结束旁白
private isEndPangbaiShown = false;
// 文本索引
private pangbaiIndex = 0;
private zimuIndex = 0;
private eddpangbaiIndex = 0;
// 章节ID和剧情ID
private zhangjieId: number = 0;
private juqingId: number = 0;
onLoad() {
this._effectMap = new Map();
}
setController(controller: JuQing_ZhangJieController) {
this._controller = controller;
}
// 添加剧情特效
addEffect(zhangjieID: number, juqingID: number, beishu: number, parentNode: Node) {
this.beishu = beishu;
this.zhangjieId = zhangjieID;
this.juqingId = juqingID;
this.isEndPangbaiShown = false; // 重置标记
this.pangbaiIndex = 0; // 重置旁白索引
this.zimuIndex = 0; // 重置字幕索引
this.eddpangbaiIndex = 0; // 重置结束旁白索引
if (!parentNode) {
console.error("剧情特效父节点为空");
return;
}
const juqingCfg = DataCache.tables.TbJuQingChangGing.get(this.juqingId);
if (!juqingCfg) {
console.error(`未找到剧情配置,ID: ${this.juqingId}`);
return;
}
EffectManager.instance.loadSpineEffect(juqingCfg.juqingziyuan, parentNode, (eff) => {
if (!eff) {
console.error("加载剧情动画失败:", juqingCfg.juqingziyuan);
return;
}
if (this._effectMap.has(this.juqingId)) {
EffectManager.instance.putSpine(eff);
return;
}
this._effectMap.set(this.juqingId, eff);
eff.setSiblingIndex(1); // 确保动画在背景之上
const spine = eff.getComponentInChildren(sp.Skeleton);
// 在addEffect方法中添加
if (spine) {
spine.timeScale = this.beishu; // 直接应用当前倍速
// 开始播放动画的事件监听
spine.setStartListener(() =>
this.onSpineStart(spine, parentNode, juqingCfg)
);
//用来设置动画播放过程中帧事件的监听
spine.setEventListener((entry: sp.spine.TrackEntry, event: sp.spine.Event,) => {
this.handleSpineEvent(entry, event, juqingCfg);
});
// 动画播放一次循环结束后的事件监听
spine.setCompleteListener(() =>
this.onSpineComplete(this.juqingId, parentNode)
);
}
}, "animation", 1, false);
}
/** 设置开始播放动画的事件监听 */
private onSpineStart(spine: sp.Skeleton, parent: Node, cfg: any) {
this.scheduleOnce(() => {
oops.audio.pauseMusic();
// 显示退出按钮
this._controller.view.BtnTuiChu.reg(() => {
this.setupTuiChuControl();
});
//显示倍数 设置倍数
this._controller.view.beisuLabel.string = `x${this.beishu}`;
// 缓存当前spine实例引用
const currentSpine = spine;
currentSpine.timeScale = this.beishu;
this._controller.view.BeishuButton.reg(() => {
this.setupBeishuControl(currentSpine);
});
// 加载并显示背景图
this._controller._changjingBg.node.active = false;
if (cfg.juqingchangjingBg) {
// 使用 LocalizationManager 加载背景图,调整参数顺序
LocalizationManager.instance.setSpriteFrame(this._controller._changjingBg, `uiatlas/${cfg.juqingchangjingBg}`, (err) => {
if (err) {
console.error(`加载背景图失败: ${err}`);
return;
}
// 调整背景图大小以适应父节点
const parentSize = parent.getComponent(UITransform)?.contentSize;
if (parentSize) {
this._controller._changjingBg.getComponent(UITransform)!.setContentSize(parentSize);
}
// 图片加载完成后显示背景图
this._controller._changjingBg.node.active = true;
});
}
});
}
/** 用来设置动画播放过程中帧事件的监听*/
private handleSpineEvent(entry: sp.spine.TrackEntry, event: sp.spine.Event, cfg: any) {
console.log(`[事件触发] 动画:${entry.animation.name} 事件:${event.data.name}`);
const audioPath = `audio/bgm/${event.data.name}`;
this._controller.audioManager.playMusic(audioPath, false);
// 显示开始旁白
this.showNextPangbai(cfg);
// });
}
/**动画播放一次循环结束后的事件监听 */
private onSpineComplete(juqingId: number, parent: Node) {
// 动画结束时停止音乐
oops.audio.stopMusic();
// 隐藏所有标签
this._controller._pangbaiLabel.node.active = false;
this._controller._zimuLabel.node.active = false;
// 处理结束事件
const changjingCfg = DataCache.tables.TbJuQingChangGing.get(juqingId);
if (changjingCfg && changjingCfg.jieshushijian.length > 0) {
const condition = changjingCfg.jieshushijian[0];
switch (condition.type) {
case 1:
const nextId = Number(condition.param);
if (nextId > 0) {
this.removeEffect(juqingId);
this.addEffect(this.zhangjieId, nextId, this.beishu, parent);
return;
}
break;
}
}
// 恢复背景音乐
oops.audio.resumeMusic();
// 最终章节处理逻辑
this.handleFinalChapter(changjingCfg);
}
/** 退出按钮*/
private setupTuiChuControl() {
this.clearAll();
this._controller._changjingBg.node.active = false;
oops.audio.resumeMusic();
this._controller.updateUI();
}
/** 倍数按钮*/
private setupBeishuControl(spine: sp.Skeleton) {
const targetSpeed = this.beishu === 1 ? 2 : 1;
// 使用tween实现平滑过渡
tween(spine)
.to(0.3, { timeScale: targetSpeed })
.call(() => {
this.beishu = targetSpeed;
this._controller.view.beisuLabel.string = `x${this.beishu}`;
})
.start();
}
// 显示下一条旁白
private showNextPangbai(juqingCfg: any) {
const pangbaiTexts = juqingCfg.startpangbai?.map(item => LocalizationManager.instance.get(item)) || [];
if (this.pangbaiIndex < pangbaiTexts.length) {
const pangbaiLabel = this._controller._pangbaiLabel;
pangbaiLabel.node.active = true;
pangbaiLabel.string = pangbaiTexts[this.pangbaiIndex];
this.pangbaiIndex++;
} else {
this._controller._pangbaiLabel.node.active = false;
this.showNextZimu(juqingCfg)
}
}
// 显示下一条字幕
private showNextZimu(juqingCfg: any) {
const zimuTexts = juqingCfg.zimu?.map(item => LocalizationManager.instance.get(item)) || [];
if (this.zimuIndex < zimuTexts.length) {
const zimuLabel = this._controller._zimuLabel;
zimuLabel.node.active = true;
zimuLabel.string = zimuTexts[this.zimuIndex];
this.zimuIndex++;
} else {
this._controller._zimuLabel.node.active = false;
this.showEndPangbai(juqingCfg);
}
}
// 显示结束旁白
private showEndPangbai(juqingCfg: any) {
const eddpangbaiTexts = juqingCfg.endpangbai?.map(item => LocalizationManager.instance.get(item)) || [];
if (this.eddpangbaiIndex < eddpangbaiTexts.length) {
const eddpangbaiLabel = this._controller._pangbaiLabel;
eddpangbaiLabel.node.active = true;
eddpangbaiLabel.string = eddpangbaiTexts[this.eddpangbaiIndex];
this.eddpangbaiIndex++;
this.isEndPangbaiShown = true;
} else {
this._controller._pangbaiLabel.node.active = false;
}
}
// 处理最终章节逻辑
private handleFinalChapter(changjingCfg: any) {
// 首次观看时才显示奖励弹窗
const watchedEpisodes = this._controller.mainModel.gameData.juqingData.episodeStoryMap[changjingCfg.gushiid] || [];
if (!watchedEpisodes.includes(this.juqingId)) {
const rewardDatas = changjingCfg.rewardDatas;
if (rewardDatas && rewardDatas.length > 0) {
const rewardList = [{ items: rewardDatas }];
this._pendingRemoval = this.juqingId;
ProxyRewards.Open((ctrl) => {
(ctrl as RewardsController).onRewards(rewardList);
ctrl.onClose = () => {
if (this._pendingRemoval !== null) {
this.clearAll();
this._pendingRemoval = null;
this._controller._changjingBg.node.active = false;
}
oops.message.dispatchEvent(GameEvent.RefreshJuJiList);
};
});
} else {
this.clearAll();
oops.message.dispatchEvent(GameEvent.RefreshJuJiList);
}
} else {
this.clearAll();
this._controller._changjingBg.node.active = false;
oops.message.dispatchEvent(GameEvent.RefreshJuJiList);
}
// 记录已观看章节到对应故事
if (changjingCfg) {
const gushiid = changjingCfg.gushiid;
const episodeMap = this._controller.mainModel.gameData.juqingData.episodeStoryMap;
if (!episodeMap[gushiid]) {
episodeMap[gushiid] = [];
}
if (!episodeMap[gushiid].includes(this.juqingId)) {
episodeMap[gushiid].push(this.juqingId);
this._controller.mainModel.saveMainData();
}
}
// 消耗能量
const episodeCfg = DataCache.tables.TbJuQingZhangJie.get(this.zhangjieId);
this._controller.mainModel.consumeEnergyItem(episodeCfg.xiaohaonum);
}
// 移除剧情特效
removeEffect(zhangjieId: number) {
if (this._effectMap.has(zhangjieId)) {
let effNode = this._effectMap.get(zhangjieId);
EffectManager.instance.put(effNode);
this._effectMap.delete(zhangjieId);
// 清除旧事件监听
this._controller.view.BeishuButton.unRegAll();
}
}
// 清除所有剧情特效
clearAll() {
this._effectMap.forEach((node) => {
node.removeFromParent(); // 从父节点移除
node.destroy(); // 销毁节点
});
this._effectMap.clear();
this._controller.audioManager.stopMusic();
// 重置所有状态
this.isEndPangbaiShown = false;
this.pangbaiIndex = 0;
this.zimuIndex = 0;
this.eddpangbaiIndex = 0;
// 取消按钮事件注册
this._controller.view.BtnTuiChu.unRegAll();
this._controller.view.BeishuButton.unRegAll();
}
})();
private onItemRender(index: number, item: Node) {
let ctrl = item.getComponent(JuQing_ZhangJieItemController);
if (!ctrl.view) {
ctrl.Setup();
}
const zhangjieData = this.zhangjiefgList[index];
ctrl.onInitView(zhangjieData, this);
const playButton = ctrl.view.TiLiButton;
if (playButton && this.juQing_ZhangJieModel.checkZhangJieUnlockCondition(zhangjieData.id)) {
playButton.reg(() => {
const episodeCfg = DataCache.tables.TbJuQingZhangJie.get(zhangjieData.id);
if (this.mainModel.gameData.rewards[3] < episodeCfg.xiaohaonum) {
return oops.gui.toast("货币不足");
}
this._juqingEffects.addEffect(zhangjieData.id, zhangjieData.juqingid, 1, this.view.juqing);
this.view.juqing.active = true;
this.view.TitleBar.active = false;
this.view.Bg_1.node.active = false;
this.view.Bg_2.node.active = true;
});
}
}
public updateUI() {
this.view.juqing.active = false;
this.view.Bg_2.node.active = false;
this.view.TitleBar.active = true;
this.view.Bg_1.node.active = true;
// 重置文本标签
this._pangbaiLabel.string = "";
this._zimuLabel.string = "";
const juqingcfg = DataCache.tables.TbJuQing.get(this._gushiId);
const maxLength = 61;
const storyText = LocalizationManager.instance.get(juqingcfg.gushi) || '未命名';
const displayText = storyText.length > maxLength ? storyText.slice(0, maxLength) + '...' : storyText;
this.view.jianjieLabel.string = `剧情简介: ${displayText}`;
this.view.titleNameLabel.string = LocalizationManager.instance.get(juqingcfg.gushiname) || '未命名';
// 更新观看进度
const watchedCount = this.juQing_ZhangJieModel.getWatchedEpisodesCountByStory(this._gushiId);
const totalCount = this.zhangjiefgList.length;
this.view.jinduLabel.string = `观看进度: ${watchedCount}/${totalCount}`;
// 图标
let iconPath = ResHelper.getJuQingPath(juqingcfg.icon);
LocalizationManager.instance.setSpriteFrame(this.view.icon, iconPath);
}
}那这个功能怎么实现音频变速