"use strict"; cc._RF.push(module, '375b0oNLwhN27LKAfsLuxn3', 'cmp.plot.dialogue.wnd'); // Scripts/mod/plot/cmps/cmp.plot.dialogue.wnd.js "use strict"; /****************************************************************** * Copyright(C) 2019 - 2020 Nx Studio * * 剧情对话场景 * * ******************************************************************/ var BridgeWindow = require("bridge.window"); var NxSpine = require("nx.fx.spine"); var BattleController = require("battle_controller"); var DARK = cc.color(57, 57, 57, 255); cc.Class({ "extends": BridgeWindow, properties: { nodTouch: { "default": null, type: cc.Node }, nodBG: { "default": null, type: cc.Node }, spAnim: { "default": null, type: NxSpine }, nodRoles: { "default": null, type: cc.Node }, spAnimMiddle: { "default": null, type: NxSpine }, nodDialog: { "default": null, type: cc.Node }, nodTell: { "default": null, type: cc.Node }, nodSkip: { "default": null, type: cc.Button }, nodTemps: { "default": null, type: cc.Node } }, // 重载:参数打开 onOpenConfigs: function onOpenConfigs(_params) { // 当前无剧本 this.scenario = nx.bridge.plot.vget("info"); if (nx.dt.objEmpty(this.scenario)) { nx.error("$PlotDialogue:对白失败,当前无剧本!"); this.delayClose(); return; } // 初始化环境 this.doPrepare(); // 视图监听 nx.bridge.plot.vbind(this, [["step", this.onStepChanged.bind(this)], ["key", this.onKeyChanged.bind(this)]]); // 自动开始 var step = nx.bridge.plot.vget("step"); if (step < 0) { nx.bridge.plot.next(); } nx.dg = this; }, // 关闭 onDisable: function onDisable() { this.stopSFX(); this.stopVoice(); // 视图解绑 nx.bridge.plot.vunbind(this); }, // 初始化环境 doPrepare: function doPrepare() { var _this = this; // UI初始化 this.nodDialog.active = false; this.nodTell.active = false; // 可否跳过 this.nodSkip.node.active = false; if (this.scenario && this.scenario.skip) { this.nodSkip.interactable = false; nx.tween.delayFadeIn(this.nodSkip, "", 3, 1, function () { _this.nodSkip.interactable = true; }); } // 加载角色模型 this.loadRoles(); }, // 执行单步 doStep: function doStep(_data) { // 无效 if (nx.dt.objEmpty(_data)) { return; } // 当前步信息 this.step = _data; // 背景 if (nx.dt.objNEmpty(_data.bg)) { this.stepBG(_data.bg); return; } // 背景音乐 if (nx.dt.objNEmpty(_data.bgm)) { this.stepBGM(_data.bgm); return; } // Spine if (nx.dt.objNEmpty(_data.spine)) { this.stepSpine(_data.spine); return; } // Spine中间层 if (nx.dt.objNEmpty(_data.spine_mid)) { this.stepSpineMiddle(_data.spine_mid); return; } // 讲述 if (nx.dt.objNEmpty(_data.tell)) { this.stepTell(_data.tell); return; } // 对白 if (nx.dt.arrNEmpty(_data.talks)) { this.stepTalks(_data.talks); return; } // 角色出现 if (nx.dt.objNEmpty(_data.appear)) { this.stepAppear(_data.appear); return; } // 角色离开 if (nx.dt.objNEmpty(_data.disappear)) { this.stepDisAppear(_data.disappear); return; } // 角色聚焦 if (nx.dt.objNEmpty(_data.focus)) { this.stepFocus(_data.focus); return; } // 窗体操作 if (nx.dt.objNEmpty(_data.window)) { this.stepWindow(_data.window); return; } // 等待事件 if (nx.dt.objNEmpty(_data.event)) { this.stepEvent(_data.event); return; } // 特殊操作 if (nx.dt.objNEmpty(_data.special)) { this.stepSpecail(_data.special); return; } // 无效处理 nx.error("$PlotDialogue:无效步骤! ", nx.dt.enjson(_data)); nx.bridge.plot.next(); }, // 步数改变 onStepChanged: function onStepChanged(_step, _, _init) { var step = nx.bridge.plot.stepData(); if (nx.dt.objEmpty(step)) { return; } // 执行 this.doStep(step); }, // ======================================================================== // 角色相关 // ======================================================================== // 加载角色模型 loadRoles: function loadRoles() { var _this2 = this; this.nodRoles.removeAllChildren(true); var roles = nx.dt.objClone(this.scenario.roles); var temp = nx.gui.find(this.nodTemps, "roleT"); this.scenario.roles.forEach(function (role) { var node = cc.instantiate(temp); node.opacity = 0; node.parent = _this2.nodRoles; node.scale = role[2] || 1.0; node.offset = cc.v2(role[3] || 0, role[4] || 0); node.y = role[4] || 0; }); }, // ======================================================================== // 单步处理:角色 // ======================================================================== // 单步执行:角色出现 stepAppear: function stepAppear(_data) { var node = this.nodRoles.children[_data.who]; if (!node) { nx.error("$PlotDialogue:角色未找到! ", _data.who); nx.bridge.plot.next(); return; } // 出现 var self = this; var appear = function appear() { // 出现方式 node.opacity = 255; if (_data.way == "right") { node.x = self.node.width / 2; } else if (_data.way == "left") { node.x = -self.node.width / 2; } // 自动布局 var nodes = []; self.nodRoles.children.forEach(function (_n) { if (_n && _n.opacity > 0) { nodes.push(_n); } }); var space = self.scenario.spaces[nodes.length - 1]; for (var i = 0; i < nodes.length; ++i) { var rd = nodes[i]; var pos = cc.v2(space[i], rd.y); nx.tween.moveTo(rd, "", _data.secs, pos); } // 延迟下一步 self.scheduleOnce(function () { nx.bridge.plot.next(); }, _data.secs * 0.9); }; // 模型载入 if (!node.spine) { var role = this.scenario.roles[_data.who]; var path = cc.path.join("resDB/models", role[1], "show"); node.spine = nx.gui.getComponent(node, "", "nx.fx.spine"); node.spine.play(path, _data.action, function (_event) { if (_event == "start") { appear(); } }, true); nx.gui.setColor(node.spine, "", DARK); return; } appear(); }, // 单步执行:角色离开 stepDisAppear: function stepDisAppear(_data) { var node = this.nodRoles.children[_data.who]; if (!node) { nx.error("$PlotDialogue:角色未找到! ", _data.who); nx.bridge.plot.next(); return; } // 自动布局 var self = this; var autoSpace = function autoSpace() { var nodes = []; self.nodRoles.children.forEach(function (_n) { if (_n && _n.opacity > 0) { nodes.push(_n); } }); var space = self.scenario.spaces[nodes.length - 1]; for (var i = 0; i < nodes.length; ++i) { var rd = nodes[i]; var pos = cc.v2(space[i], rd.y); nx.tween.moveTo(rd, "", _data.secs / 2, pos); } // 延迟下一步 self.scheduleOnce(function () { nx.bridge.plot.next(); }, _data.secs * 0.45); }; nx.tween.fadeOut(node, "", _data.secs / 2, function () { autoSpace(); }); }, // 单步执行:角色聚焦 stepFocus: function stepFocus(_data) { // 音效 this.playSFX(_data.sfx, !!_data.loop); // 重复聚焦 if (this.focus == _data.who) { nx.bridge.plot.next(); return; } // 如果聚焦动作为空,则只改变对白对象 if (nx.dt.strEmpty(_data.action)) { this.focus = _data.who; var _role = this.scenario.roles[this.focus]; nx.gui.setString(this.nodDialog, "title/name", nx.text.getKey(_role[0])); nx.gui.setString(this.nodDialog, "content", ""); this.scheduleOnce(function () { nx.bridge.plot.next(); }, 0.1); return; } // 老的还原 if (nx.dt.numGood(this.focus)) { var _node = this.nodRoles.children[this.focus]; var _spnode = nx.gui.find(_node, "sp"); cc.Tween.stopAllByTarget(_spnode); cc.tween(_spnode).to(_data.secs || 0.1, { scale: 1, color: DARK }).start(); } // 新的聚焦 this.focus = _data.who; if (!nx.dt.numGood(this.focus)) { return; } var node = this.nodRoles.children[this.focus]; var spnode = nx.gui.find(node, "sp"); cc.Tween.stopAllByTarget(spnode); cc.tween(spnode).to(_data.secs || 0.1, { scale: 1.05, color: cc.Color.WHITE }).call(function () { nx.bridge.plot.next(); }).start(); if (nx.dt.strNEmpty(_data.action) && node.spine) { node.spine.action(_data.action, true); } // 说话者信息 var role = this.scenario.roles[this.focus]; nx.gui.setString(this.nodDialog, "title/name", nx.text.getKey(role[0])); nx.gui.setString(this.nodDialog, "content", ""); }, // ======================================================================== // 单步处理:动画 // ======================================================================== // 单步执行 stepSpine: function stepSpine(_data) { var _this3 = this; var path = cc.path.join("prefab/plot/spines", _data.file); var done = function done() { nx.bridge.plot.next(); }; // 播放 nx.gui.setOpacity(this.spAnim, "", 255); this.spAnim.play(path, _data.action, function (_key) { if (_key == "start") { _this3.playSFX(_data.sfx, !!_data.loop); return; } if (_key == "complete" && _data.wait) { done(); return; } }, _data.loop); if (!_data.wait) { done(); } }, // 单步执行 stepSpineMiddle: function stepSpineMiddle(_data) { var _this4 = this; var self = this; var path = cc.path.join("prefab/plot/spines", _data.file); var done = function done() { self.spAnimMiddle.stop(); nx.bridge.plot.next(); }; // 播放 nx.gui.setOpacity(this.spAnimMiddle, "", 255); this.spAnimMiddle.play(path, _data.action, function (_key) { if (_key == "start") { _this4.playSFX(_data.sfx, !!_data.loop); return; } if (_key == "complete" && _data.wait) { done(); return; } }, _data.loop); if (!_data.wait) { done(); } }, // ======================================================================== // 单步处理:背景 // ======================================================================== // 单步执行 // { "bg": { "file":"bg002", "op":"fadeSpine", "opsecs": 5.3 } }, stepBG: function stepBG(_data) { var _this5 = this; var path = cc.path.join("prefab/plot/images", _data.file); // 延迟更变背景,但是不延迟 if (_data.op == "delay") { this.scheduleOnce(function () { nx.gui.setSpriteFrame(_this5.nodBG, "", path); }, _data.opsecs || 0.3); nx.bridge.plot.next(); return; } nx.gui.setSpriteFrame(this.nodBG, "", path); // 背景&&动画 淡进淡出切换 if (_data.op == "fadeSpine") { nx.tween.fadeOut(this.spAnim, "", _data.opsecs || 0.5); nx.tween.fadeIn(this.nodBG, "", _data.opsecs || 0.5, function () { nx.bridge.plot.next(); }); return; } // 直接下一步 nx.bridge.plot.next(); }, // ======================================================================== // 单步处理:背景音乐 // ======================================================================== // 单步执行 // { "bg": { "file":"bg002" } }, stepBGM: function stepBGM(_data) { var cmp = nx.gui.getComponent(this, "", "nx.fx.BGM"); if (cmp) { cmp.reset(); cmp.bgmRK = cc.path.join("prefab/plot/audios", _data.file); cmp.reActive(); } // 直接下一步 nx.bridge.plot.next(); }, // ======================================================================== // 单步处理:对白 // ======================================================================== // 单步执行 stepTalks: function stepTalks(_data) { this.talks = nx.dt.objClone(_data); this.doTalk(); }, // 单步对话 doTalk: function doTalk() { if (nx.dt.arrEmpty(this.talks)) { this.nodDialog.active = false; nx.bridge.plot.next(); return; } var data = this.talks.shift(); if (nx.dt.objEmpty(data)) { this.doTalk(); return; } this.nodDialog.active = true; // 当前动作 var node = this.nodRoles.children[this.focus]; if (node && node.spine) { // 动作 if (nx.dt.strNEmpty(data.action)) { node.spine.action(data.action, true); } // 播放速度 if (nx.dt.numPositive(data.speed, false)) { node.spine.setTimeScale(data.speed); } } // 内容 if (data.words && nx.dt.strNEmpty(data.words)) { var txt = nx.text.getKey(data.words); txt = nx.text.formatS("%s", txt); var cmp = nx.gui.setString(this.nodDialog, "content", txt); if (cmp) { cmp.fontSize = data.fontSize || 22; cmp.lineHeight = cmp.fontSize * 1.5; var scale = nx.gui.getComponent(cmp, "", "nx.fx.local.text"); if (scale) { scale.autoScale(); } } } // 抖动 if (nx.dt.objNEmpty(data.shake)) { var secs = data.shake.secs || 0.5; var offset = cc.v2(data.shake.x || 10, data.shake.y || 10); nx.tween.shake(this.nodDialog, "content", secs, offset); } // 语音 this.playVoice(data.voice); // 继续 nx.gui.setActive(this.nodDialog, "continue", this.talks.length > 1); }, // ======================================================================== // 单步处理:窗体 // ======================================================================== // 单步执行 stepWindow: function stepWindow(_data) { // 关闭窗体 if (nx.dt.strNEmpty(_data.close)) { nx.bridge.closePanel(_data.close); } // 打开窗体 if (nx.dt.strNEmpty(_data.open)) { nx.bridge.createPanel(_data.open, _data.args || {}); } nx.bridge.plot.next(); }, // ======================================================================== // 单步处理:事件 // ======================================================================== // 单步执行 stepEvent: function stepEvent(_data) { this.wkey = _data.key || ""; }, // 触发事件改变 onKeyChanged: function onKeyChanged(_key, _, _init) { if (_init || nx.dt.strEmpty(_key)) { return; } if (this.wkey == _key) { nx.bridge.plot.next(); } }, // ======================================================================== // 单步处理:特殊操作 // ======================================================================== // 单步执行 stepSpecail: function stepSpecail(_data) { var _this6 = this; if (nx.dt.strEmpty(_data.key)) { nx.error("$PlotDialogue:特殊操作失败,关键字缺失!"); nx.bridge.plot.next(); return; } // 全隐 if (_data.key == "hide") { nx.bridge.plot.next(); this.scheduleOnce(function () { _this6.node.opacity = 0; _this6.nodTouch.active = false; nx.gui.getComponent(_this6, "", cc.BlockInputEvents).enabled = false; }, _data.delay || 0.1); return; } // 全显 if (_data.key == "show") { this.node.opacity = 255; this.nodTouch.active = true; nx.gui.getComponent(this, "", cc.BlockInputEvents).enabled = true; nx.bridge.plot.next(); return; } // 首战 if (_data.key == "fstBattle") { var BC = BattleController.getInstance(); BC.requestUseHeroBattle(); this.wkey = _data.event; return; } }, // ======================================================================== // 单步处理:讲述 // ======================================================================== // 单步讲述 stepTell: function stepTell(_data) { if (nx.dt.objEmpty(_data)) { this.nodTell.active = false; nx.bridge.plot.next(); return; } this.nodTell.active = true; var txt = nx.text.getKey(_data.words); nx.gui.setString(this.nodTell, "txt", txt); var self = this; nx.tween.fadeIn(this.nodTell, "txt", _data.fadeIn, function () { self.scheduleOnce(function () { nx.tween.fadeOut(self.nodTell, "txt", _data.fadeOut, function () { self.nodTell.active = false; nx.bridge.plot.next(); }); }, _data.delay); }); this.playVoice(_data.voice); }, // ======================================================================== // 音效处理 // ======================================================================== // 互斥播放 playSFX: function playSFX(_sfx, _loop) { var _this7 = this; if (_loop === void 0) { _loop = true; } if (nx.dt.strEmpty(_sfx)) { return; } var path = cc.path.join("prefab/plot/audios", _sfx); // 老音效判断 if (this.sfxAction) { // 是否已经结束 if (!nx.audio.isSFXPlaying(this.sfxAction.handle)) { this.sfxAction.path = ""; this.sfxAction.handle = -1; } // 重复播放 if (this.sfxAction.path == path) { return; } // 关闭 if (this.sfxAction.handle > 0) { nx.audio.stopSFX(this.sfxAction.handle); } this.sfxAction = null; } nx.audio.playSFX(path, _loop, function (_err, _id, _path) { if (!_err) { _this7.sfxAction = { path: _path || path, handle: _id }; } }); }, // 立即清理 stopSFX: function stopSFX() { if (this.sfxAction) { nx.audio.stopSFX(this.sfxAction.handle); this.sfxAction = null; } }, // ======================================================================== // 语音处理 // ======================================================================== // 播放 playVoice: function playVoice(_voice) { var _this8 = this; if (nx.dt.strEmpty(_voice)) { return; } var path = cc.path.join("prefab/plot/audios", _voice); // 老音效判断 if (this.sfxVoice) { // 是否已经结束 if (!nx.audio.isSFXPlaying(this.sfxVoice.handle)) { this.sfxVoice.path = ""; this.sfxVoice.handle = -1; } // 重复播放 if (this.sfxVoice.path == path) { return; } // 关闭 if (this.sfxVoice.handle > 0) { nx.audio.stopVoice(this.sfxVoice.handle); } this.sfxVoice = null; } nx.audio.playVoice(path, function (_err, _id, _path) { if (!_err) { _this8.sfxVoice = { path: _path || path, handle: _id }; } }); }, // 语音关闭 stopVoice: function stopVoice() { if (this.sfxVoice) { nx.audio.stopSFX(this.sfxVoice.handle); this.sfxVoice = null; } }, // ======================================================================== // 用户输入 // ======================================================================== // 点击跳过 onTouchSkip: function onTouchSkip() { nx.bridge.plot.done(); this.close(); }, // 点击继续 onTouchContinue: function onTouchContinue() {} }); cc._RF.pop();