From e81ef21b878bfbc48bc8144130c4e6b4c0773d70 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 2 Sep 2021 20:32:51 +0800 Subject: [PATCH] =?UTF-8?q?stopAsync=20=E7=AB=8B=E5=88=BB=E5=81=9C?= =?UTF-8?q?=E6=AD=A2=E6=89=80=E6=9C=89=E5=BC=82=E6=AD=A5=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _docs/api.md | 3 + _server/CodeMirror/defs.js | 4 ++ _server/MotaAction.g4 | 14 +++++ _server/MotaActionParser.js | 4 ++ _server/editor_blockly.js | 2 +- _server/editor_blocklyconfig.js | 1 + libs/control.js | 17 +++-- libs/events.js | 106 +++++++++++++++++++++----------- libs/maps.js | 75 +++++++++++++--------- libs/ui.js | 2 +- project/floors/sample0.js | 55 +++++++++++++++++ runtime.d.ts | 3 + 12 files changed, 214 insertions(+), 72 deletions(-) diff --git a/_docs/api.md b/_docs/api.md index abb6bf36..2a18a9e7 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -1209,6 +1209,9 @@ seed: 随机种子,相同的种子保证了录像的可重复性 route: 经由base64压缩后的录像,用于从头开始的录像回放 callback: 回调函数,可选 +stopAsync: fn() +立刻停止所有正在进行的异步事件 + trigger: fn(x?: number, y?: number, callback?: fn()) 触发(x,y)点的系统事件;会执行该点图块的script属性,同时支持战斗(会触发战后)、道具(会触发道具后)、楼层切换等等 callback: 执行完毕的回调函数 diff --git a/_server/CodeMirror/defs.js b/_server/CodeMirror/defs.js index 3d6e6d33..1830642c 100644 --- a/_server/CodeMirror/defs.js +++ b/_server/CodeMirror/defs.js @@ -3835,6 +3835,10 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!doc": "当前是否有未处理完毕的异步事件(不包含动画和音效)", "!type": "fn() -> bool" }, + "stopAsync": { + "!doc": "立刻停止所有正在进行的异步事件", + "!type": "fn()" + }, "openEquipbox": { "!doc": "点击装备栏时的打开操作", "!type": "fn(fromUserAction?: bool)" diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 5ab58682..dc0784d0 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -851,6 +851,7 @@ action | sleep_s | wait_s | waitAsync_s + | stopAsync_s | battle_s | battle_1_s | openDoor_s @@ -3076,6 +3077,19 @@ return code; */; +stopAsync_s + : '立刻结束所有异步事件' BGNL Newline + + +/* stopAsync_s +tooltip : stopAsync: 立刻结束所有异步事件 +helpUrl : /_docs/#/instruction +colour : this.soundColor +var code = '{"type": "stopAsync"},\n'; +return code; +*/; + + callBook_s : '呼出怪物手册' diff --git a/_server/MotaActionParser.js b/_server/MotaActionParser.js index c89e9fab..0565e5b9 100644 --- a/_server/MotaActionParser.js +++ b/_server/MotaActionParser.js @@ -972,6 +972,10 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['waitAsync_s'].xmlText([ data.excludeAnimates||false, data.includeSounds||false, this.next]); break; + case "stopAsync": // 立刻停止所有异步事件 + this.next = MotaActionBlocks['stopAsync_s'].xmlText([ + this.next]); + break; case "callBook": // 呼出怪物手册 this.next = MotaActionBlocks['callBook_s'].xmlText([ this.next]); diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index f8c0a850..e83c764a 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -248,7 +248,7 @@ editor_blockly = function () { } if (one.type == 'previewUI' && this.checkAsync(one.action)) return true; if (one.async && one.type != 'animate' && one.type != 'function' && one.type != 'text') hasAsync = true; - if (one.type == 'waitAsync') hasAsync = false; + if (one.type == 'waitAsync' || one.type == 'stopAsync') hasAsync = false; } return hasAsync; } diff --git a/_server/editor_blocklyconfig.js b/_server/editor_blocklyconfig.js index 48e1fea8..0dc19af8 100644 --- a/_server/editor_blocklyconfig.js +++ b/_server/editor_blocklyconfig.js @@ -196,6 +196,7 @@ editor_blocklyconfig=(function(){ {"case": "timeout", "action": [{"type": "comment", "text": "当超时未操作时执行此事件"}]}, ]}), MotaActionBlocks['waitAsync_s'].xmlText(), + MotaActionBlocks['stopAsync_s'].xmlText(), MotaActionBlocks['vibrate_s'].xmlText(), MotaActionBlocks['animate_s'].xmlText(), MotaActionBlocks['animate_1_s'].xmlText(), diff --git a/libs/control.js b/libs/control.js index 8f2d8a17..a3386870 100644 --- a/libs/control.js +++ b/libs/control.js @@ -911,7 +911,7 @@ control.prototype.setHeroOpacity = function (opacity, moveMode, time, callback) } }, 10); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = callback; } // ------ 画布、位置、阻激夹域,显伤 ------ // @@ -1031,7 +1031,7 @@ control.prototype.moveViewport = function (x, y, moveMode, time, callback) { } }, per_time); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = callback; } ////// 获得勇士面对位置的x坐标 ////// @@ -2735,10 +2735,16 @@ control.prototype._setCurtain_animate = function (nowColor, color, time, moveMod time /= Math.max(core.status.replay.speed, 1) var per_time = 10, step = 0, steps = parseInt(time / per_time); if (steps <= 0) steps = 1; + var curr = nowColor; var moveFunc = core.applyEasing(moveMode); + + var cb = function () { + core.status.curtainColor = curr; + if (callback) callback(); + } var animate = setInterval(function() { step++; - var curr = [ + curr = [ nowColor[0] + (color[0] - nowColor[0]) * moveFunc(step / steps), nowColor[1] + (color[1] - nowColor[1]) * moveFunc(step / steps), nowColor[2] + (color[2] - nowColor[2]) * moveFunc(step / steps), @@ -2749,12 +2755,11 @@ control.prototype._setCurtain_animate = function (nowColor, color, time, moveMod if (step == steps) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - core.status.curtainColor = color; - if (core.isset(callback)) callback(); + cb(); } }, per_time); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = cb; } ////// 画面闪烁 ////// diff --git a/libs/events.js b/libs/events.js index f39f58eb..7687f9e1 100644 --- a/libs/events.js +++ b/libs/events.js @@ -581,21 +581,26 @@ events.prototype._openDoor_animate = function (block, x, y, callback) { blockInfo.posX = 0; core.maps._drawBlockInfo(blockInfo, x, y); + + var cb = function () { + core.maps._removeBlockFromMap(core.status.floorId, block); + if (!locked) core.unlockControl(); + core.status.replay.animate = false; + core.events.afterOpenDoor(block.event.id, x, y); + if (callback) callback(); + } + var animate = window.setInterval(function() { blockInfo.posX++; if (blockInfo.posX == 4) { - core.maps._removeBlockFromMap(core.status.floorId, block); clearInterval(animate); delete core.animateFrame.asyncId[animate]; - if (!locked) core.unlockControl(); - core.status.replay.animate = false; - core.events.afterOpenDoor(block.event.id, x, y); - if (callback) callback(); + cb(); return; } core.maps._drawBlockInfo(blockInfo, x, y); }, core.status.replay.speed == 24 ? 1 : speed / Math.max(core.status.replay.speed, 1)); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = cb; } ////// 开一个门后触发的事件 ////// @@ -2519,6 +2524,11 @@ events.prototype._action_waitAsync = function (data, x, y, prefix) { }, 50 / core.status.replay.speed); } +events.prototype._action_stopAsync = function (data, x, y, prefix) { + core.stopAsync(); + core.doAction(); +} + events.prototype._action_callBook = function (data, x, y, prefix) { if (core.isReplaying() || !core.hasItem('book')) { core.doAction(); @@ -2896,6 +2906,19 @@ events.prototype.hasAsync = function () { return Object.keys(core.animateFrame.asyncId).length > 0; } +////// 立刻停止所有异步事件 ////// +events.prototype.stopAsync = function () { + var callbacks = []; + for (var id in core.animateFrame.asyncId) { + clearInterval(id); + callbacks.push(core.animateFrame.asyncId[id]); + } + core.animateFrame.asyncId = {}; + callbacks.forEach(function (cb) { + if (cb && cb instanceof Function) cb(); + }); +} + events.prototype.hasAsyncAnimate = function () { return (core.status.animateObjs || []).length > 0; } @@ -3161,7 +3184,7 @@ events.prototype._moveTextBox_moving = function (ctx, moveInfo, callback) { if (callback) callback(); } }, 10); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = callback; } ////// 清除对话框 ////// @@ -3209,19 +3232,23 @@ events.prototype.closeDoor = function (x, y, id, callback) { blockInfo.posX = 3; core.maps._drawBlockInfo(blockInfo, x, y); + var cb = function () { + core.setBlock(id, x, y); + core.showBlock(x, y); + if (callback) callback(); + } + var animate = window.setInterval(function () { blockInfo.posX--; if (blockInfo.posX < 0) { clearInterval(animate); delete core.animateFrame.asyncId[animate]; - core.setBlock(id, x, y); - core.showBlock(x, y); - if (callback) callback(); + cb(); return; } core.maps._drawBlockInfo(blockInfo, x, y); }, core.status.replay.speed == 24 ? 1 : speed / Math.max(core.status.replay.speed, 1)); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = cb; } ////// 显示图片 ////// @@ -3325,13 +3352,12 @@ events.prototype._moveImage_moving = function (name, moveInfo, callback) { core.setOpacity(name, currOpacity); core.relocateCanvas(name, currX, currY); if (step == steps) { - core.setOpacity(name, toOpacity); delete core.animateFrame.asyncId[animate]; clearInterval(animate); if (callback) callback(); } }, per_time); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = callback; } ////// 旋转图片 ////// @@ -3374,8 +3400,7 @@ events.prototype._rotateImage_rotating = function (name, rotateInfo, callback) { if (callback) callback(); } }, per_time); - core.animateFrame.asyncId[animate] = true; - + core.animateFrame.asyncId[animate] = callback; } ////// 放缩一张图片 ////// @@ -3434,7 +3459,7 @@ events.prototype._scaleImage_scale = function (ctx, scaleInfo, callback) { if (callback) callback(); } }, per_time); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = callback; } ////// 绘制或取消一张gif图片 ////// @@ -3481,7 +3506,7 @@ events.prototype.setVolume = function (value, time, callback) { if (callback) callback(); } }, per_time); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = callback; } ////// 画面震动 ////// @@ -3497,6 +3522,10 @@ events.prototype.vibrate = function (direction, time, speed, power, callback) { if (direction == 'random') { direction = ['horizontal', 'vertical', 'diagonal1', 'diagonal2'][Math.floor(Math.random() * 4)]; } + var cb = function () { + core.addGameCanvasTranslate(0, 0); + if (callback) callback(); + } var animate = setInterval(function () { core.events._vibrate_update(shakeInfo); switch (direction) { @@ -3508,11 +3537,11 @@ events.prototype.vibrate = function (direction, time, speed, power, callback) { if (shakeInfo.duration === 0 && shakeInfo.shake == 0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - if (callback) callback(); + cb(); } }, 10); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = cb; } events.prototype._vibrate_update = function (shakeInfo) { @@ -3546,13 +3575,17 @@ events.prototype.eventMoveHero = function(steps, time, callback) { }); core.status.heroMoving = -1; var _run = function () { + var cb = function () { + core.status.heroMoving = 0; + core.drawHero(); + if (callback) callback(); + } + var animate=window.setInterval(function() { if (moveSteps.length==0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - core.status.heroMoving = 0; - core.drawHero(); - if (callback) callback(); + cb(); } else { if (step == 0 && moveSteps[0][0] == 'speed' && moveSteps[0][1] >= 16) { @@ -3567,7 +3600,7 @@ events.prototype.eventMoveHero = function(steps, time, callback) { } }, core.status.replay.speed == 24 ? 1 : time / 8 / core.status.replay.speed); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = cb; } _run(); } @@ -3622,15 +3655,26 @@ events.prototype.jumpHero = function (ex, ey, time, callback) { } events.prototype._jumpHero_doJump = function (jumpInfo, callback) { + var cb = function () { + core.setHeroLoc('x', jumpInfo.ex); + core.setHeroLoc('y', jumpInfo.ey); + core.status.heroMoving = 0; + core.drawHero(); + if (callback) callback(); + } + core.status.heroMoving = -1; var animate = window.setInterval(function () { if (jumpInfo.jump_count > 0) core.events._jumpHero_jumping(jumpInfo) - else - core.events._jumpHero_finished(animate, jumpInfo.ex, jumpInfo.ey, callback); + else { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + cb(); + } }, jumpInfo.per_time); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = cb; } events.prototype._jumpHero_jumping = function (jumpInfo) { @@ -3642,16 +3686,6 @@ events.prototype._jumpHero_jumping = function (jumpInfo) { core.drawHero('stop', { x: nowx - 32 * x, y: nowy - 32 * y }); } -events.prototype._jumpHero_finished = function (animate, ex, ey, callback) { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - core.setHeroLoc('x', ex); - core.setHeroLoc('y', ey); - core.status.heroMoving = 0; - core.drawHero(); - if (callback) callback(); -} - ////// 设置角色行走图 ////// events.prototype.setHeroIcon = function (name, noDraw) { name = core.getMappedName(name); diff --git a/libs/maps.js b/libs/maps.js index 1f5e2d8b..daf4537f 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -2592,6 +2592,17 @@ maps.prototype.moveBlock = function (x, y, steps, time, keep, callback) { maps.prototype._moveBlock_doMove = function (blockInfo, canvases, moveInfo, callback) { var animateTotal = blockInfo.animate, animateTime = 0; var _run = function () { + var cb = function () { + core.maps._deleteDetachedBlock(canvases); + // 不消失 + if (moveInfo.keep) { + core.setBlock(blockInfo.number, moveInfo.x, moveInfo.y); + core.showBlock(moveInfo.x, moveInfo.y); + core.moveEnemyOnPoint(moveInfo.sx, moveInfo.sy, moveInfo.x, moveInfo.y); + } + if (callback) callback(); + } + var animate = window.setInterval(function () { if (blockInfo.cls != 'tileset') { animateTime += moveInfo.per_time; @@ -2609,9 +2620,9 @@ maps.prototype._moveBlock_doMove = function (blockInfo, canvases, moveInfo, call else core.maps._moveBlock_moving(blockInfo, canvases, moveInfo); } else - core.maps._moveJumpBlock_finished(blockInfo, canvases, moveInfo, animate, callback); + core.maps._moveJumpBlock_finished(blockInfo, canvases, moveInfo, animate, cb); }, moveInfo.per_time); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = cb; } _run(); } @@ -2725,14 +2736,25 @@ maps.prototype.__generateJumpInfo = function (sx, sy, ex, ey, time) { } maps.prototype._jumpBlock_doJump = function (blockInfo, canvases, jumpInfo, callback) { + var cb = function () { + core.maps._deleteDetachedBlock(canvases); + // 不消失 + if (jumpInfo.keep) { + core.setBlock(blockInfo.number, jumpInfo.ex, jumpInfo.ey); + core.showBlock(jumpInfo.ex, jumpInfo.ey); + core.moveEnemyOnPoint(jumpInfo.sx, jumpInfo.sy, jumpInfo.ex, jumpInfo.ey); + } + if (callback) callback(); + } + var animate = window.setInterval(function () { if (jumpInfo.jump_count > 0) core.maps._jumpBlock_jumping(blockInfo, canvases, jumpInfo) else - core.maps._moveJumpBlock_finished(blockInfo, canvases, jumpInfo, animate, callback); + core.maps._moveJumpBlock_finished(blockInfo, canvases, jumpInfo, animate, cb); }, jumpInfo.per_time); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = cb; } maps.prototype.__updateJumpInfo = function (jumpInfo) { @@ -2749,20 +2771,13 @@ maps.prototype._jumpBlock_jumping = function (blockInfo, canvases, jumpInfo) { core.maps._moveDetachedBlock(blockInfo, jumpInfo.px, jumpInfo.py, jumpInfo.opacity, canvases); } -maps.prototype._moveJumpBlock_finished = function (blockInfo, canvases, info, animate, callback) { +maps.prototype._moveJumpBlock_finished = function (blockInfo, canvases, info, animate, cb) { if (info.keep) info.opacity = 0; else info.opacity -= 0.06; if (info.opacity <= 0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - this._deleteDetachedBlock(canvases); - // 不消失 - if (info.keep) { - core.setBlock(blockInfo.number, info.x, info.y); - core.showBlock(info.x, info.y); - core.moveEnemyOnPoint(info.sx, info.sy, info.x, info.y); - } - if (callback) callback(); + cb(); } else { this._moveDetachedBlock(blockInfo, info.px, info.py, info.opacity, canvases); @@ -2790,30 +2805,34 @@ maps.prototype.animateBlock = function (loc, type, time, callback) { maps.prototype._animateBlock_doAnimate = function (loc, list, type, time, callback) { var step = 0, steps = Math.max(parseInt(time / 10), 1); + var cb = function () { + list.forEach(function (t) { + if (t.blockInfo) + core.maps._deleteDetachedBlock(t.canvases); + }); + loc.forEach(function (t) { + if (type == 'show') core.showBlock(t[0], t[1]); + else if (type == 'hide') core.hideBlock(t[0], t[1]); + else if (type == 'remove') core.removeBlock(t[0], t[1]); + else { + core.setBlockOpacity(type, t[0], t[1]); + core.showBlock(t[0], t[1]); + } + }); + if (callback) callback(); + } + var animate = setInterval(function () { step++; core.maps._animateBlock_drawList(list, step / steps); if (step == steps) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - list.forEach(function (t) { - if (t.blockInfo) - core.maps._deleteDetachedBlock(t.canvases); - }); - loc.forEach(function (t) { - if (type == 'show') core.showBlock(t[0], t[1]); - else if (type == 'hide') core.hideBlock(t[0], t[1]); - else if (type == 'remove') core.removeBlock(t[0], t[1]); - else { - core.setBlockOpacity(type, t[0], t[1]); - core.showBlock(t[0], t[1]); - } - }); - if (callback) callback(); + cb(); } }, 10); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = cb; } maps.prototype._animateBlock_getList = function (loc, type) { diff --git a/libs/ui.js b/libs/ui.js index 14439aa7..e680e3f5 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1683,7 +1683,7 @@ ui.prototype._drawScrollText_animate = function (ctx, time, callback) { core.drawImage('ui', ctx.canvas, 0, currH); }, per_time); - core.animateFrame.asyncId[animate] = true; + core.animateFrame.asyncId[animate] = callback; } ////// 文本图片化 ////// diff --git a/project/floors/sample0.js b/project/floors/sample0.js index 7ffc7566..41259e44 100644 --- a/project/floors/sample0.js +++ b/project/floors/sample0.js @@ -99,6 +99,61 @@ main.floors.sample0= "type": "hide", "time": 500 } + ], + "7,7": [ + { + "type": "move", + "loc": [ + 0, + 0 + ], + "time": 100, + "keep": true, + "async": true, + "steps": [ + "right:12", + "left:12", + "right:12", + "left:12", + "right:12", + "left:12", + "right:12", + "left:12", + "right:12", + "left:12", + "right:12", + "left:12", + "right:12", + "left:12", + "right:12", + "left:12", + "right:12", + "left:12", + "right:12", + "left:12", + "right:12", + "left:12" + ] + }, + { + "type": "wait", + "forceChild": true, + "timeout": 10000, + "data": [ + { + "case": "keyboard", + "keycode": "13,32", + "action": [ + { + "type": "stopAsync" + } + ] + } + ] + }, + { + "type": "waitAsync" + } ] }, "changeFloor": { diff --git a/runtime.d.ts b/runtime.d.ts index 50200bf4..f99e7754 100644 --- a/runtime.d.ts +++ b/runtime.d.ts @@ -1232,6 +1232,9 @@ declare class events { /** 当前是否有未处理完毕的异步事件(不包含动画和音效) */ hasAsync(): boolean + /** 立刻停止所有异步事件 */ + stopAsync(): void + /** * 跟随 * @param name 要跟随的一个合法的4x4的行走图名称,需要在全塔属性注册