From 115811447ad3e71c2cd7dee2a52ee45b57e98eac Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 8 Aug 2021 12:29:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=9A=E5=AF=B9=E8=AF=9D=E6=A1=86=20&=20?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E5=AF=B9=E8=AF=9D=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _server/MotaAction.g4 | 44 ++++++++++++++--- _server/MotaActionParser.js | 14 ++++-- _server/editor_blocklyconfig.js | 4 +- libs/actions.js | 56 ++++++++++------------ libs/events.js | 83 ++++++++++++++++++++++++++++++++- libs/ui.js | 20 ++++++-- 6 files changed, 173 insertions(+), 48 deletions(-) diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 10468310..26e42096 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -771,6 +771,8 @@ action : text_0_s | text_1_s | text_2_s + | moveTextBox_s + | clearTextBox_s | comment_s | autoText_s | scrollText_s @@ -915,7 +917,7 @@ text_0_s tooltip : text:显示一段文字(剧情) helpUrl : /_docs/#/instruction previewBlock : true -default : ["欢迎使用事件编辑器(回车直接多行编辑)"] +default : ["欢迎使用事件编辑器(双击方块可直接预览)"] var code = '"'+EvalString_Multi_0+'"'; if (block.isCollapsed() || !block.isEnabled()) { code = '{"type": "text", "text": '+code; @@ -927,7 +929,7 @@ return code+',\n'; */; text_1_s - : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点像素 px' PosString? 'py' PosString? '宽度' PosString? BGNL? Newline EvalString_Multi Newline + : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点像素 px' PosString? 'py' PosString? '宽度' PosString? '对话框编号' Int BGNL? Newline EvalString_Multi Newline /* text_1_s @@ -935,7 +937,7 @@ tooltip : text:显示一段文字(剧情),选项较多请右键点击帮 helpUrl : /_docs/#/instruction previewBlock : true allIds : ['EvalString_1'] -default : ["小妖精","fairy","","","","","欢迎使用事件编辑器(回车直接多行编辑)"] +default : ["小妖精","fairy","","","","",0,"欢迎使用事件编辑器(双击方块可直接预览)"] var title=''; if (EvalString_0==''){ if (EvalString_1=='' )title=''; @@ -956,9 +958,10 @@ if(EvalString_2 && !(/^(up|center|down|hero|this)(,(hero|null|\d+,\d+|\d+))?$/.t } EvalString_2 = EvalString_2 && ('\\b['+EvalString_2+']'); var code = '"'+title+EvalString_2+EvalString_Multi_0+'"'; -if (block.isCollapsed() || !block.isEnabled() || pos) { +if (block.isCollapsed() || !block.isEnabled() || pos || Int_0) { code = '{"type": "text", "text": '+code; if (pos) code += ', "pos": ' + pos; + if (Int_0) code += ', "code": ' + Int_0; if (block.isCollapsed()) code += ', "_collapsed": true'; if (!block.isEnabled()) code += ', "_disabled": true'; code += '}'; @@ -967,7 +970,7 @@ return code+',\n'; */; text_2_s - : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点像素 px' PosString? 'py' PosString? '宽度' PosString? BGNL? Newline EvalString_Multi BGNL? Newline textDrawingList* Newline + : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点像素 px' PosString? 'py' PosString? '宽度' PosString? '对话框编号' Int BGNL? Newline EvalString_Multi BGNL? Newline textDrawingList* Newline /* text_2_s @@ -975,7 +978,7 @@ tooltip : text:显示一段文字(剧情),选项较多请右键点击帮 helpUrl : /_docs/#/instruction previewBlock : true allIds : ['EvalString_1'] -default : ["小妖精","fairy","","","","","欢迎使用事件编辑器(回车直接多行编辑)",null] +default : ["小妖精","fairy","","","","",0,"欢迎使用事件编辑器(双击方块可直接预览)",null] var title=''; if (EvalString_0==''){ if (EvalString_1=='' )title=''; @@ -996,9 +999,10 @@ if(EvalString_2 && !(/^(up|center|down|hero|this)(,(hero|null|\d+,\d+|\d+))?$/.t } EvalString_2 = EvalString_2 && ('\\b['+EvalString_2+']'); var code = '"'+title+EvalString_2+textDrawingList_0.replace(/\s/g, '')+EvalString_Multi_0+'"'; -if (block.isCollapsed() || !block.isEnabled() || pos) { +if (block.isCollapsed() || !block.isEnabled() || pos || Int_0) { code = '{"type": "text", "text": '+code; if (pos) code += ', "pos": ' + pos; + if (Int_0) code += ', "code": ' + Int_0; if (block.isCollapsed()) code += ', "_collapsed": true'; if (!block.isEnabled()) code += ', "_disabled": true'; code += '}'; @@ -1059,6 +1063,32 @@ var code = ''; return code; */; +moveTextBox_s + : '移动对话框' ':' Int 'px' PosString 'py' PosString '使用增量' Bool '移动方式' MoveMode_List '动画时间' Int '不等待执行完毕' Bool Newline + +/* moveTextBox_s +tooltip : 移动对话框 +helpUrl : /_docs/#/instruction +default : [1,"0","0",false,'',500,false] +MoveMode_List_0 = (MoveMode_List_0!=='') ? (', "moveMode": "'+MoveMode_List_0+'"'):''; +Bool_0 = Bool_0 ?', "relative": true':''; +Bool_1 = Bool_1 ?', "async": true':''; +var code = '{"type": "moveTextBox", "code": '+Int_0+', "loc": ['+PosString_0+','+PosString_1+']'+Bool_0+MoveMode_List_0+', "time": '+Int_1+Bool_1+'},\n'; +return code; +*/; + +clearTextBox_s + : '清除对话框' ':' Int Newline + +/* clearTextBox_s +tooltip : 清除对话框 +helpUrl : /_docs/#/instruction +default : [1] +var code = '{"type": "clearTextBox", "code": '+Int_0+'},\n'; +return code; +*/; + + comment_s : '添加注释' ':' EvalString_Multi Newline diff --git a/_server/MotaActionParser.js b/_server/MotaActionParser.js index 4ce7e408..6d254695 100644 --- a/_server/MotaActionParser.js +++ b/_server/MotaActionParser.js @@ -283,18 +283,26 @@ ActionParser.prototype.parseAction = function() { } data.pos = data.pos || []; this.next = MotaActionFunctions.xmlText('text_2_s', [ - info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], info[3], buildTextDrawing(textDrawing), this.next + info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], data.code||0, info[3], buildTextDrawing(textDrawing), this.next ], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); - } else if (info[0] || info[1] || info[2] || data.pos) { + } else if (info[0] || info[1] || info[2] || data.pos || data.code) { data.pos = data.pos || []; this.next = MotaActionFunctions.xmlText('text_1_s',[ - info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], info[3], this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); + info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], data.code||0, info[3], this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); } else { this.next = MotaActionFunctions.xmlText('text_0_s', [info[3],this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); } break; + case "moveTextBox": // 移动对话框 + data.loc = data.loc || ['','']; + this.next = MotaActionBlocks['moveTextBox_s'].xmlText([ + data.code, data.loc[0], data.loc[1], data.relative||false, data.moveMode, data.time, data.async, this.next]); + break; + case "clearTextBox": // 清除对话框 + this.next = MotaActionBlocks['clearTextBox_s'].xmlText([data.code,this.next]); + break; case "autoText": // 自动剧情文本 var info = this.getTitleAndPosition(data.text); this.next = MotaActionBlocks['autoText_s'].xmlText([ diff --git a/_server/editor_blocklyconfig.js b/_server/editor_blocklyconfig.js index 1673ac6e..51ecdd02 100644 --- a/_server/editor_blocklyconfig.js +++ b/_server/editor_blocklyconfig.js @@ -95,7 +95,9 @@ editor_blocklyconfig=(function(){ '显示文字':[ MotaActionBlocks['text_0_s'].xmlText(), MotaActionBlocks['text_1_s'].xmlText(), - MotaActionFunctions.actionParser.parseList("\t[小妖精,fairy]\f[fairy.png,0,0]欢迎使用事件编辑器(双击方块进入多行编辑)"), + MotaActionFunctions.actionParser.parseList("\t[小妖精,fairy]\f[fairy.png,0,0]欢迎使用事件编辑器(双击方块可直接预览)"), + MotaActionBlocks['moveTextBox_s'].xmlText(), + MotaActionBlocks['clearTextBox_s'].xmlText(), MotaActionBlocks['comment_s'].xmlText(), MotaActionBlocks['autoText_s'].xmlText(), MotaActionBlocks['scrollText_s'].xmlText(), diff --git a/libs/actions.js b/libs/actions.js index 58b4c28f..9ec02faf 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1019,26 +1019,33 @@ actions.prototype._onMoveConfirmBox = function (x, y) { } } +actions.prototype._clickAction_text = function () { + // 正在淡入淡出的话不执行 + if (core.status.event.animateUI) return; + + var data = core.clone(core.status.event.data.current); + if (typeof data == 'string') data = { "type": "text", "text": data }; + + // 打字机效果显示全部文字 + if (core.status.event.interval != null) { + data.showAll = true; + core.insertAction(data); + core.doAction(); + return; + } + + if (!data.code) { + core.ui._animateUI('hide', null, core.doAction); + } else { + // 不清除对话框 + core.doAction(); + } +} + ////// 自定义事件时的点击操作 ////// actions.prototype._clickAction = function (x, y, px, py) { if (core.status.event.data.type == 'text') { - // 正在淡入淡出的话不执行 - if (core.status.event.animateUI) return; - - var data = core.clone(core.status.event.data.current); - if (typeof data == 'string') data = { "type": "text", "text": data }; - - // 打字机效果显示全部文字 - if (core.status.event.interval != null) { - data.showAll = true; - core.insertAction(data); - core.doAction(); - return; - } - - // 文字 - core.ui._animateUI('hide', core.doAction); - return; + return this._clickAction_text(); } if (core.status.event.data.type == 'wait') { @@ -1125,20 +1132,7 @@ actions.prototype._keyDownAction = function (keycode) { ////// 自定义事件时,放开某个键的操作 ////// actions.prototype._keyUpAction = function (keycode) { if (core.status.event.data.type == 'text' && (keycode == 13 || keycode == 32 || keycode == 67)) { - // 正在淡入淡出的话不执行 - if (core.status.event.animateUI) return; - - var data = core.clone(core.status.event.data.current); - if (typeof data == 'string') data = { "type": "text", "text": data }; - - // 打字机效果显示全部文字 - if (core.status.event.interval != null) { - data.showAll = true; - core.insertAction(data); - return; - } - core.ui._animateUI('hide', core.doAction); - return; + return this._clickAction_text(); } if (core.status.event.data.type == 'wait') { var timeout = Math.max(0, core.status.event.timeout - new Date().getTime()) || 0; diff --git a/libs/events.js b/libs/events.js index b8790319..aa0a995d 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1354,8 +1354,28 @@ events.prototype.__action_doAsyncFunc = function (isAsync, func) { events.prototype._action_text = function (data, x, y, prefix) { if (this.__action_checkReplaying()) return; data.text = core.replaceText(data.text, prefix); + var ctx = data.code ? '__text__' + data.code : null;; + data.ctx = ctx; + if (core.getContextByName(ctx) && !data.showAll) { + core.ui._animateUI('hide', ctx, function () { + core.ui.drawTextBox(data.text, data); + core.ui._animateUI('show', ctx); + }); + return; + } core.ui.drawTextBox(data.text, data); - if (!data.showAll) core.ui._animateUI('show'); + if (!data.showAll) core.ui._animateUI('show', ctx); +} + +events.prototype._action_moveTextBox = function (data, x, y, prefix) { + if (this.__action_checkReplaying()) return; + this.__action_doAsyncFunc(data.async, core.moveTextBox, + data.code, this.__action_getLoc(data.loc, x, y, prefix), data.relative, data.moveMode, data.time); +} + +events.prototype._action_clearTextBox = function (data, x, y, prefix) { + if (this.__action_checkReplaying()) return; + core.clearTextBox(data.code, core.doAction); } events.prototype._action_autoText = function (data, x, y, prefix) { @@ -3057,6 +3077,67 @@ events.prototype.setTextAttribute = function (data) { if (main.mode == 'play') core.setFlag('textAttribute', core.status.textAttribute); } +events.prototype.moveTextBox = function (code, loc, relative, moveMode, time, callback) { + var ctx = core.getContextByName('__text__' + code); + if (!ctx) { + if (callback) callback(); + return; + } + var sx = parseInt(ctx.canvas.getAttribute('_text_left')) || 0; + var sy = parseInt(ctx.canvas.getAttribute('_text_top')) || 0; + var dx = relative ? loc[0] : (loc[0] - sx); + var dy = relative ? loc[1] : (loc[1] - sy); + var ox = parseInt(ctx.canvas.getAttribute('_left')) || 0; + var oy = parseInt(ctx.canvas.getAttribute('_top')) || 0; + + if (!time) { + core.relocateCanvas(ctx, ox + dx, oy + dy); + ctx.canvas.setAttribute('_text_left', loc[0]); + ctx.canvas.setAttribute('_text_top', loc[1]); + if (callback) callback(); + return; + } + + var moveInfo = { + sx: sx, sy: sy, dx: dx, dy: dy, ox: ox, oy: oy, + moveMode: moveMode, time: time / Math.max(core.status.replay.speed, 1) + }; + this._moveTextBox_moving(ctx, moveInfo, callback); +} + +events.prototype._moveTextBox_moving = function (ctx, moveInfo, callback) { + var step = 0, steps = moveInfo.time / 10; + if (steps <= 0) steps = 1; + var moveFunc = core.applyEasing(moveInfo.moveMode); + var animate = setInterval(function () { + step++; + var dx = moveInfo.dx * moveFunc(step / steps); + var dy = moveInfo.dy * moveFunc(step / steps); + core.relocateCanvas(ctx, parseInt(moveInfo.ox + dx), parseInt(moveInfo.oy + dy)); + ctx.canvas.setAttribute('_text_left', moveInfo.sx + dx); + ctx.canvas.setAttribute('_text_top', moveInfo.sy + dy); + if (step == steps) { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + if (callback) callback(); + } + }, 10); + core.animateFrame.asyncId[animate] = true; +} + +////// 清除对话框 ////// +events.prototype.clearTextBox = function (code, callback) { + var ctx = '__text__' + code; + if (!core.getContextByName(ctx)) { + if (callback) callback(); + } + core.ui._animateUI('hide', ctx, function () { + core.deleteCanvas(ctx); + if (callback) callback(); + }); +} + +////// 关门 ////// events.prototype.closeDoor = function (x, y, id, callback) { id = id || ""; if ((core.material.icons.animates[id] == null && core.material.icons.npc48[id] == null) diff --git a/libs/ui.js b/libs/ui.js index 1e340294..9414de9b 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1382,7 +1382,8 @@ ui.prototype._getRealContent = function (content) { return content.replace(/(\r|\\(r|c|d|e|g|z))(\[.*?])?/g, "").replace(/(\\i)(\[.*?])?/g, "占1"); } -ui.prototype._animateUI = function (type, callback) { +ui.prototype._animateUI = function (type, ctx, callback) { + ctx = ctx || 'ui'; var time = core.status.textAttribute.animateTime || 0; if (!core.status.event || !time || core.isReplaying() || (type != 'show' && type != 'hide')) { if (callback) callback(); @@ -1395,12 +1396,12 @@ ui.prototype._animateUI = function (type, callback) { } else if (type == 'hide') { opacity = 1; } - core.setOpacity('ui', opacity); + core.setOpacity(ctx, opacity); core.dom.next.style.opacity = opacity; core.status.event.animateUI = setInterval(function () { if (type == 'show') opacity += 0.05; else opacity -= 0.05; - core.setOpacity('ui', opacity); + core.setOpacity(ctx, opacity); core.dom.next.style.opacity = opacity; if (opacity >= 1 || opacity <= 0) { clearInterval(core.status.event.animateUI); @@ -1416,7 +1417,11 @@ ui.prototype.drawTextBox = function(content, config) { this.clearUI(); - content = core.replaceText(content); + var ctx = config.ctx || null; + if (ctx && main.mode == 'play') { + core.createCanvas(ctx, 0, 0, core.__PIXELS__, core.__PIXELS__, 141); + ctx = core.getContextByName(ctx); + } // Step 1: 获得标题信息和位置信息 var textAttribute = core.status.textAttribute; @@ -1430,7 +1435,7 @@ ui.prototype.drawTextBox = function(content, config) { delete posInfo.py; posInfo.pos = config.pos; } - posInfo.ctx = config.ctx; + posInfo.ctx = ctx; // Step 2: 计算对话框的矩形位置 var hPos = this._drawTextBox_getHorizontalPosition(content, titleInfo, posInfo); @@ -1438,6 +1443,11 @@ ui.prototype.drawTextBox = function(content, config) { posInfo.xoffset = hPos.xoffset; posInfo.yoffset = vPos.yoffset - 4; + if (ctx && main.mode == 'play') { + ctx.canvas.setAttribute('_text_left', hPos.left); + ctx.canvas.setAttribute('_text_top', vPos.top); + } + // Step 3: 绘制背景图 var isWindowSkin = this.drawBackground(hPos.left, vPos.top, hPos.right, vPos.bottom, posInfo); var alpha = isWindowSkin ? this._drawWindowSkin_getOpacity() : textAttribute.background[3];