diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 6fecc669..8eb700d1 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -235,6 +235,7 @@ action | updateEnemys_s | sleep_s | wait_s + | waitAsync_s | battle_s | openDoor_s | changeFloor_s @@ -245,7 +246,7 @@ action | follow_s | unfollow_s | animate_s - | viberate_s + | vibrate_s | showImage_0_s | showImage_1_s | animateImage_0_s @@ -819,6 +820,7 @@ var code = '{"type": "sleep", "time": '+Int_0+'},\n'; return code; */; + battle_s : '强制战斗' IdString Newline @@ -949,18 +951,18 @@ var code = '{"type": "unfollow"' + EvalString_0 + '},\n'; return code; */; -viberate_s +vibrate_s : '画面震动' '时间' Int '不等待执行完毕' Bool Newline -/* viberate_s -tooltip : viberate: 画面震动 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=viberate%ef%bc%9a%e7%94%bb%e9%9d%a2%e9%9c%87%e5%8a%a8 +/* vibrate_s +tooltip : vibrate: 画面震动 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=vibrate%ef%bc%9a%e7%94%bb%e9%9d%a2%e9%9c%87%e5%8a%a8 default : [2000,false] colour : this.soundColor Int_0 = Int_0 ?(', "time": '+Int_0):''; var async = Bool_0?', "async": true':'' -var code = '{"type": "viberate"' + Int_0 + async + '},\n'; +var code = '{"type": "vibrate"' + Int_0 + async + '},\n'; return code; */; @@ -1459,6 +1461,20 @@ var code = '{"type": "wait"},\n'; return code; */; + +waitAsync_s + : '等待所有异步事件执行完毕' + + +/* waitAsync_s +tooltip : waitAsync: 等待所有异步事件执行完毕 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=waitAsync%ef%bc%9a%e7%ad%89%e5%be%85%e6%89%80%e6%9c%89%e5%bc%82%e6%ad%a5%e4%ba%8b%e4%bb%b6%e6%89%a7%e8%a1%8c%e5%ae%8c%e6%af%95 +colour : this.soundColor +var code = '{"type": "waitAsync"},\n'; +return code; +*/; + + function_s : '自定义JS脚本' BGNL? Newline RawEvalString Newline BEND Newline @@ -2023,8 +2039,8 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['animate_s'].xmlText([ data.name,animate_loc,data.async||false,this.next]); break; - case "viberate": // 画面震动 - this.next = MotaActionBlocks['viberate_s'].xmlText([data.time||0, data.async||false, this.next]); + case "vibrate": // 画面震动 + this.next = MotaActionBlocks['vibrate_s'].xmlText([data.time||0, data.async||false, this.next]); break; case "showImage": // 显示图片 if(this.isset(data.name)){ @@ -2221,6 +2237,10 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['wait_s'].xmlText([ this.next]); break; + case "waitAsync": // 等待所有异步事件执行完毕 + this.next = MotaActionBlocks['waitAsync_s'].xmlText([ + this.next]); + break; case "revisit": // 立刻重新执行该事件 this.next = MotaActionBlocks['revisit_s'].xmlText([ this.next]); diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index f36cb09e..2ea9e2bb 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -131,7 +131,8 @@ editor_blockly = function () { '特效/声音':[ MotaActionBlocks['sleep_s'].xmlText(), MotaActionBlocks['wait_s'].xmlText(), - MotaActionBlocks['viberate_s'].xmlText(), + MotaActionBlocks['waitAsync_s'].xmlText(), + MotaActionBlocks['vibrate_s'].xmlText(), MotaActionBlocks['animate_s'].xmlText(), MotaActionBlocks['showStatusBar_s'].xmlText(), MotaActionBlocks['hideStatusBar_s'].xmlText(), diff --git a/docs/event.md b/docs/event.md index 041d9547..3b5cba46 100644 --- a/docs/event.md +++ b/docs/event.md @@ -863,9 +863,9 @@ name为可选的,是要取消跟随的行走图文件名。 如果name省略,则会取消所有的跟随效果。 -### viberate:画面震动 +### vibrate:画面震动 -使用 `{"type": "viberate", "time": 2000, "async": true}` 可以造成画面震动效果。 +使用 `{"type": "vibrate", "time": 2000, "async": true}` 可以造成画面震动效果。 time可以指定震动时间,默认是2000毫秒。 @@ -1548,6 +1548,19 @@ choices为一个数组,其中每一项都是一个选项列表。 ``` +### waitAsync:等待所有异步事件执行完毕 + +上面有很多很多的异步事件(也就执行时不等待执行完毕)。 + +由于录像是加速播放,且会跳过`{"type":"sleep"}`(等待X毫秒)事件;因此异步行为很有可能导致录像播放出错。 + +例如,异步移动一个NPC去某格,然后等待X毫秒,再勇士走过去对话; +但是录像播放中,等待X毫秒的行为会被跳过,因此勇士可能走过去时异步还未执行完成,导致录像出错。 + +我们可以使用`{"type":"waitAsync"}`来等待所有异步事件执行完毕。 + +该事件会进行等待,直到所有可能的异步事件(异步动画除外)执行完毕。 + ### function: 自定义JS脚本 上述给出了这么多事件,但有时候往往不能满足需求,这时候就需要执行自定义脚本了。 diff --git a/libs/control.js b/libs/control.js index c1f03d4b..aca04d4d 100644 --- a/libs/control.js +++ b/libs/control.js @@ -867,6 +867,7 @@ control.prototype.eventMoveHero = function(steps, time, callback) { var animate=window.setInterval(function() { var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); if (moveSteps.length==0) { + delete core.animateFrame.asyncId[animate]; clearInterval(animate); core.drawHero(null, x, y); if (core.isset(callback)) callback(); @@ -889,7 +890,9 @@ control.prototype.eventMoveHero = function(steps, time, callback) { moveSteps.shift(); } } - }, time / 8 / core.status.replay.speed) + }, time / 8 / core.status.replay.speed); + + core.animateFrame.asyncId[animate] = true; } ////// 勇士跳跃事件 ////// @@ -944,6 +947,7 @@ control.prototype.jumpHero = function (ex, ey, time, callback) { nowx - core.bigmap.offsetX, nowy + 32-height - core.bigmap.offsetY, 32, height); } else { + delete core.animateFrame.asyncId[animate]; clearInterval(animate); core.setHeroLoc('x', ex); core.setHeroLoc('y', ey); @@ -953,8 +957,7 @@ control.prototype.jumpHero = function (ex, ey, time, callback) { }, time / 16 / core.status.replay.speed); - - + core.animateFrame.asyncId[animate] = true; } ////// 每移动一格后执行的事件 ////// @@ -1492,12 +1495,15 @@ control.prototype.setFg = function(color, time, callback) { core.fillRect('curtain', 0, 0, 416, 416, core.arrayToRGBA([nowR,nowG,nowB,nowA])); if (step>=25) { + delete core.animateFrame.asyncId[changeAnimate]; clearInterval(changeAnimate); core.status.curtainColor = color; // core.status.replay.animate=false; if (core.isset(callback)) callback(); } }, time/25/core.status.replay.speed); + + core.animateFrame.asyncId[changeAnimate] = true; } ////// 更新全地图显伤 ////// diff --git a/libs/core.js b/libs/core.js index f14206fe..4e87bdd9 100644 --- a/libs/core.js +++ b/libs/core.js @@ -41,7 +41,8 @@ function core() { 'level': 0, 'nodes': [], 'data': null, - } + }, + "asyncId": {} } this.musicStatus = { 'audioContext': null, // WebAudioContext diff --git a/libs/events.js b/libs/events.js index a02099bd..091ab206 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1059,7 +1059,7 @@ events.prototype.doAction = function() { core.updateStatusBar(); this.doAction(); break; - case "viberate": + case "vibrate": if (data.async) { core.events.vibrate(data.time); this.doAction(); @@ -1102,6 +1102,16 @@ events.prototype.doAction = function() { } } break; + case "waitAsync": // 等待所有异步事件执行完毕 + { + var test = window.setInterval(function () { + if (Object.keys(core.animateFrame.asyncId)==0) { + clearInterval(test); + core.events.doAction(); + } + }, 50); + break; + } case "revisit": // 立刻重新执行该事件 { var block=core.getBlock(x,y); // 重新获得事件 @@ -1513,6 +1523,7 @@ events.prototype.animateImage = function (type, image, loc, time, keep, callback else opacityVal -= 0.1; core.setOpacity('data', opacityVal); if (opacityVal >=1 || opacityVal<=0) { + delete core.animateFrame.asyncId[animate]; clearInterval(animate); if (type == 'show' && keep) core.canvas.image.drawImage(image, x, y); @@ -1522,6 +1533,8 @@ events.prototype.animateImage = function (type, image, loc, time, keep, callback if (core.isset(callback)) callback(); } }, time / 10); + + core.animateFrame.asyncId[animate] = true; } ////// 移动图片 ////// @@ -1554,13 +1567,14 @@ events.prototype.moveImage = function (image, from, to, time, keep, callback) { if (step <= steps) drawImage(); else { + delete core.animateFrame.asyncId[animate]; clearInterval(animate); - // score.clearMap('data'); - // core.status.replay.animate=false; if (keep) core.canvas.image.drawImage(image, toX, toY); if (core.isset(callback)) callback(); } }, per_time); + + core.animateFrame.asyncId[animate] = true; } ////// 淡入淡出音乐 ////// @@ -1587,12 +1601,15 @@ events.prototype.setVolume = function (value, time, callback) { var nowVolume = currVolume+(value-currVolume)*step/32; set(nowVolume); if (step>=32) { + delete core.animateFrame.asyncId[fade]; clearInterval(fade); // core.status.replay.animate=false; if (core.isset(callback)) callback(); } }, time / 32); + + core.animateFrame.asyncId[fade] = true; } ////// 画面震动 ////// @@ -1650,11 +1667,14 @@ events.prototype.vibrate = function(time, callback) { update(); addGameCanvasTranslate(shake, 0); if(shake_duration===0) { + delete core.animateFrame.asyncId[animate]; clearInterval(animate); // core.status.replay.animate=false; if (core.isset(callback)) callback(); } }, 50/3); + + core.animateFrame.asyncId[animate] = true; } ////// 打开一个全局商店 ////// diff --git a/libs/maps.js b/libs/maps.js index 229d6ebd..ac08d2dd 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -831,6 +831,7 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { else alpha -= 0.06; core.clearMap('route', nowX, nowY-height+32, 32, height); if (alpha<=0) { + delete core.animateFrame.asyncId[animate]; clearInterval(animate); // 不消失 if (keep) { @@ -872,6 +873,9 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { } } }, time / 16 / core.status.replay.speed); + + core.animateFrame.asyncId[animate] = true; + } ////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 ////// @@ -970,6 +974,7 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) { else alpha -= 0.06; core.clearMap('route', drawX(), drawY()-height+32, 32, height); if (alpha<=0) { + delete core.animateFrame.asyncId[animate]; clearInterval(animate); core.clearMap('route'); core.setOpacity('route', 1); @@ -987,6 +992,8 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) { } }, time / 16 / core.status.replay.speed); + + core.animateFrame.asyncId[animate] = true; } ////// 显示/隐藏某个块时的动画效果 //////