import { _decorator, Component, Node, resources, JsonAsset, Sprite, SpriteFrame, Label, Button, director } from 'cc'; import { DialogueBox } from './DialogueBox'; import { CharacterView } from './CharacterView'; import { ChoiceButton } from './ChoiceButton'; import { AffectionSystem } from './AffectionSystem'; const { ccclass, property } = _decorator; // 剧情数据结构 interface StoryData { title: string; scenes: SceneData[]; } interface SceneData { id: string; background?: string; characters: CharacterShowData[]; dialogue: DialogueData[]; choices?: ChoiceData[]; nextScene?: string; } interface CharacterShowData { id: string; name: string; emotion: string; position: 'left' | 'center' | 'right'; visible: boolean; } interface DialogueData { speaker?: string; text: string; emotion?: string; } interface ChoiceData { text: string; nextScene: string; affectionChange?: { [key: string]: number }; } @ccclass('StoryManager') export class StoryManager extends Component { private static _instance: StoryManager = null; public static get instance(): StoryManager { return StoryManager._instance; } @property(DialogueBox) dialogueBox: DialogueBox; @property(CharacterView) characterView: CharacterView; @property(Node) choiceContainer: Node; @property(AffectionSystem) affectionSystem: AffectionSystem; private storyData: StoryData = null; private currentScene: SceneData = null; private currentDialogueIndex: number = 0; private isTyping: boolean = false; onLoad() { StoryManager._instance = this; } start() { // 自动加载第一章 this.loadChapter('chapter1'); } /** * 加载剧情章节 */ loadChapter(chapterId: string) { resources.load(`story/${chapterId}`, JsonAsset, (err, jsonAsset) => { if (err) { console.error('加载剧情失败:', err); return; } this.storyData = jsonAsset.json as StoryData; console.log('剧情加载成功:', this.storyData.title); // 开始播放第一个场景 if (this.storyData.scenes.length > 0) { this.playScene(this.storyData.scenes[0].id); } }); } /** * 播放指定场景 */ playScene(sceneId: string) { const scene = this.storyData.scenes.find((s) => s.id === sceneId); if (!scene) { console.error('未找到场景:', sceneId); return; } this.currentScene = scene; this.currentDialogueIndex = 0; // 设置背景 if (scene.background) { this.loadBackground(scene.background); } // 更新角色显示 this.updateCharacters(scene.characters); // 隐藏选项 this.hideChoices(); // 开始对话 this.showNextDialogue(); } /** * 显示下一句对话 */ showNextDialogue() { if (!this.currentScene) return; // 检查是否还有对话 if (this.currentDialogueIndex >= this.currentScene.dialogue.length) { this.onDialogueEnd(); return; } const dialogue = this.currentScene.dialogue[this.currentDialogueIndex]; // 更新对话框 this.dialogueBox.show(dialogue.speaker, dialogue.text, () => { this.isTyping = false; }); // 更新立绘表情 if (dialogue.emotion && this.characterView) { this.characterView.setEmotion(dialogue.emotion); } this.currentDialogueIndex++; this.isTyping = true; } /** * 点击对话区域继续 */ onDialogueClicked() { if (this.isTyping) { // 打字时点击直接显示完整文本 this.dialogueBox.finishTyping(); this.isTyping = false; } else { // 显示下一句 this.showNextDialogue(); } } /** * 对话结束处理 */ private onDialogueEnd() { if (!this.currentScene) return; // 检查是否有选项 if (this.currentScene.choices && this.currentScene.choices.length > 0) { this.showChoices(this.currentScene.choices); } // 检查是否有下一场景 else if (this.currentScene.nextScene) { this.playScene(this.currentScene.nextScene); } else { console.log('剧情结束'); } } /** * 显示选项 */ private showChoices(choices: ChoiceData[]) { this.hideChoices(); choices.forEach((choice, index) => { const choiceNode = this.choiceContainer.children[index]; if (choiceNode) { choiceNode.active = true; const choiceBtn = choiceNode.getComponent(ChoiceButton); if (choiceBtn) { choiceBtn.setup(choice.text, () => { this.onChoiceSelected(choice); }); } } }); } /** * 隐藏选项 */ private hideChoices() { this.choiceContainer.children.forEach(child => { child.active = false; }); } /** * 选择选项 */ private onChoiceSelected(choice: ChoiceData) { // 更新好感度 if (choice.affectionChange) { this.affectionSystem.changeAffection(choice.affectionChange); } // 跳转到下一场景 if (choice.nextScene) { this.playScene(choice.nextScene); } } /** * 加载背景图 */ private loadBackground(bgPath: string) { resources.load(`backgrounds/${bgPath}`, SpriteFrame, (err, spriteFrame) => { if (err) { console.error('加载背景失败:', err); return; } // 假设有一个背景节点 const bgNode = this.node.getChildByName('Background'); if (bgNode) { const sprite = bgNode.getComponent(Sprite); if (sprite) { sprite.spriteFrame = spriteFrame; } } }); } /** * 更新角色显示 */ private updateCharacters(characters: CharacterShowData[]) { if (!this.characterView) return; characters.forEach(char => { if (char.visible) { this.characterView.showCharacter(char.id, char.name, char.emotion, char.position); } else { this.characterView.hideCharacter(char.id); } }); } /** * 跳转到指定场景(可外部调用) */ public goToScene(sceneId: string) { this.playScene(sceneId); } /** * 重新开始 */ public restart() { if (this.storyData && this.storyData.scenes.length > 0) { this.affectionSystem.reset(); this.playScene(this.storyData.scenes[0].id); } } }