From 9330a18664ad3997e0cf14cc65f4b7a6a78cf6a3 Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 4 Feb 2018 20:06:31 +0800 Subject: [PATCH] Conversation --- docs/event.md | 38 ++++++++++++ libs/core.js | 39 ++++++------ libs/events.js | 12 ++++ libs/floors/sample0.js | 6 +- libs/ui.js | 132 +++++++++++++++++++++++++++++++++++++---- 5 files changed, 192 insertions(+), 35 deletions(-) diff --git a/docs/event.md b/docs/event.md index f1ef08d2..b4a83951 100644 --- a/docs/event.md +++ b/docs/event.md @@ -214,6 +214,25 @@ ] ``` +除此以外,我们还能实现“对话框效果”,只要有`\b[...]`就可以。 + +- `\b[up]` 直接显示在当前点上方。同样把这里的up换成down则为下方。 + - 如果不存在当前点(如在firstArrive中调用),则显示在屏幕最上方(最下方) +- `\b[up,hero]` 显示在勇士上方。同样把这里的up换成down则为下方。 +- `\b[up,x,y]` 显示在(x,y)点的上方(下方);x和y都为整数且在0到12之间。 + +``` js +"x,y": [ // 实际执行的事件列表 + "\b[up]这段文字显示在当前点上方", + "\b[down]这段文字显示在当前点上方", + "\t[hero]\b[up,hero]这是一段勇士说的话,会显示在勇士上方", + "\t[小妖精,fairy]\b[down,2,2]这是一段小妖精说的话,会显示在(2,2)点下方", +] +``` + +!> `\t[...]`必须在`\b[...]`前面!不然两者都无法正常显示。 + + 另外值得一提的是,我们是可以在文字中计算一个表达式的值的。只需要将表达式用 `${ }`整个括起来就可以。 ``` js @@ -242,6 +261,25 @@ ![调试](./img/eventdebug.png) +### setText:设置剧情文本的属性 + +使用`{"type": "setText"}`可以设置剧情文本的各项属性。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "setText", "position": "up", "title": [255,0,0], "text": [255,255,0], "background": [0,0,255,0.3]}, + "这段话将显示在上方,标题为红色,正文为黄色,背景为透明度0.3的蓝色" +] +``` + +position为可选项,表示设置文字显示位置。只能为up(上),center(中)和down(下)三者。 + +title为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示标题(名字)颜色。 + +text为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示正文颜色。 + +background为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示背景色。 + ### tip:显示一段提示文字 `{"type": "tip"}`可以在左上角显示一段提示文字。 diff --git a/libs/core.js b/libs/core.js index d786f573..cde05083 100644 --- a/libs/core.js +++ b/libs/core.js @@ -28,13 +28,6 @@ function core() { 'turnHeroTimeout': null, } this.interval = { - //'twoAnimate': null, - //'fourAnimate': null, - //'boxAnimate': null, - //'twoTime': null, - //'fourTime': null, - //'boxTime': null, - //'globalAnimate': false, 'heroMoveTriggerInterval': null, 'heroMoveInterval': null, "tipAnimate": null, @@ -131,6 +124,12 @@ function core() { 'selection': null, 'ui': null, }, + 'textAttribute': { + 'position': "center", + "title": [255,215,0,1], + "background": [0,0,0,0.85], + "text": [255,255,255,1], + }, 'curtainColor': null, 'usingCenterFly':false, 'openingDoor': null, @@ -2270,9 +2269,7 @@ core.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback) var color = core.floors[floorId].color; // 直接变色 - var nowR = parseInt(color[0]), nowG = parseInt(color[1]), nowB = parseInt(color[2]); - var toRGB = "#"+((1<<24)+(nowR<<16)+(nowG<<8)+nowB).toString(16).slice(1); - core.dom.curtain.style.background = toRGB; + core.dom.curtain.style.background = this.arrayToRGB(color); if (core.isset(color[3])) core.dom.curtain.style.opacity = color[3]; else core.dom.curtain.style.opacity=1; @@ -2389,6 +2386,7 @@ core.prototype.drawLine = function (map, x1, y1, x2, y2, style, lineWidth) { core.canvas[map].beginPath(); core.canvas[map].moveTo(x1, y1); core.canvas[map].lineTo(x2, y2); + core.canvas[map].closePath(); core.canvas[map].stroke(); } @@ -3249,9 +3247,7 @@ core.prototype.setFg = function(color, time, callback) { if (time==0) { // 直接变色 - var nowR = parseInt(color[0]), nowG = parseInt(color[1]), nowB = parseInt(color[2]); - var toRGB = "#"+((1<<24)+(nowR<<16)+(nowG<<8)+nowB).toString(16).slice(1); - core.dom.curtain.style.background = toRGB; + core.dom.curtain.style.background = this.arrayToRGB(color); core.dom.curtain.style.opacity = color[3]; core.status.curtainColor = color; if (core.isset(callback)) callback(); @@ -3267,12 +3263,7 @@ core.prototype.setFg = function(color, time, callback) { var nowR = parseInt(fromColor[0]+(color[0]-fromColor[0])*step/25); var nowG = parseInt(fromColor[1]+(color[1]-fromColor[1])*step/25); var nowB = parseInt(fromColor[2]+(color[2]-fromColor[2])*step/25); - if (nowR<0) nowR=0; if (nowR>255) nowR=255; - if (nowG<0) nowG=0; if (nowG>255) nowG=255; - if (nowB<0) nowB=0; if (nowB>255) nowB=255; - - var toRGB = "#"+((1<<24)+(nowR<<16)+(nowG<<8)+nowB).toString(16).slice(1); - core.dom.curtain.style.background = toRGB; + core.dom.curtain.style.background = this.arrayToRGB([nowR,nowG,nowB]); core.dom.curtain.style.opacity = nowAlpha; if (step>=25) { @@ -3714,6 +3705,14 @@ core.prototype.setTwoDigits = function (x) { return parseInt(x)<10?"0"+x:x; } +////// 数组转RGB ////// +core.prototype.arrayToRGB = function (color) { + var nowR = parseInt(color[0])||0, nowG = parseInt(color[1])||0, nowB = parseInt(color[2])||0; + if (nowR<0) nowR=0; if (nowB<0) nowB=0;if (nowG<0) nowG=0; + if (nowR>255) nowR=255; if (nowB>255) nowB=255; if (nowG>255) nowG=255; + return "#"+((1<<24)+(nowR<<16)+(nowG<<8)+nowB).toString(16).slice(1); +} + ////// 作弊 ////// core.prototype.debug = function() { core.setStatus('hp', 999999); @@ -4551,7 +4550,7 @@ core.prototype.unLockControl = function () { ////// 判断某对象是否不为undefined也不会null ////// core.prototype.isset = function (val) { - if (val == undefined || val == null) { + if (val == undefined || val == null || val==NaN) { return false; } return true diff --git a/libs/events.js b/libs/events.js index b38b9a65..4d1e98a1 100644 --- a/libs/events.js +++ b/libs/events.js @@ -292,6 +292,18 @@ events.prototype.doAction = function() { else core.ui.drawTextBox(data.data); break; + case "setText": // 设置文本状态 + if (data.position=='up'||data.position=='down'||data.position=='center') { + core.status.textAttribute.position=data.position; + } + ["background", "title", "text"].forEach(function (t) { + if (core.isset(data[t]) && (data[t] instanceof Array) && data[t].length>=3) { + if (data[t].length==3) data[t].push(1); + core.status.textAttribute[t]=data[t]; + } + }) + core.events.doAction(); + break; case "tip": core.drawTip(core.replaceText(data.text)); core.events.doAction(); diff --git a/libs/floors/sample0.js b/libs/floors/sample0.js index 02d712bc..e6bc1f58 100644 --- a/libs/floors/sample0.js +++ b/libs/floors/sample0.js @@ -28,7 +28,7 @@ main.floors.sample0 = { ], "firstArrive": [ // 第一次到该楼层触发的事件 "\t[样板提示]首次到达某层可以触发 firstArrive 事件,该事件可类似于RMXP中的“自动执行脚本”。\n\n本事件支持一切的事件类型,常常用来触发对话,例如:", - "\t[hero]我是谁?我从哪来?我又要到哪去?", + "\t[hero]\b[up,hero]我是谁?我从哪来?我又要到哪去?", "\t[仙子,fairy]你问我...?我也不知道啊...", "本层主要对道具、门、怪物等进行介绍,有关事件的各种信息在下一层会有更为详细的说明。", ], @@ -36,9 +36,9 @@ main.floors.sample0 = { "10,9": [ // 守着道具的老人 "\t[老人,man]这些是本样板支持的所有的道具。\n\n道具分为三类:items, constants, tools。\nitems 为即捡即用类道具,例如宝石、血瓶、剑盾等。\nconstants 为永久道具,例如怪物手册、楼层传送器、幸运金币等。\ntools 为消耗类道具,例如破墙镐、炸弹、中心对称飞行器等。\n\n后两类道具在工具栏中可以看到并使用。", - "\t[老人,man]有关道具效果,定义在items.js中。\n目前大多数道具已有默认行为,如有自定义的需求则需在items.js中修改代码。", + "\t[老人,man]\b[up]有关道具效果,定义在items.js中。\n目前大多数道具已有默认行为,如有自定义的需求则需在items.js中修改代码。", "\t[老人,man]constants 和 tools 各最多只允许12种,多了会导致图标溢出。", - "\t[老人,man]拾取道具结束后可触发 afterGetItem 事件。\n\n有关事件的各种信息在下一层会有更为详细的说明。", + "\t[老人,man]\b[up]拾取道具结束后可触发 afterGetItem 事件。\n\n有关事件的各种信息在下一层会有更为详细的说明。", {"type": "hide", "time": 500} // 消失 ], "10,11": [ // 守着门的老人 diff --git a/libs/ui.js b/libs/ui.js index 05fd7fec..30d7ca22 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -63,6 +63,48 @@ ui.prototype.drawTextBox = function(content) { } } + // 获得位置信息 + + var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; + + var position = textAttribute.position, px=null, py=null, ydelta=0; + if (content.indexOf("\b[")==0) { + var index = content.indexOf("]"); + if (index>=0) { + var str = content.substring(2, index); + content = content.substring(index + 1); + + var ss=str.split(","); + + if (ss[0]=='up' || ss[0]=='center' || ss[0]=='down') { + position=ss[0]; + if (core.status.event.id=='action') { + px = core.status.event.data.x; + py = core.status.event.data.y; + } + + if (ss.length>=2) { + if (ss[1]=='hero') { + px=core.getHeroLoc('x'); + py=core.getHeroLoc('y'); + ydelta = core.material.icons.hero.height-32; + } + else if (ss.length>=3) { + px=parseInt(ss[1]); + py=parseInt(ss[2]); + } + } + } + /* + if (ss.length==3) { + px=parseInt(ss[1]); + py=parseInt(ss[2]); + } + */ + + } + } + content = core.replaceText(content); var background = core.canvas.ui.createPattern(core.material.ground, "repeat"); @@ -76,14 +118,74 @@ ui.prototype.drawTextBox = function(content) { var validWidth = right-(content_left-left)-13; var contents = core.splitLines("ui", content, validWidth, '16px Verdana'); - var height = 416 - 10 - Math.min(416-24*(contents.length+1)-65, 250); - var top = (416-height)/2, bottom = height; + var height = 20 + 21*(contents.length+1) + (id=='hero'?core.material.icons.hero.height-10:core.isset(name)?32-10:0); + + + var xoffset = 6, yoffset = 22; + + var top; + if (position=='center') { + top = (416 - height) / 2; + } + else if (position=='up') { + if (px==null || py==null) { + top = 5; + } + else { + top = 32 * py - height - ydelta - yoffset; + } + } + else if (position=='down') { + if (px==null || py==null) { + top = 416 - height - 5; + } + else { + top = 32 * py + 32 + yoffset; + } + } // var left = 97, top = 64, right = 416 - 2 * left, bottom = 416 - 2 * top; - core.setAlpha('ui', 0.85); - core.fillRect('ui', left, top, right, bottom, '#000000'); - core.setAlpha('ui', 1); - core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2); + //core.setAlpha('ui', 0.85); + core.setAlpha('ui', textAttribute.background[3]); + core.setFillStyle('ui', core.arrayToRGB(textAttribute.background)); + core.setStrokeStyle('ui', '#FFFFFF'); + + + core.fillRect('ui', left, top, right, height); + core.strokeRect('ui', left - 1, top - 1, right + 1, height + 1, '#FFFFFF', 2); + + var xoffset = 6; + + // draw triangle + if (position=='up' && core.isset(px) && core.isset(py)) { + core.canvas.ui.clearRect(32*px+xoffset, top+height-1, 32-2*xoffset, 2); + core.canvas.ui.beginPath(); + core.canvas.ui.moveTo(32*px+xoffset-1, top+height-1); + core.canvas.ui.lineTo(32*px+16, top+height+yoffset-2); + core.canvas.ui.lineTo(32*px+32-xoffset+1, top+height-1); + core.canvas.ui.moveTo(32*px+xoffset-1, top+height-1); + core.canvas.ui.closePath(); + core.canvas.ui.fill(); + // core.canvas.ui.stroke(); + // core.drawLine('ui', 32*px+4+1, top+height+1, 32*px + 28-1, top+height+1, core.arrayToRGB(textAttribute.background), 3); + core.drawLine('ui', 32*px+xoffset, top+height, 32*px+16, top+height+yoffset-2); + core.drawLine('ui', 32*px+32-xoffset, top+height, 32*px+16, top+height+yoffset-2); + } + if (position=='down' && core.isset(px) && core.isset(py)) { + core.canvas.ui.clearRect(32*px+xoffset, top-2, 32-2*xoffset, 3); + core.canvas.ui.beginPath(); + core.canvas.ui.moveTo(32*px+xoffset-1, top+1); + core.canvas.ui.lineTo(32*px+16-1, top-yoffset+2); + core.canvas.ui.lineTo(32*px+32-xoffset-1, top+1); + core.canvas.ui.moveTo(32*px+xoffset-1, top+1); + core.canvas.ui.closePath(); + core.canvas.ui.fill(); + // core.canvas.ui.stroke(); + // core.drawLine('ui', 32*px+4+1, top+height+1, 32*px + 28-1, top+height+1, core.arrayToRGB(textAttribute.background), 3); + core.drawLine('ui', 32*px+xoffset, top, 32*px+16, top-yoffset+2); + core.drawLine('ui', 32*px+32-xoffset, top, 32*px+16, top-yoffset+2); + } + core.status.boxAnimateObjs = []; // 名称 @@ -93,11 +195,14 @@ ui.prototype.drawTextBox = function(content) { if (core.isset(id)) { content_top = top+57; + core.setAlpha('ui', textAttribute.title[3]); + core.setFillStyle('ui', core.arrayToRGB(textAttribute.title)); + core.setStrokeStyle('ui', core.arrayToRGB(textAttribute.title)); if (id == 'hero') { var heroHeight=core.material.icons.hero.height; - core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, heroHeight+2, '#FFD700', 2); - core.fillText('ui', core.status.hero.name, content_left, top + 30, '#FFD700', 'bold 22px Verdana'); + core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, heroHeight+2, null, 2); + core.fillText('ui', core.status.hero.name, content_left, top + 30, null, 'bold 22px Verdana'); core.clearMap('ui', left + 15, top + 40, 32, heroHeight); core.fillRect('ui', left + 15, top + 40, 32, heroHeight, background); var heroIcon = core.material.icons.hero['down']; @@ -106,7 +211,7 @@ ui.prototype.drawTextBox = function(content) { else { core.fillText('ui', name, content_left, top + 30, '#FFD700', 'bold 22px Verdana'); if (core.isset(icon)) { - core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, 34, '#FFD700', 2); + core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, 34, null, 2); core.status.boxAnimateObjs = []; core.status.boxAnimateObjs.push({ 'bgx': left + 15, 'bgy': top + 40, 'bgsize': 32, @@ -117,12 +222,15 @@ ui.prototype.drawTextBox = function(content) { } } + core.setAlpha('ui', textAttribute.text[3]); + core.setFillStyle('ui', core.arrayToRGB(textAttribute.text)); + for (var i=0;i', 270, top+height-13, '#CCCCCC', '13px Verdana'); + // core.fillText('ui', '<点击任意位置继续>', 270, top+height-13, '#CCCCCC', '13px Verdana'); } ////// 绘制一个选项界面 //////