diff --git a/README.md b/README.md index 1006b2c4..8fbb18f2 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,18 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ## 更新说明 +### 2018.9.28 V2.4.2 + +* [x] 允许导入tilesets直接使用,无需PS和注册 +* [x] tilesets的素材允许以矩形方式整体绘制 +* [x] Alt+0~9保存素材,Ctrl+0~9快速选中 +* [x] 增加了透明块的支持 +* [x] 装备允许按照百分比增加属性 +* [x] 多动画的同时播放 +* [x] 修复了打开存读档页面时闪屏的问题 +* [x] 修复了cannotMove仍然能轻按和瞬移的问题 +* [x] 所有已知Bug修复,部分代码重构和细节优化 + ### 2018.9.18 V2.4.1 * [x] 增加背景层和前景层的图块绘制,多层图块可叠加 diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 48850a17..d6e6efbe 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -802,7 +802,7 @@ return code; */; viberate_s - : '画面震动' '时间' Int '异步' Bool Newline + : '画面震动' '时间' Int '不等待执行完毕' Bool Newline /* viberate_s @@ -817,7 +817,7 @@ return code; */; animate_s - : '显示动画' IdString '位置' EvalString? '异步' Bool Newline + : '显示动画' IdString '位置' EvalString? '不等待执行完毕' Bool Newline /* animate_s @@ -867,7 +867,7 @@ return code; */; animateImage_0_s - : '图片淡入' EvalString '起点像素位置' 'x' PosString 'y' PosString '动画时间' Int '异步' Bool Newline + : '图片淡入' EvalString '起点像素位置' 'x' PosString 'y' PosString '动画时间' Int '不等待执行完毕' Bool Newline /* animateImage_0_s @@ -881,7 +881,7 @@ return code; */; animateImage_1_s - : '图片淡出' EvalString '起点像素位置' 'x' PosString 'y' PosString '动画时间' Int '异步' Bool Newline + : '图片淡出' EvalString '起点像素位置' 'x' PosString 'y' PosString '动画时间' Int '不等待执行完毕' Bool Newline /* animateImage_1_s @@ -921,7 +921,7 @@ return code; moveImage_0_s : '图片移动' EvalString '起点像素位置' 'x' PosString 'y' PosString BGNL - '终点像素位置' 'x' PosString 'y' PosString '移动时间' Int '异步' Bool Newline + '终点像素位置' 'x' PosString 'y' PosString '移动时间' Int '不等待执行完毕' Bool Newline /* moveImage_0_s @@ -935,7 +935,7 @@ return code; */; setFg_0_s - : '更改画面色调' Number ',' Number ',' Number ',' Number '动画时间' Int? '异步' Bool Newline + : '更改画面色调' Number ',' Number ',' Number ',' Number '动画时间' Int? '不等待执行完毕' Bool Newline /* setFg_0_s @@ -959,7 +959,7 @@ return code; */; setFg_1_s - : '恢复画面色调' '动画时间' Int? '异步' Bool Newline + : '恢复画面色调' '动画时间' Int? '不等待执行完毕' Bool Newline /* setFg_1_s @@ -1110,7 +1110,7 @@ return code; */; setVolume_s - : '设置音量' Int '渐变时间' Int? '异步' Bool Newline + : '设置音量' Int '渐变时间' Int? '不等待执行完毕' Bool Newline /* setVolume_s diff --git a/_server/editor.js b/_server/editor.js index 937d5dd0..1372d04f 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -1,6 +1,6 @@ function editor() { this.version = "2.0"; - this.brushMod = "line";//["line","rectangle"] + this.brushMod = "line";//["line","rectangle","tileset"] this.layerMod = "map";//["fgmap","map","bgmap"] this.isMobile = false; } @@ -97,6 +97,12 @@ editor.prototype.idsInit = function (maps, icons) { var id = indexBlock.event.id; var indexId = indexBlock.id; var allCls = Object.keys(icons); + if(i==17){ + editor.ids.push({'idnum': 17, 'id': id, 'images': 'terrains'}); + point++; + editor.indexs[i].push(point); + continue; + } for (var j = 0; j < allCls.length; j++) { if (id in icons[allCls[j]]) { editor.ids.push({'idnum': indexId, 'id': id, 'images': allCls[j], 'y': icons[allCls[j]][id]}); @@ -114,7 +120,10 @@ editor.prototype.idsInit = function (maps, icons) { var img = core.material.images.tilesets[imgName]; var width = Math.floor(img.width/32), height = Math.floor(img.height/32); if(img.width%32 || img.height%32){ - alert(imgName+'的长或宽不是32的整数倍, 请修改后刷新页面') + alert(imgName+'的长或宽不是32的整数倍, 请修改后刷新页面'); + } + if(img.width*img.height > 32*32*1000){ + alert(imgName+'上的图块数量超过了1000,请修改后刷新页面'); } for (var id=startOffset; idx1){x0^=x1;x1^=x0;x0^=x1;}//swap if(y0>y1){y0^=y1;y1^=y0;y0^=y1;}//swap stepPostfix=[]; - for(var ii=x0;ii<=x1;ii++){ - for(var jj=y0;jj<=y1;jj++){ + for(var jj=y0;jj<=y1;jj++){ + for(var ii=x0;ii<=x1;ii++){ stepPostfix.push({x:ii,y:jj}) } } @@ -646,8 +692,22 @@ editor.prototype.listen = function () { if (editor.layerMod!='map' && editor.info.images && editor.info.images.indexOf('48')!==-1){ printe('前景/背景不支持48的图块'); } else { - for (var ii = 0; ii < stepPostfix.length; ii++) + if(editor.brushMod==='tileset' && core.tilesets.indexOf(editor.info.images)!==-1){ + var imgWidth=~~(core.material.images.tilesets[editor.info.images].width/32); + var x0=stepPostfix[0].x; + var y0=stepPostfix[0].y; + var idnum=editor.info.idnum; + for (var ii = 0; ii < stepPostfix.length; ii++){ + if(stepPostfix[ii].y!=y0){ + y0++; + idnum+=imgWidth; + } + editor[editor.layerMod][stepPostfix[ii].y][stepPostfix[ii].x] = editor.ids[editor.indexs[idnum+stepPostfix[ii].x-x0]]; + } + } else { + for (var ii = 0; ii < stepPostfix.length; ii++) editor[editor.layerMod][stepPostfix[ii].y][stepPostfix[ii].x] = editor.info; + } } // console.log(editor.map); editor.updateMap(); @@ -710,9 +770,12 @@ editor.prototype.listen = function () { info: {} }; var reDo = null; + var shortcut = core.getLocalStorage('shortcut',{48: 0, 49: 0, 50: 0, 51: 0, 52: 0, 53: 0, 54: 0, 55: 0, 56: 0, 57: 0}); document.body.onkeydown = function (e) { // 禁止快捷键的默认行为 - if (e.ctrlKey && ( e.keyCode == 90 || e.keyCode == 89 )) + if (e.ctrlKey && [89, 90, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) + e.preventDefault(); + if (e.altKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) e.preventDefault(); //Ctrl+z 撤销上一步undo if (e.keyCode == 90 && e.ctrlKey && preMapData && currDrawData.pos.length && selectBox.isSelected) { @@ -757,6 +820,18 @@ editor.prototype.listen = function () { editor.changeFloor(toId); } } + //ctrl + 0~9 切换到快捷图块 + if (e.ctrlKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1){ + editor.setSelectBoxFromInfo(JSON.parse(JSON.stringify(shortcut[e.keyCode]||0))); + } + //alt + 0~9 改变快捷图块 + if (e.altKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1){ + var infoToSave = JSON.stringify(editor.info||0); + if(infoToSave==JSON.stringify({}))return; + shortcut[e.keyCode]=JSON.parse(infoToSave); + printf('已保存该快捷图块, ctrl + '+(e.keyCode-48)+' 使用.') + core.setLocalStorage('shortcut',shortcut); + } } var dataSelection = document.getElementById('dataSelection'); @@ -803,9 +878,11 @@ editor.prototype.listen = function () { if (pos.x == 0 && pos.y == 0) { // editor.info={idnum:0, id:'empty','images':'清除块', 'y':0}; editor.info = 0; + } else if(pos.x == 0 && pos.y == 1){ + editor.info = editor.ids[editor.indexs[17]]; } else { if (hasOwnProp(autotiles, pos.images)) editor.info = {'images': pos.images, 'y': 0}; - else if (pos.images == 'terrains') editor.info = {'images': pos.images, 'y': pos.y - 1}; + else if (pos.images == 'terrains') editor.info = {'images': pos.images, 'y': pos.y - 2}; else if (core.tilesets.indexOf(pos.images)!=-1) editor.info = {'images': pos.images, 'y': pos.y, 'x': pos.x-editor.widthsX[spriter][1]}; else editor.info = {'images': pos.images, 'y': pos.y}; @@ -874,28 +951,7 @@ editor.prototype.listen = function () { editor.hideMidMenu(); e.stopPropagation(); var thisevent = editor.map[editor.pos.y][editor.pos.x]; - var pos={x: 0, y: 0, images: "terrains"}; - var ysize = 32; - if(thisevent==0){ - //选中清除块 - editor.info = 0; - editor.pos=pos; - } else { - var ids=editor.indexs[thisevent.idnum]; - ids=ids[0]?ids[0]:ids; - editor.info=editor.ids[ids]; - pos.x=editor.widthsX[thisevent.images][1]; - pos.y=editor.info.y; - if(thisevent.images=='terrains')pos.y++; - ysize = thisevent.images.indexOf('48') === -1 ? 32 : 48; - } - setTimeout(function(){selectBox.isSelected = true;}); - dataSelection.style.left = pos.x * 32 + 'px'; - dataSelection.style.top = pos.y * ysize + 'px'; - dataSelection.style.height = ysize - 6 + 'px'; - tip.infos = JSON.parse(JSON.stringify(editor.info)); - editor_mode.onmode('nextChange'); - editor_mode.onmode('enemyitem'); + editor.setSelectBoxFromInfo(thisevent); } var fields = Object.keys(editor.file.comment._data.floors._data.loc._data); @@ -1013,6 +1069,11 @@ editor.prototype.listen = function () { editor.brushMod=brushMod2.value; } + var brushMod3=document.getElementById('brushMod3'); + if(brushMod3)brushMod3.onchange=function(){ + editor.brushMod=brushMod3.value; + } + var layerMod=document.getElementById('layerMod'); layerMod.onchange=function(){ editor.layerMod=layerMod.value; diff --git a/_server/editor_mode.js b/_server/editor_mode.js index ad0ba74f..9bbf0c0b 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -315,7 +315,7 @@ editor_mode = function (editor) { //editor.info=editor.ids[editor.indexs[201]]; if (!core.isset(editor.info)) return; - if (Object.keys(editor.info).length !== 0) editor_mode.info = editor.info;//避免editor.info被清空导致无法获得是物品还是怪物 + if (Object.keys(editor.info).length !== 0 && editor.info.idnum!=17) editor_mode.info = editor.info;//避免editor.info被清空导致无法获得是物品还是怪物 if (!core.isset(editor_mode.info.id)) { // document.getElementById('table_a3f03d4c_55b8_4ef6_b362_b345783acd72').innerHTML = ''; diff --git a/_server/vm.js b/_server/vm.js index afd49b90..6707dea0 100644 --- a/_server/vm.js +++ b/_server/vm.js @@ -241,6 +241,7 @@ var tip = new Vue({ isAutotile: false, isSelectedBlock: false, isClearBlock: false, + isAirwall: false, geneMapSuccess: false, timer: null, msgs: [ //分别编号1,2,3,4,5,6,7,8,9,10;奇数警告,偶数成功 @@ -264,12 +265,17 @@ var tip = new Vue({ infos: { handler: function (val, oldval) { this.isClearBlock = false; + this.isAirwall = false; if (typeof(val) != 'undefined') { if (val == 0) { this.isClearBlock = true; return; } if ('id' in val) { + if (val.idnum == 17) { + this.isAirwall = true; + return; + } this.hasId = true; } else { this.hasId = false; diff --git a/docs/V2.0.md b/docs/V2.0.md index 0df0686a..95c18918 100644 --- a/docs/V2.0.md +++ b/docs/V2.0.md @@ -1,6 +1,6 @@ # V2.0版本介绍 -?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.2**,上次更新时间:* {docsify-updated} * 目前样板已经更新到V2.0版本以上,本章将对V2.0的一些内容进行介绍。 diff --git a/docs/api.md b/docs/api.md index 699407e0..14cde546 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,6 +1,6 @@ # 附录: API列表 -?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.2**,上次更新时间:* {docsify-updated} * **这里只列出所有可能会被造塔者用到的常用API,更多的有关内容请在代码内进行查询。** diff --git a/docs/element.md b/docs/element.md index a9e1dc78..400a0605 100644 --- a/docs/element.md +++ b/docs/element.md @@ -1,6 +1,6 @@ # 元件说明 -?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.2**,上次更新时间:* {docsify-updated} * 在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。 diff --git a/docs/event.md b/docs/event.md index 34ce372d..9a38fa19 100644 --- a/docs/event.md +++ b/docs/event.md @@ -1,6 +1,6 @@ # 事件 -?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.2**,上次更新时间:* {docsify-updated} * 本章内将对样板所支持的事件进行介绍。 diff --git a/docs/index.md b/docs/index.md index b4ca28de..20370283 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ # HTML5 魔塔样板说明文档 -?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.2**,上次更新时间:* {docsify-updated} * 众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。 diff --git a/docs/personalization.md b/docs/personalization.md index ab9ed33e..f7d4422b 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -1,6 +1,6 @@ # 个性化 -?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.2**,上次更新时间:* {docsify-updated} * 有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。 @@ -261,6 +261,8 @@ ID必须由数字字母下划线组成,数字在1000以内,且均不能和 除此之外,额外素材在游戏中的使用和正式素材都是一致的,也能在前景或背景图层绘制。 +额外素材可以使用“tileset贴图”的方式进行绘制,一次绘制一个矩形区域。 + ## 自定义道具效果 本节中将继续介绍如何自己编辑一个道具的效果。 diff --git a/docs/start.md b/docs/start.md index f819c427..2db090e1 100644 --- a/docs/start.md +++ b/docs/start.md @@ -1,6 +1,6 @@ # 快速上手 -?> 目前版本**v2.4.1**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.4.2**,上次更新时间:* {docsify-updated} * 在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔! @@ -50,6 +50,8 @@ 绘制地图时可以右键弹出菜单,移动图块和事件。 +从V2.4.2开始,可以使用`Alt+0~9`对一个图块素材快速保存,`Ctrl+0~9`来快速选用。 + ### 从RMXP导入已有的地图 如果我们想复刻一个现有的,已经被RMXP所制作的塔,也有很便捷的方式,那就是用到我们的“地图生成器”。 diff --git a/editor-mobile.html b/editor-mobile.html index 5aaa217f..3f656e78 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -234,6 +234,7 @@

当前选择为清除块,可擦除地图上块

+

当前选择为空气墙, 在编辑器中可视, 在游戏中隐藏的墙, 用来配合前景/背景的贴图

图块编号:{{ infos['idnum'] }}

图块ID:{{ infos['id'] }}

@@ -276,6 +277,7 @@ - +
+ 画线 画矩形 + tileset贴图
@@ -432,6 +435,8 @@ if (location.protocol.indexOf("http")!=0) {