From 8e68f1fbdf954dbc357da77668822b548460e4e8 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Wed, 18 Apr 2018 18:11:21 +0800 Subject: [PATCH] Animate image & Gif support --- .idea/misc.xml | 6 ++ _server/blockly/MotaAction.g4 | 73 +++++++++++++++ _server/editor_blockly.js | 4 + docs/event.md | 44 +++++++++ editor.html | 8 +- index.html | 2 + libs/control.js | 18 ++++ libs/events.js | 166 ++++++++++++++++++++++++---------- libs/loader.js | 2 +- libs/maps.js | 18 +++- main.js | 2 + project/data.js | 6 +- project/floors/sample2.js | 2 +- project/sounds/058-Slow01.mid | Bin 6183 -> 0 bytes styles.css | 52 +++++++---- 更新说明.txt | 4 +- 16 files changed, 327 insertions(+), 80 deletions(-) create mode 100644 .idea/misc.xml delete mode 100644 project/sounds/058-Slow01.mid diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..28a804d8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index dc9c1e17..033ed685 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -177,6 +177,10 @@ action | animate_s | showImage_0_s | showImage_1_s + | animateImage_0_s + | animateImage_1_s + | showGif_0_s + | showGif_1_s | setFg_0_s | setFg_1_s | setWeather_s @@ -577,6 +581,57 @@ var code = '{"type": "showImage"},\n'; return code; */ +animateImage_0_s + : '图片淡入' EvalString '起点像素位置' 'x' Number 'y' Number '动画时间' Int Newline + ; + +/* animateImage_0_s +tooltip : animageImage:图片淡入 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=animateimage%ef%bc%9a%e5%9b%be%e7%89%87%e6%b7%a1%e5%85%a5%e6%b7%a1%e5%87%b +default : ["bg.jpg",0,0,500] +colour : this.printColor +var code = '{"type": "animateImage", "action": "show", "name": "'+EvalString_0+'", "loc": ['+Number_0+','+Number_1+'], "time": '+Int_0+'},\n'; +return code; +*/ + +animateImage_1_s + : '图片淡出' EvalString '起点像素位置' 'x' Number 'y' Number '动画时间' Int Newline + ; + +/* animateImage_1_s +tooltip : animageImage:图片淡出 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=animateimage%ef%bc%9a%e5%9b%be%e7%89%87%e6%b7%a1%e5%85%a5%e6%b7%a1%e5%87%b +default : ["bg.jpg",0,0,500] +colour : this.printColor +var code = '{"type": "animateImage", "action": "hide", "name": "'+EvalString_0+'", "loc": ['+Number_0+','+Number_1+'], "time": '+Int_0+'},\n'; +return code; +*/ + +showGif_0_s + : '显示动图' EvalString '起点像素位置' 'x' Number 'y' Number Newline + ; + +/* showGif_0_s +tooltip : showGif:显示动图 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=showgif%ef%bc%9a%e6%98%be%e7%a4%ba%e5%8a%a8%e5%9b%be +default : ["bg.gif",0,0] +colour : this.printColor +var code = '{"type": "showGif", "name": "'+EvalString_0+'", "loc": ['+Number_0+','+Number_1+']},\n'; +return code; +*/ + +showGif_1_s + : '清除所有动图' Newline + ; + +/* showGif_1_s +tooltip : showGif:清除所有显示的动图 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=showgif%ef%bc%9a%e6%98%be%e7%a4%ba%e5%8a%a8%e5%9b%be +colour : this.printColor +var code = '{"type": "showGif"},\n'; +return code; +*/ + setFg_0_s : '更改画面色调' Number ',' Number ',' Number ',' Number '动画时间' Int? Newline ; @@ -1244,6 +1299,24 @@ ActionParser.prototype.parseAction = function() { this.next]); } break; + case "animateImage": // 显示图片 + if(data.action == 'show'){ + this.next = MotaActionBlocks['animateImage_0_s'].xmlText([ + data.name,data.loc[0],data.loc[1],data.time,this.next]); + } else if (data.action == 'hide') { + this.next = MotaActionBlocks['animateImage_1_s'].xmlText([ + data.name,data.loc[0],data.loc[1],data.time,this.next]); + } + break; + case "showGif": // 显示动图 + if(this.isset(data.name)){ + this.next = MotaActionBlocks['showGif_0_s'].xmlText([ + data.name,data.loc[0],data.loc[1],this.next]); + } else { + this.next = MotaActionBlocks['showGif_1_s'].xmlText([ + this.next]); + } + break; case "setFg": // 颜色渐变 if(this.isset(data.color)){ this.next = MotaActionBlocks['setFg_0_s'].xmlText([ diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index e4ac4e5d..0baf0f45 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -62,7 +62,11 @@ editor_blockly = function () { ]}), MotaActionBlocks['setText_s'].xmlText(), MotaActionBlocks['showImage_0_s'].xmlText(), + MotaActionBlocks['animateImage_0_s'].xmlText(), + MotaActionBlocks['animateImage_1_s'].xmlText(), MotaActionBlocks['showImage_1_s'].xmlText(), + MotaActionBlocks['showGif_0_s'].xmlText(), + MotaActionBlocks['showGif_1_s'].xmlText(), MotaActionBlocks['tip_s'].xmlText(), MotaActionBlocks['openShop_s'].xmlText(), MotaActionBlocks['win_s'].xmlText(), diff --git a/docs/event.md b/docs/event.md index f661e1d3..b7ff20fd 100644 --- a/docs/event.md +++ b/docs/event.md @@ -636,6 +636,50 @@ loc为图片左上角坐标,以像素为单位进行计算。 调用show/hide/move/animate等几个事件同样会清除所有显示的图片。 +### animateImage:图片淡入淡出 + +我们还可以使用 `{"type": "animateImage"}` 来造成显示图片的淡入淡出效果。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "animateImage", "action": "show", "name": "bg.jpg", "loc": [231,297], "time": 500}, // 在(231,297)淡入bg.jpg,动画时间500ms + {"type": "animateImage", "action": "hide", "name": "1.png", "loc": [109,167], "time": 300}, // 在(109,167)淡出1.png,动画时间300ms +] +``` + +action为淡入还是淡出,`show`为淡入,`hide`会淡出。 + +name为图片名。**请确保图片在data.js中的images中被定义过。** + +loc为图片左上角坐标,以像素为单位进行计算。 + +time为淡入淡出的时间,如果是0则忽略此项。 + +!> 淡入淡出图片只是会在顶层绘制“淡入”和“淡出”效果,动画结束即消失,并不会实际对图片的显示造成影响。请与showImage事件合用。 + +如果多张图片的淡入淡出可以采用以下方式(仅供参考): + +假设我现在已经有了`1.jpg`显示在屏幕上: +- 淡入显示`2.png`:调用`animateImage`淡入图片,然后立刻调用`showImage`显示图片。 +- 淡出`1.png`:清除所有图片,`showImage`显示`2.png`,然后调用`animateImage`淡出`1.jpg` + +### showGif:显示动图 + +我们可以使用 `{"type": "showGif"}` 来显示一张图片。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "showGif", "name": "timg.gif", "loc": [231,297]}, // 在(231,297)显示一张动图 + {"type": "showGif"} // 如果不指定name则清除所有动图。 +] +``` + +name为图片名。**请确保图片在data.js中的images中被定义过。** + +loc为动图左上角坐标,以像素为单位进行计算。 + +如果不指定name则清除所有显示的动图。 + ### setFg: 更改画面色调 我们可以使用 `{"type": "setFg"}` 来更改画面色调。 diff --git a/editor.html b/editor.html index 47d845cb..e3a2d9fa 100644 --- a/editor.html +++ b/editor.html @@ -139,9 +139,11 @@

事件编辑器    + + - +

+
+
diff --git a/index.html b/index.html index e04a22e4..bf967b87 100644 --- a/index.html +++ b/index.html @@ -103,6 +103,8 @@

+
+
diff --git a/libs/control.js b/libs/control.js index 85c001db..a4db300b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2349,6 +2349,24 @@ control.prototype.resize = function(clientWidth, clientHeight) { border: '3px #fff solid', } }, + { + id: 'gif', + rules: { + width: (canvasWidth - SPACE*2) + unit, + height:(canvasWidth - SPACE*2) + unit, + top: (canvasTop + SPACE) + unit, + right: SPACE + unit, + } + }, + { + id: 'gif2', + rules: { + width: (canvasWidth - SPACE*2) + unit, + height:(canvasWidth - SPACE*2) + unit, + top: (canvasTop + SPACE) + unit, + right: SPACE + unit, + } + }, { id: 'curtain', rules: { diff --git a/libs/events.js b/libs/events.js index 67c8dbcd..de85c843 100644 --- a/libs/events.js +++ b/libs/events.js @@ -390,13 +390,15 @@ events.prototype.doAction = function() { }); break; case "changeFloor": // 楼层转换 - var heroLoc = {"x": data.loc[0], "y": data.loc[1]}; - if (core.isset(data.direction)) heroLoc.direction=data.direction; - core.changeFloor(data.floorId||core.status.floorId, null, heroLoc, data.time, function() { - core.lockControl(); - core.events.doAction(); - }); - break; + { + var heroLoc = {"x": data.loc[0], "y": data.loc[1]}; + if (core.isset(data.direction)) heroLoc.direction=data.direction; + core.changeFloor(data.floorId||core.status.floorId, null, heroLoc, data.time, function() { + core.lockControl(); + core.events.doAction(); + }); + break; + } case "changePos": // 直接更换勇士位置,不切换楼层 core.clearMap('hero', 0, 0, 416, 416); if (core.isset(data.loc)) { @@ -414,6 +416,36 @@ events.prototype.doAction = function() { else core.clearMap('animate', 0, 0, 416, 416); this.doAction(); break; + case "animateImage": // 淡入淡出图片 + if (core.status.replay.replaying) { // 正在播放录像 + this.doAction(); + } + else { + if (core.isset(data.loc) && core.isset(core.material.images.images[data.name]) && (data.action=="show" || data.action=="hide")) { + core.events.animateImage(data.action, core.material.images.images[data.name], data.loc, data.time, function() { + core.events.doAction(); + }); + } + else { + this.doAction(); + } + } + break; + case "showGif": // 显示动图 + if (core.isset(data.loc) && core.isset(core.material.images.images[data.name])) { + var gif = new Image(); + gif.src = core.material.images.images[data.name].src; + gif.style.position = 'absolute'; + gif.style.left = (data.loc[0]*core.domStyle.scale)+"px"; + gif.style.top = (data.loc[1]*core.domStyle.scale)+"px"; + core.dom.gif2.appendChild(gif); + } + else { + while (core.dom.gif2.firstChild) + core.dom.gif2.removeChild(core.dom.gif2.firstChild); + } + this.doAction(); + break; case "setFg": // 颜色渐变 core.setFg(data.color, data.time, function() { core.events.doAction(); @@ -424,21 +456,23 @@ events.prototype.doAction = function() { this.doAction(); break; case "openDoor": // 开一个门,包括暗墙 - var floorId=data.floorId || core.status.floorId; - var block=core.getBlock(data.loc[0], data.loc[1], floorId); - if (block!=null) { - if (floorId==core.status.floorId) - core.openDoor(block.block.event.id, block.block.x, block.block.y, false, function() { - core.events.doAction(); - }) - else { - core.removeBlock(block.block.x,block.block.y,floorId); - this.doAction(); + { + var floorId=data.floorId || core.status.floorId; + var block=core.getBlock(data.loc[0], data.loc[1], floorId); + if (block!=null) { + if (floorId==core.status.floorId) + core.openDoor(block.block.event.id, block.block.x, block.block.y, false, function() { + core.events.doAction(); + }) + else { + core.removeBlock(block.block.x,block.block.y,floorId); + this.doAction(); + } + break; } + this.doAction(); break; } - this.doAction(); - break; case "openShop": // 打开一个全局商店 if (core.status.replay.replaying) { // 正在播放录像,简单将visited置为true core.status.shops[data.id].visited=true; @@ -458,19 +492,21 @@ events.prototype.doAction = function() { }) break; case "trigger": // 触发另一个事件;当前事件会被立刻结束。需要另一个地点的事件是有效的 - var toX=data.loc[0], toY=data.loc[1]; - var block=core.getBlock(toX, toY); - if (block!=null) { - block = block.block; - if (core.isset(block.event) && block.event.trigger=='action') { - // 触发 - core.status.event.data.list = core.clone(block.event.data); - core.status.event.data.x=block.x; - core.status.event.data.y=block.y; + { + var toX=data.loc[0], toY=data.loc[1]; + var block=core.getBlock(toX, toY); + if (block!=null) { + block = block.block; + if (core.isset(block.event) && block.event.trigger=='action') { + // 触发 + core.status.event.data.list = core.clone(block.event.data); + core.status.event.data.x=block.x; + core.status.event.data.y=block.y; + } } + this.doAction(); + break; } - this.doAction(); - break; case "playSound": if (!core.status.replay.replaying) core.playSound(data.name); @@ -586,16 +622,18 @@ events.prototype.doAction = function() { }); break; case "function": - var func = data["function"]; - if (core.isset(func)) { - if ((typeof func == "string") && func.indexOf("function")==0) { - eval('('+func+')()'); + { + var func = data["function"]; + if (core.isset(func)) { + if ((typeof func == "string") && func.indexOf("function")==0) { + eval('('+func+')()'); + } + else if (func instanceof Function) + func(); } - else if (func instanceof Function) - func(); + this.doAction(); + break; } - this.doAction(); - break; case "update": core.updateStatusBar(); this.doAction(); @@ -610,15 +648,17 @@ events.prototype.doAction = function() { } break; case "revisit": // 立刻重新执行该事件 - var block=core.getBlock(x,y); // 重新获得事件 - if (block!=null) { - block = block.block; - if (core.isset(block.event) && block.event.trigger=='action') { - core.status.event.data.list = core.clone(block.event.data); + { + var block=core.getBlock(x,y); // 重新获得事件 + if (block!=null) { + block = block.block; + if (core.isset(block.event) && block.event.trigger=='action') { + core.status.event.data.list = core.clone(block.event.data); + } } + this.doAction(); + break; } - this.doAction(); - break; case "exit": // 立刻结束事件 core.status.event.data.list = []; core.events.doAction(); @@ -893,6 +933,10 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback } else core.setWeather(); + // 清除gif + while (core.dom.gif.firstChild) + core.dom.gif.removeChild(core.dom.gif.firstChild); + // 检查重生 if (!core.isset(fromLoad)) { core.status.maps[floorId].blocks.forEach(function(block) { @@ -902,7 +946,6 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback } }) } - core.drawMap(floorId, function () { setTimeout(function() { if (core.isset(heroLoc.direction)) @@ -941,6 +984,37 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback }, 25); } +////// 图片淡入/淡出 ////// +events.prototype.animateImage = function (type, image, loc, time, callback) { + time = time||0; + if ((type!='show' && type!='hide') || time<=0) { + if (core.isset(callback)) callback(); + return; + } + + clearInterval(core.interval.tipAnimate); + core.setAlpha('data', 1); + + var opacityVal = 0; + if (type == 'hide') opacityVal = 1; + + core.setOpacity('data', opacityVal); + core.canvas.data.drawImage(image, loc[0], loc[1]); + core.status.replay.animate=true; + var animate = setInterval(function () { + if (type=='show') opacityVal += 0.1; + else opacityVal -= 0.1; + core.setOpacity('data', opacityVal); + if (opacityVal >=1 || opacityVal<=0) { + clearInterval(animate); + core.clearMap('data', 0, 0, 416, 416); + core.setOpacity('data', 1); + core.status.replay.animate=false; + if (core.isset(callback)) callback(); + } + }, time / 10 / core.status.replay.speed); +} + ////// 打开一个全局商店 ////// events.prototype.openShop = function(shopId, needVisited) { var shop = core.status.shops[shopId]; diff --git a/libs/loader.js b/libs/loader.js index 48844bb6..5f36f1dc 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -171,7 +171,7 @@ loader.prototype.loadMusic = function () { } else { var music = new Audio(); - music.preload = core.musicStatus.startDirectly?'auto':'none'; + music.preload = 'none'; if (main.bgmRemote) music.src = 'https://gitee.com/ckcz123/h5music/raw/master/'+core.firstData.name+'/'+t; else music.src = 'project/sounds/'+t; music.loop = 'loop'; diff --git a/libs/maps.js b/libs/maps.js index 23866b4a..d2575c2c 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -328,8 +328,19 @@ maps.prototype.drawMap = function (mapName, callback) { if (core.isset(dx) && core.isset(dy) && core.isset(core.material.images.images[p])) { dx*=32; dy*=32; var image = core.material.images.images[p]; - if (!t[3]) - core.canvas.bg.drawImage(image, dx*ratio, dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); + if (!t[3]) { + core.canvas.bg.drawImage(image, dx * ratio, dy * ratio, Math.min(size - dx * ratio, ratio * image.width), Math.min(size - dy * ratio, ratio * image.height)); + if (/.*\.gif/i.test(p)) { + while (core.dom.gif.firstChild) + core.dom.gif.removeChild(core.dom.gif.firstChild); + var gif = new Image(); + gif.src = core.material.images.images[p].src; + gif.style.position = 'absolute'; + gif.style.left = (dx*core.domStyle.scale)+"px"; + gif.style.top = (dy*core.domStyle.scale)+"px"; + core.dom.gif.appendChild(gif); + } + } else core.canvas.event2.drawImage(image, dx*ratio, dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height)); } @@ -669,9 +680,6 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { if (type=='show') opacityVal += 0.1; else opacityVal -= 0.1; core.setOpacity('animate', opacityVal); - core.clearMap('animate',0,0,416,416); - - draw(); if (opacityVal >=1 || opacityVal<=0) { clearInterval(animate); core.clearMap('animate', 0, 0, 416, 416); diff --git a/main.js b/main.js index ee198da6..945206a6 100644 --- a/main.js +++ b/main.js @@ -35,6 +35,8 @@ function main() { 'toolBar': document.getElementById('toolBar'), 'tools': document.getElementsByClassName('tools'), 'gameCanvas': document.getElementsByClassName('gameCanvas'), + 'gif': document.getElementById('gif'), + 'gif2': document.getElementById('gif2'), 'curtain': document.getElementById('curtain'), 'startButtons': document.getElementById('startButtons'), 'playGame': document.getElementById('playGame'), diff --git a/project/data.js b/project/data.js index 247bd3a7..1bf2802b 100644 --- a/project/data.js +++ b/project/data.js @@ -5,13 +5,13 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "sample0", "sample1", "sample2", "MT0" ], "images" : [ - "bg.jpg", + "bg.jpg" ], "animates" : [ - "hand", "sword", "zone", "yongchang", + "hand", "sword", "zone", ], "bgms" : [ - 'bgm.mp3', 'qianjin.mid', 'star.mid', + 'bgm.mp3' ], "sounds" : [ 'floor.mp3', 'attack.ogg', 'door.ogg', 'item.ogg', 'zone.ogg' diff --git a/project/floors/sample2.js b/project/floors/sample2.js index 187e2520..8467f162 100644 --- a/project/floors/sample2.js +++ b/project/floors/sample2.js @@ -12,7 +12,7 @@ main.floors.sample2 = "images": [], // // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。 "color": [255,0,0,0.3], // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。 "weather": ["rain",10], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。 - "bgm": "qianjin.mid", // 到达该层后默认播放的BGM。本项可忽略。 + "bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。 "item_ratio": 1, // 该层的宝石/血瓶倍率 "map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成 [ 5, 5, 5, 5, 5, 5, 87, 5, 5, 5, 5, 5, 5], diff --git a/project/sounds/058-Slow01.mid b/project/sounds/058-Slow01.mid deleted file mode 100644 index 05ce9228c590fc77d3959b0c8230c51ce44ea5ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6183 zcmeH~OK%fb7=}+EG-%j#!J6{)qH>=azAX(4bmKNGwKk<~`s2eDj`jGWmshW6T?- z#~kl@n#n)_dog2?B+L!6)^W4@?$N%lPE`uLPkg$@ zd#<3RLGhnUt80)D?EcZ6DwrNb+ zX6>Q*(kx~ZW^pQE8fn0+4Uh%^^ra#a86+kokwId@S4jmbDFBRmHZU04a8=|*Dw4=Z zMH1L)T)k}?*LcQmmy3&60mpc*CCbGv&)E1F3H;c;pAq@#?##=|XOvtNc~W&7C7&dZ zt$eyWqkO`;1?%J1t-CX0`0;8-K3)$P`hk49JJa3j9BgfZd^GE>51sF>b0?#yu1 z&v4XFcW1gA^}*I=Ql>G@lTK9%i!%^JPJsH=chjG_o++W4GD-NMbBi`YwZjBn1{2V@v22Pvo=`3_4Y??<&i z`keAnAv5!oB$Ft;uJHjij#N|~G|(v0QyQ6H-i#M5?Crj{>FwTyyN`fMe7i@ z{LgqY^3Gq;Olkl#HYYWhj3S4Td7+qJLSEg9C(Qjhbv}&DNUBs}18R=(=6FTZl>9C# zxlNSiJDd1opcx1z0kj+wyuCIlxm^+y{7;L+SYU%|j`HTD%1V2dCwXg~GrTi$Z8Km4 z3_}PkcZPsqF!AgpOmhZ9GqRXx0J$}DykRllRs1^$CGZr4_*(zfuAkQkra8^}b5exs zye8iNJq|w3e9%zW`M%EgtFAvw9vof6{txmF`u%0kd%wCk-uw0U`#)el+%1pvYPWp& z{=<9b`=qtSZn?#7xn)gRTO0(p*e(AsiSpl1TA7?_X(Oq!wNxRQRuW)T0Gw8Zg<5F< z?E_V|zA6OQngGxyqz_58CIQ5{(yy}P##LfoGAYxV$r%Ev6t;R!qAUL#xLP@kG0RM; z3KI!$O@q;qRXS5q_(AV!U-qN7eb1VS1zaiY3m6~>c$9Ebxk|qhCIj0~DI(!z5V~Y0 zDA+i<)F?&Q=gw}Kxgt?jVZ0lA~Od+GrSQ7(2Iuh%IgfZEgi1c8yyBDcT2Q7%2xSs2rSOBbG?sk7|GP zx)r#E)UANzORsBuK#e06RR?h^prbB<_E36p{CrxcO!G6-EV6BG=ZliMH_