diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 6fecc669..c4c827c9 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -183,6 +183,18 @@ var code = '[\n'+action_0+']\n'; return code; */; +//eachArrive 事件编辑器入口之一 +eachArrive_m + : '每次到达楼层' BGNL? Newline action+ BEND + + +/* eachArrive_m +tooltip : 每次到达楼层 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6 +var code = '[\n'+action_0+']\n'; +return code; +*/; + //changeFloor 事件编辑器入口之一 changeFloor_m : '楼梯, 传送门' BGNL? Newline Floor_List IdString? Stair_List 'x' Number ',' 'y' Number '朝向' DirectionEx_List '动画时间' Int? '允许穿透' Bool BEND @@ -235,6 +247,7 @@ action | updateEnemys_s | sleep_s | wait_s + | waitAsync_s | battle_s | openDoor_s | changeFloor_s @@ -245,7 +258,7 @@ action | follow_s | unfollow_s | animate_s - | viberate_s + | vibrate_s | showImage_0_s | showImage_1_s | animateImage_0_s @@ -470,13 +483,13 @@ return code; show_s - : '显示事件' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '动画时间' Int? Newline + : '显示事件' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '动画时间' Int? '不等待执行完毕' Bool? Newline /* show_s tooltip : show: 将禁用事件启用,楼层和动画时间可不填,xy可用逗号分隔表示多个点 helpUrl : https://h5mota.com/games/template/docs/#/event?id=show%EF%BC%9A%E5%B0%86%E4%B8%80%E4%B8%AA%E7%A6%81%E7%94%A8%E4%BA%8B%E4%BB%B6%E5%90%AF%E7%94%A8 -default : ["","","",500] +default : ["","","",500,false] colour : this.eventColor var floorstr = ''; if (EvalString_0 && EvalString_1) { @@ -497,18 +510,19 @@ if (EvalString_0 && EvalString_1) { } IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); Int_0 = Int_0 ?(', "time": '+Int_0):''; -var code = '{"type": "show"'+floorstr+IdString_0+''+Int_0+'},\n'; +Bool_0 = Bool_0 ?', "async": true':''; +var code = '{"type": "show"'+floorstr+IdString_0+''+Int_0+Bool_0+'},\n'; return code; */; hide_s - : '隐藏事件' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '动画时间' Int? Newline + : '隐藏事件' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '动画时间' Int? '不等待执行完毕' Bool? Newline /* hide_s tooltip : hide: 将一个启用事件禁用,所有参数均可不填,代表禁用事件自身,xy可用逗号分隔表示多个点 helpUrl : https://h5mota.com/games/template/docs/#/event?id=hide%EF%BC%9A%E5%B0%86%E4%B8%80%E4%B8%AA%E5%90%AF%E7%94%A8%E4%BA%8B%E4%BB%B6%E7%A6%81%E7%94%A8 -default : ["","","",500] +default : ["","","",500,false] colour : this.eventColor var floorstr = ''; if (EvalString_0 && EvalString_1) { @@ -529,7 +543,8 @@ if (EvalString_0 && EvalString_1) { } IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); Int_0 = Int_0 ?(', "time": '+Int_0):''; -var code = '{"type": "hide"'+floorstr+IdString_0+''+Int_0+'},\n'; +Bool_0 = Bool_0 ?', "async": true':''; +var code = '{"type": "hide"'+floorstr+IdString_0+''+Int_0+Bool_0+'},\n'; return code; */; @@ -819,6 +834,7 @@ var code = '{"type": "sleep", "time": '+Int_0+'},\n'; return code; */; + battle_s : '强制战斗' IdString Newline @@ -949,18 +965,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 +1475,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 @@ -1644,8 +1674,8 @@ Global_Attribute_List /*Global_Attribute_List ['font','statusLeftBackground','statusTopBackground', 'toolsBackground', 'borderColor', 'statusBarColor', 'hardLabelColor', 'floorChangingBackground', 'floorChangingTextColor']*/; Global_Value_List - : '血网伤害'|'中毒伤害'|'衰弱效果'|'红宝石效果'|'蓝宝石效果'|'绿宝石效果'|'红血瓶效果'|'蓝血瓶效果'|'黄血瓶效果'|'绿血瓶效果'|'破甲比例'|'反击比例'|'净化比例'|'仇恨增加值'|'最大合法HP'|'动画时间' - /*Global_Value_List ['lavaDamage','poisonDamage','weakValue', 'redJewel', 'blueJewel', 'greenJewel', 'redPotion', 'bluePotion', 'yellowPotion', 'greenPotion', 'breakArmor', 'counterAttack', 'purify', 'hatred', 'maxValidHp', 'animateSpeed']*/; + : '血网伤害'|'中毒伤害'|'衰弱效果'|'红宝石效果'|'蓝宝石效果'|'绿宝石效果'|'红血瓶效果'|'蓝血瓶效果'|'黄血瓶效果'|'绿血瓶效果'|'破甲比例'|'反击比例'|'净化比例'|'仇恨增加值'|'行走速度'|'动画时间' + /*Global_Value_List ['lavaDamage','poisonDamage','weakValue', 'redJewel', 'blueJewel', 'greenJewel', 'redPotion', 'bluePotion', 'yellowPotion', 'greenPotion', 'breakArmor', 'counterAttack', 'purify', 'hatred', 'moveSpeed', 'animateSpeed']*/; Bool: 'TRUE' | 'FALSE' @@ -1901,7 +1931,7 @@ ActionParser.prototype.parseAction = function() { y_str.push(t[1]); }) this.next = MotaActionBlocks['show_s'].xmlText([ - x_str.join(','),y_str.join(','),data.floorId||'',data.time||0,this.next]); + x_str.join(','),y_str.join(','),data.floorId||'',data.time||0,data.async||false,this.next]); break; case "hide": // 消失 data.loc=data.loc||[]; @@ -1913,7 +1943,7 @@ ActionParser.prototype.parseAction = function() { y_str.push(t[1]); }) this.next = MotaActionBlocks['hide_s'].xmlText([ - x_str.join(','),y_str.join(','),data.floorId||'',data.time||0,this.next]); + x_str.join(','),y_str.join(','),data.floorId||'',data.time||0,data.async||false,this.next]); break; case "setBlock": // 设置图块 data.loc=data.loc||['','']; @@ -2023,8 +2053,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 +2251,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/comment.js b/_server/comment.js index 2cdc9364..2b7fcc33 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -330,6 +330,12 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_event": "firstArrive", "_data": "第一次到该楼层触发的事件,可以双击进入事件编辑器。" }, + "eachArrive": { + "_leaf": true, + "_type": "event", + "_event": "eachArrive", + "_data": "每次到该楼层触发的事件,可以双击进入事件编辑器;该事件会比firstArrive先执行。" + }, "parallelDo": { "_leaf": true, "_type": "textarea", diff --git a/_server/data.comment.js b/_server/data.comment.js index 681abdf8..300a5fc0 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -276,6 +276,13 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = } } }, + "startCanvas": { + "_leaf": true, + "_type": "event", + "_event": "firstArrive", + "_range": "thiseval==null || thiseval instanceof Array", + "_data": "标题界面事件化,可以使用事件流的形式来绘制开始界面等。\n需要开启startUsingCanvas这个开关。\n详见文档-个性化-标题界面事件化。" + }, "startText": { "_leaf": true, "_type": "event", @@ -373,11 +380,10 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_type": "textarea", "_data": "仇恨属性中,每杀死一个怪物获得的仇恨值" }, - "maxValidHp": { + "moveSpeed": { "_leaf": true, "_type": "textarea", - "_range": "thiseval==null||thiseval>0", - "_data": "最大合法生命值;如果此项不为null且用户通关血量超过本值,则视为作弊,不上传成绩" + "_data": "行走速度,即勇士每走一格的时间,一般100比较合适" }, "animateSpeed": { "_leaf": true, @@ -560,6 +566,12 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "是否循环计算临界;如果此项为true则使用循环法(而不是回合数计算法)来算临界" }, + "startUsingCanvas": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "是否开始菜单canvas化;如果此项为true,则将使用canvas来绘制开始菜单" + }, "startDirectly": { "_leaf": true, "_type": "checkbox", diff --git a/_server/editor.js b/_server/editor.js index 7b418d1d..3da2558c 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -11,6 +11,7 @@ function editor() { if (string.indexOf(substring) > -1){ message = 'Script Error: See Browser Console for Detail'; } else { + if (url) url = url.substring(url.lastIndexOf('/')+1); message = [ 'Message: ' + msg, 'URL: ' + url, @@ -183,6 +184,7 @@ editor.prototype.mapInit = function () { editor.currentFloorData.fgmap = editor.fgmap; editor.currentFloorData.bgmap = editor.bgmap; editor.currentFloorData.firstArrive = []; + editor.currentFloorData.eachArrive = []; editor.currentFloorData.events = {}; editor.currentFloorData.changeFloor = {}; editor.currentFloorData.afterBattle = {}; diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index f36cb09e..c16c0a12 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -52,6 +52,7 @@ editor_blockly = function () { MotaActionBlocks['afterGetItem_m'].xmlText(), MotaActionBlocks['afterOpenDoor_m'].xmlText(), MotaActionBlocks['firstArrive_m'].xmlText(), + MotaActionBlocks['eachArrive_m'].xmlText(), MotaActionBlocks['level_m'].xmlText(), ], '显示文字':[ @@ -131,7 +132,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(), @@ -420,7 +422,7 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ var type = args.type; if (!type) return false; editor_blockly.id = id_; - codeAreaHL.setValue(input.value.replace(/\\r/g,'\\\\r')); + codeAreaHL.setValue(input.value.replace(/\\r/g,'\\\\r').replace(/\\f/,'\\\\f')); document.getElementById('entryType').value = type; editor_blockly.parse(); editor_blockly.show(); diff --git a/_server/editor_file.js b/_server/editor_file.js index 68d9c8ec..3e938917 100644 --- a/_server/editor_file.js +++ b/_server/editor_file.js @@ -156,6 +156,7 @@ editor_file = function (editor, callback) { color: saveStatus?currData.color:null, weather: saveStatus?currData.weather:null, firstArrive: [], + eachArrive: [], parallelDo: "", events: {}, changeFloor: {}, diff --git a/docs/element.md b/docs/element.md index fc633a07..254f8ad9 100644 --- a/docs/element.md +++ b/docs/element.md @@ -313,6 +313,7 @@ floorId指定的是目标楼层的唯一标识符(ID)。 - 使用`\b[...]`来制作对话框效果,如`\b[up,3,2]`。 - 使用`\r[...]`来动态修改局部文本的颜色,如`\r[red]`。 - 使用`${}`来计算一个表达式的值,如`${status:atk+status:def}`。 +- 使用`\f[...]`来同时插入一张立绘图,如`\f[1.png,100,200]`。 从V2.5.2开始,也允许绘制一张头像图在对话框中,只要通过`\t[1.png]`或`\t[标题,1.png]`的写法。 diff --git a/docs/event.md b/docs/event.md index 041d9547..7720332f 100644 --- a/docs/event.md +++ b/docs/event.md @@ -228,7 +228,7 @@ 除此以外,我们还能实现“对话框效果”,只要有`\b[...]`就可以。 - `\b[up]` 直接显示在当前点上方。同样把这里的up换成down则为下方。 - - 如果不存在当前点(如在firstArrive中调用),则显示在屏幕最上方(最下方) + - 如果不存在当前点(如在firstArrive或eachArrive中调用),则显示在屏幕最上方(最下方) - `\b[up,hero]` 显示在勇士上方。同样把这里的up换成down则为下方。 - `\b[up,x,y]` 显示在(x,y)点的上方(下方);x和y都为整数且在0到12之间。 @@ -253,6 +253,20 @@ ] ``` +从V2.5.3以后,也可以使用`\f[...]`来同时绘制一张图片。 + +其基本写法是`\f[图片名,起始x像素,起始y像素]`,或者`\f[图片名,起始x像素,起始y像素,绘制宽度,绘制高度]`。 + +需要注意的是,这个图片是绘制在UI层上的,下一个事件执行时即会擦除;同时如果使用了\t的图标动画效果,重叠的地方也会被图标动画给覆盖掉。 + +``` js +"x,y": [ // 实际执行的事件列表 + "\t[勇士]\b[up,hero]\f[1.png,100,100]以(100,100)为左上角绘制1.png图片", + "\t[hero]\f[1.png,100,100]\f[2.png,300,300]同时绘制了两张图片", + "\f[1.png,100,100,300,300]也可以填写宽高,这样会把图片强制进行放缩到指定的宽高值" +] +``` + 另外值得一提的是,我们是可以在文字中计算一个表达式的值的。只需要将表达式用 `${ }`整个括起来就可以。 ``` js @@ -441,7 +455,7 @@ value为必填项,代表要修改到的结果。此项无需再手动加单引 name必填项,代表要修改的全局数值,其和全塔属性中的values一一对应。目前只能为`"lavaDamage", "poisonDamage", "weakValue", "redJewel", "blueJewel", "greenJewel", "redPotion", "bluePotion", "yellowPotion", "greenPotion", "breakArmor", "counterAttack", -"purify", "hatred", "maxValidHp", "animateSpeed"`。 +"purify", "hatred", "moveSpeed", "animateSpeed"`。 value为必填项,代表要修改到的结果。该项必须是个数值。 @@ -456,7 +470,8 @@ value为必填项,代表要修改到的结果。该项必须是个数值。 {"type": "show", "loc": [3,6], "floorId": "MT1", "time": 500}, // 启用MT1层[3,6]位置事件,动画500ms {"type": "show", "loc": [3,6], "time": 500}, // 如果启用目标是当前层,则可以省略floorId项 {"type": "show", "loc": [3,6]}, // 如果不指定动画时间,则立刻显示,否则动画效果逐渐显示,time为动画时间 - {"type": "show", "loc": [[3,6],[2,9],[1,2]], "time": 500} // 我们也可以同时动画显示多个点。 + {"type": "show", "loc": [[3,6],[2,9],[1,2]], "time": 500}, // 我们也可以同时动画显示多个点。 + {"type": "show", "loc": [3,6], "time": 500, "async": true} // 可以使用异步动画效果 ] ``` @@ -468,13 +483,15 @@ floorId为目标点的楼层,如果不是该楼层的事件(比如4楼小偷 time为动画效果时间,如果指定了某个大于0的数,则会以动画效果慢慢从无到有显示,动画时间为该数值;如果不指定该选项则无动画直接立刻显示。 +async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 + !> **要注意的是,调用show事件后只是让该事件从禁用状态变成启用,从不可见不可交互变成可见可交互,但本身不会去执行该点的事件。** ### hide:将一个启用事件禁用 `{"type":"hide"}`和show刚好相反,它会让一个已经启用的事件被禁用。 -其参数和show也完全相同,loc指定事件的位置,floorId为楼层(同层可忽略),time指定的话事件会以动画效果从有到无慢慢消失。 +其参数和show也完全相同,loc指定事件的位置,floorId为楼层(同层可忽略),time指定的话事件会以动画效果从有到无慢慢消失,async代表是否是异步效果。 loc同样可以简单的写[x,y]表示单个点,或二维数组[[x1,y1],[x2,y2],...]表示多个点。 @@ -492,7 +509,7 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}` {"type": "hide", "loc": [[3,6],[2,9],[1,2]], "time": 500}, // 也可以同时指定多个点消失 {"type": "hide", "time": 500}, // 如果不指定loc选项则默认为当前点, 例如这个就是500ms消失当前对话的NPC {"type": "hide"}, // 无动画将当前事件禁用,常常适用于某个空地点(触发陷阱事件、触发机关门这种) - + {"type": "hide", "loc": [3,6], "time": 500, "async": true} // 可以使用异步动画效果 ] ``` @@ -807,8 +824,6 @@ time为可选的,指定的话将作为楼层切换动画的时间。 **如果time指定为小于100,则视为没有楼层切换动画。** -!> **changeFloor到达一个新的楼层,将不会执行firstArrive事件!如有需求请在到达点设置自定义事件,然后使用type: trigger立刻调用之。** - ### changePos:当前位置切换/勇士转向 有时候我们不想要楼层切换的动画效果,而是直接让勇士从A点到B点。 @@ -863,9 +878,9 @@ name为可选的,是要取消跟随的行走图文件名。 如果name省略,则会取消所有的跟随效果。 -### viberate:画面震动 +### vibrate:画面震动 -使用 `{"type": "viberate", "time": 2000, "async": true}` 可以造成画面震动效果。 +使用 `{"type": "vibrate", "time": 2000, "async": true}` 可以造成画面震动效果。 time可以指定震动时间,默认是2000毫秒。 @@ -1548,6 +1563,19 @@ choices为一个数组,其中每一项都是一个选项列表。 ``` +### waitAsync:等待所有异步事件执行完毕 + +上面有很多很多的异步事件(也就是执行时不等待执行完毕)。 + +由于录像是加速播放,且会跳过`{"type":"sleep"}`(等待X毫秒)事件;因此异步行为很有可能导致录像播放出错。 + +例如,异步移动一个NPC去某格,然后等待X毫秒,再勇士走过去对话; +但是录像播放中,等待X毫秒的行为会被跳过,因此勇士可能走过去时异步还未执行完成,导致录像出错。 + +我们可以使用`{"type":"waitAsync"}`来等待所有异步事件执行完毕。 + +该事件会进行等待,直到所有可能的异步事件(异步动画除外)执行完毕。 + ### function: 自定义JS脚本 上述给出了这么多事件,但有时候往往不能满足需求,这时候就需要执行自定义脚本了。 @@ -2113,7 +2141,7 @@ if (core.getFlag("door",0)==2) { core.stopReplay(); core.waitHeroToStop(function() { core.removeGlobalAnimate(0,0,true); - core.clearMap('all'); // 清空全地图 + core.clearMap('all'); core.clearMap('curtain'); // 清空全地图 core.drawText([ "\t[恭喜通关]你的分数是${status:hp}。" ], function () { diff --git a/docs/personalization.md b/docs/personalization.md index e8b6f810..153ee029 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -17,10 +17,10 @@ HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们 - fg:前景层;绘制前景图层素材fgmap,和前景贴图 - damage:显伤层;主要用来绘制怪物显伤和领域显伤 - animate:动画层;主要用来绘制动画。showImage事件绘制的图片也是在这一层。 -- image:图片层;主要用来绘制显示图片 - weather:天气层;主要用来绘制天气(雨/雪) - route:路线层;主要用来绘制勇士的行走路线图,也用来绘制图块的淡入/淡出效果,图块的移动等。 - curtain:色调层;用来控制当前楼层的画面色调 +- image:图片层;主要用来绘制显示图片;该层之所以在curtain层上是为了可以在全黑时贴大头像图 - ui:UI层;用来绘制一切UI窗口,如剧情文本、怪物手册、楼传器、系统菜单等等 - data:数据层;用来绘制一些顶层的或更新比较快的数据,如左上角的提示,战斗界面中数据的变化等等。 @@ -51,7 +51,7 @@ HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们 在地图编辑器中绘图时,下拉框选中“背景层”或“前景层”即可在对应的图层上绘图。 -其中背景层和前景层仅为静态绘图(不支持动画),但可以使用自动元件(autotile)。 +其中背景层和前景层可以使用任何素材,以及使用自动元件(autotile)。 可以使用`showBgFgMap`, `hideBgFgMap`, `setBgFgBlock`等事件对背景和前景图层进行操作。 @@ -560,6 +560,39 @@ this.myfunc = function(x) { 通过这种,将脚本和自定义事件混用的方式,可以达到和RM中公共事件类似的效果,即一个调用触发一系列事件。 --> + +## 标题界面事件化 + +从V2.5.3开始,我们可以将标题界面的绘制和游戏开始用事件来完成。可以通过绘制画布、 + +全塔属性,flags中的startUsingCanvas可以决定是否开启标题界面事件化。 + +然后就可以使用“事件流”的形式来绘制标题界面、提供选项等等。 + +在这里可以调用任意事件。例如,可以贴若干个图,可以事件切换楼层到某个剧情层再执行若干事件,等等。 + +关于选项,样板默认给出的是最简单的choices事件;你也可以使用贴按钮图,循环处理+等待操作来定制自己的按钮点击效果。 + +!> 开始游戏、读取存档、录像回放的效果已经默认给出,请不要修改或删减这些内容,以免出现问题。 + +标题界面事件全部处理完后,将再继续执行startText事件。 + +## 手机端按键模式 + +从V2.5.3以后,我们可以给手机端增加按键了,这样将非常有利于技能的释放。 + +当用户在竖屏模式下点击工具栏,就会在工具栏按钮和快捷键模式之间进行切换。 + +切换到快捷键模式后,可以点1-7,分别等价于在电脑端按键1-7。 + +可以在脚本编辑的onKeyUp中定义每个快捷键的使用效果,比如使用道具或释放技能等。 + +默认值下,1使用破,2使用炸,3使用飞,4使用其他存在的道具,5-7未定义。可以相应修改成自己的效果。 + +也可以替换icons.png中的对应图标,以及修改main.js中`main.statusBar.image.btn1~7`中的onclick事件来自定义按钮和对应按键。 + +非竖屏模式下、回放录像中、隐藏状态栏中,将不允许进行切换。 + ## 自定义状态栏(新增显示项) 在V2.2以后,我们可以自定义状态栏背景图(全塔属性 - statusLeftBackground)等等。 @@ -577,7 +610,7 @@ this.myfunc = function(x) { ``` 3. 在editor.html中的statusBar(323行起),仿照第二点同样添加;这一项如果不进行则会地图编辑器报错。editor-mobile.html同理。 -4. 使用便捷PS工具,打开icons.png,新增一行并将魔力的图标P上去;记下其索引比如30(从0开始数)。 +4. 使用便捷PS工具,打开icons.png,新增一行并将魔力的图标P上去;记下其索引比如37(从0开始数)。 5. 在main.js的this.statusBar中增加图片、图标和内容的定义。 ``` js this.statusBar = { diff --git a/editor-mobile.html b/editor-mobile.html index 9141fe2d..89b98714 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -174,6 +174,7 @@ + @@ -412,6 +413,13 @@ + + + + + + +

diff --git a/editor.html b/editor.html index 41e3e25c..b5f76989 100644 --- a/editor.html +++ b/editor.html @@ -173,6 +173,7 @@ + @@ -398,6 +399,13 @@ + + + + + + +

diff --git a/index.html b/index.html index 2a05eb95..4e65f98a 100644 --- a/index.html +++ b/index.html @@ -118,6 +118,13 @@ + + + + + + +

diff --git a/libs/actions.js b/libs/actions.js index 6439e095..5b8a3ede 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -166,6 +166,9 @@ actions.prototype.keyDown = function(keyCode) { if (core.status.event.id=='replay') { this.keyDownReplay(keyCode); } + if (core.status.event.id=='gameInfo') { + this.keyDownGameInfo(keyCode); + } return; } if(!core.status.played) { @@ -280,6 +283,10 @@ actions.prototype.keyUp = function(keyCode, altKey) { this.keyUpReplay(keyCode); return; } + if (core.status.event.id=='gameInfo') { + this.keyUpGameInfo(keyCode); + return; + } if (core.status.event.id=='centerFly') { this.keyUpCenterFly(keyCode); return; @@ -590,6 +597,10 @@ actions.prototype.onclick = function (x, y, stepPostfix) { return; } + if (core.status.event.id=='gameInfo') { + this.clickGameInfo(x,y); + } + } ////// 滑动鼠标滚轮时的操作 ////// @@ -991,7 +1002,6 @@ actions.prototype.clickViewMaps = function (x,y) { } else if (x>=2 && x<=10 && y>=5 && y<=7) { core.clearMap('data'); - core.setOpacity('data', 1); core.ui.closePanel(); } } @@ -1020,7 +1030,6 @@ actions.prototype.keyUpViewMaps = function (keycode) { if (keycode==27 || keycode==13 || keycode==32 || (!core.status.replay.replaying && keycode==67)) { core.clearMap('data'); - core.setOpacity('data', 1); core.ui.closePanel(); return; } @@ -1903,25 +1912,10 @@ actions.prototype.clickSettings = function (x,y) { core.ui.drawSyncSave(); break; case 5: - core.ui.drawStatistics(); + core.status.event.selection=0; + core.ui.drawGameInfo(); break; case 6: - if (core.platform.isPC) { - window.open("/score.php?name="+core.firstData.name+"&num=10", "_blank"); - } - else { - if (confirm("即将离开本塔,跳转至本塔评论页面,确认?")) { - window.location.href = "/score.php?name="+core.firstData.name+"&num=10"; - } - } - break; - case 7: - core.ui.drawHelp(); - break; - case 8: - core.ui.drawAbout(); - break; - case 9: core.status.event.selection=1; core.ui.drawConfirmBox("你确定要返回标题页面吗?", function () { core.ui.closePanel(); @@ -1931,7 +1925,7 @@ actions.prototype.clickSettings = function (x,y) { core.ui.drawSettings(); }); break; - case 10: + case 7: core.ui.closePanel(); break; } @@ -2057,7 +2051,7 @@ actions.prototype.clickSyncSave = function (x,y) { core.ui.drawStorageRemove(); break; case 7: - core.status.event.selection=3; + core.status.event.selection=4; core.ui.drawSettings(); break; @@ -2291,7 +2285,7 @@ actions.prototype.clickStorageRemove = function (x, y) { } break; case 2: - core.status.event.selection=5; + core.status.event.selection=6; core.ui.drawSyncSave(); break; } @@ -2414,6 +2408,77 @@ actions.prototype.keyUpReplay = function (keycode) { } } + +////// 游戏信息界面时的点击操作 ////// +actions.prototype.clickGameInfo = function (x, y) { + if (x<5 || x>7) return; + var choices = core.status.event.ui.choices; + + var topIndex = 6 - parseInt((choices.length - 1) / 2); + + if (y>=topIndex && y=49 && keycode<=57) { + var index = keycode-49; + if (index=1 && x<=11) { diff --git a/libs/control.js b/libs/control.js index c1f03d4b..56bdff04 100644 --- a/libs/control.js +++ b/libs/control.js @@ -70,7 +70,7 @@ control.prototype.setRequestAnimationFrame = function () { } // Global Animate - if (core.animateFrame.globalAnimate && core.isPlaying()) { + if (core.animateFrame.globalAnimate && core.isPlaying() && core.isset(core.status.floorId)) { if (timestamp-core.animateFrame.globalTime>core.animateFrame.speed && core.isset(core.status.globalAnimateObjs)) { @@ -81,9 +81,21 @@ control.prototype.setRequestAnimationFrame = function () { } if ((core.status.autotileAnimateObjs.blocks||[]).length>0) { + var groundId = (core.status.maps||core.floors)[core.status.floorId].defaultGround || "ground"; + var blockIcon = core.material.icons.terrains[groundId]; core.status.autotileAnimateObjs.status++; core.status.autotileAnimateObjs.blocks.forEach(function (block) { - core.drawAutotile(core.canvas.event, core.status.autotileAnimateObjs.map, block, 32, 0, 0, core.status.autotileAnimateObjs.status); + var cv = core.isset(block.name)?core.canvas[block.name]:core.canvas.event; + cv.clearRect(block.x * 32, block.y * 32, 32, 32); + if (core.isset(block.name)) { + if (block.name == 'bg') { + core.canvas.bg.drawImage(core.material.images.terrains, 0, blockIcon * 32, 32, 32, block.x * 32, block.y * 32, 32, 32); + } + core.drawAutotile(cv, core.status.autotileAnimateObjs[block.name+"map"], block, 32, 0, 0, core.status.autotileAnimateObjs.status); + } + else { + core.drawAutotile(cv, core.status.autotileAnimateObjs.map, block, 32, 0, 0, core.status.autotileAnimateObjs.status); + } }) } @@ -221,6 +233,15 @@ control.prototype.showStartAnimate = function (noAnimate, callback) { core.status.played = false; core.clearStatus(); core.clearMap('all'); + core.clearMap('curtain'); + + if (core.flags.startUsingCanvas) { + core.dom.startTop.style.display = 'none'; + core.dom.startButtonGroup.style.display = 'block'; + core.events.startGame(''); + if (core.isset(callback)) callback(); + return; + } if(noAnimate) { core.dom.startTop.style.display = 'none'; @@ -444,7 +465,7 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { core.control.tryMoveDirectly(destX, destY); } core.status.automaticRoute.moveDirectly = false; - }, 100); + }, core.values.moveSpeed || 100); } return; } @@ -693,7 +714,7 @@ control.prototype.setHeroMoveInterval = function (direction, x, y, callback) { core.status.heroMoving = 0; if (core.isset(callback)) callback(); } - }, 12.5 * toAdd / core.status.replay.speed); + }, (core.values.moveSpeed||100) / 8 * toAdd / core.status.replay.speed); } ////// 实际每一步的行走过程 ////// @@ -836,7 +857,7 @@ control.prototype.moveHero = function (direction, callback) { /////// 使用事件让勇士移动。这个函数将不会触发任何事件 ////// control.prototype.eventMoveHero = function(steps, time, callback) { - time = time || 100; + time = time || core.values.moveSpeed || 100; // 要运行的轨迹:将steps展开 var moveSteps=[]; @@ -867,6 +888,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 +911,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 +968,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 +978,7 @@ control.prototype.jumpHero = function (ex, ey, time, callback) { }, time / 16 / core.status.replay.speed); - - + core.animateFrame.asyncId[animate] = true; } ////// 每移动一格后执行的事件 ////// @@ -1025,7 +1049,7 @@ control.prototype.updateViewport = function() { ////// 绘制勇士 ////// control.prototype.drawHero = function (direction, x, y, status, offset) { - if (!core.isPlaying() || core.status.isStarting) return; + if (!core.isPlaying()) return; var scan = { 'up': {'x': 0, 'y': -1}, @@ -1492,26 +1516,26 @@ 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; } ////// 更新全地图显伤 ////// control.prototype.updateDamage = function (floorId, canvas) { - - if (!core.isset(floorId)) floorId = core.status.floorId; + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; if (!core.isset(canvas)) { canvas = core.canvas.damage; core.clearMap('damage'); } - // 正在开始游戏中 - if (core.status.isStarting) return; - // 更新显伤 var mapBlocks = core.status.maps[floorId].blocks; // 没有怪物手册 @@ -1655,15 +1679,21 @@ control.prototype.chooseReplayFile = function () { } if (core.isset(obj.version) && obj.version!=core.firstData.version) { // alert("游戏版本不一致!"); - if (!confirm("游戏版本不一致!\n你仍然想播放录像吗?")) + if (!confirm("游戏版本不一致!\n你仍然想播放录像吗?")) { return; + } } - if (!core.isset(obj.route) || !core.isset(obj.hard)) { + if (!core.isset(obj.route)) { alert("无效的录像!"); return; } - core.startGame(obj.hard, obj.seed, core.decodeRoute(obj.route)); + if (core.flags.startUsingCanvas) { + core.startGame('', obj.seed, core.decodeRoute(obj.route)); + } + else { + core.startGame(obj.hard, obj.seed, core.decodeRoute(obj.route)); + } }, function () { }) @@ -2672,6 +2702,16 @@ control.prototype.playSound = function (sound) { } } +control.prototype.checkBgm = function() { + if (core.musicStatus.startDirectly && core.musicStatus.bgmStatus) { + if (core.musicStatus.playingBgm==null + || core.material.bgms[core.musicStatus.playingBgm].paused) { + core.musicStatus.playingBgm=null; + core.playBgm(core.bgms[0]); + } + } +} + ////// 清空状态栏 ////// control.prototype.clearStatusBar = function() { @@ -2738,7 +2778,8 @@ control.prototype.triggerStatusBar = function (name) { if (name!='hide') name='show'; var statusItems = core.dom.status; var toolItems = core.dom.tools; - if (name == 'hide') { + core.domStyle.showStatusBar = name == 'show'; + if (!core.domStyle.showStatusBar) { for (var i = 0; i < statusItems.length; ++i) statusItems[i].style.opacity = 0; for (var i = 0; i < toolItems.length; ++i) @@ -2747,10 +2788,8 @@ control.prototype.triggerStatusBar = function (name) { else { for (var i = 0; i < statusItems.length; ++i) statusItems[i].style.opacity = 1; - for (var i = 0; i < toolItems.length; ++i) - toolItems[i].style.display = 'block'; - if (core.domStyle.screenMode != 'vertical') - core.statusBar.image.shop.style.display = 'none'; + this.setToolbarButton(false); + core.dom.tools.hard.style.display = 'block'; } } @@ -2832,6 +2871,33 @@ control.prototype.updateGlobalAttribute = function (name) { } } +////// 改变工具栏为按钮1-7 ////// +control.prototype.setToolbarButton = function (useButton) { + if (!core.domStyle.showStatusBar) return; + + if (!core.isset(useButton)) useButton = core.domStyle.toolbarBtn; + if (core.domStyle.screenMode != 'vertical') useButton = false; + + core.domStyle.toolbarBtn = useButton; + if (useButton) { + ["book","fly","toolbox","shop","save","load","settings"].forEach(function (t) { + core.statusBar.image[t].style.display = 'none'; + }); + ["btn1","btn2","btn3","btn4","btn5","btn6","btn7"].forEach(function (t) { + core.statusBar.image[t].style.display = 'block'; + }) + } + else { + ["btn1","btn2","btn3","btn4","btn5","btn6","btn7"].forEach(function (t) { + core.statusBar.image[t].style.display = 'none'; + }); + ["book","fly","toolbox","shop","save","load","settings"].forEach(function (t) { + core.statusBar.image[t].style.display = 'block'; + }); + core.statusBar.image.shop.style.display = core.domStyle.screenMode != 'vertical' ? "none":"block"; + } +} + ////// 屏幕分辨率改变后重新自适应 ////// control.prototype.resize = function(clientWidth, clientHeight) { if (main.mode=='editor')return; @@ -2894,6 +2960,8 @@ control.prototype.resize = function(clientWidth, clientHeight) { var zoom = (ADAPT_WIDTH - width) / 4.22; var aScale = 1 - zoom / 100; + core.domStyle.toolbarBtn = false; + // 移动端 if (width < CHANGE_WIDTH) { if(width < ADAPT_WIDTH){ @@ -3132,7 +3200,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { { imgId: 'shop', rules:{ - display: shopDisplay + display: shopDisplay && core.domStyle.showStatusBar } }, { @@ -3222,6 +3290,7 @@ control.prototype.resize = function(clientWidth, clientHeight) { }, ] core.domRenderer(); + this.setToolbarButton(); } ////// 渲染DOM ////// diff --git a/libs/core.js b/libs/core.js index f14206fe..f6cfe375 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 @@ -73,6 +74,8 @@ function core() { this.domStyle = { styles: [], scale: 1.0, + toolbarBtn: false, + showStatusBar: true, } this.bigmap = { canvas: ["bg", "event", "event2", "fg", "damage", "route"], @@ -176,7 +179,7 @@ function core() { // 动画 'globalAnimateObjs': [], 'boxAnimateObjs': [], - 'autotileAnimateObjs': {}, + 'autotileAnimateObjs': {"status": 0, "blocks": [], "map": null, "bgmap": null, "fgmap": null}, 'animateObjs': [], }; this.status = {}; diff --git a/libs/events.js b/libs/events.js index a02099bd..a1a3184a 100644 --- a/libs/events.js +++ b/libs/events.js @@ -91,14 +91,15 @@ events.prototype.initGame = function () { ////// 游戏开始事件 ////// events.prototype.startGame = function (hard, seed, route, callback) { - if (core.status.isStarting) return; - core.status.isStarting = true; + main.dom.levelChooseButtons.style.display='none'; + main.dom.startButtonGroup.style.display='none'; var start = function () { console.log('开始游戏'); - core.resetStatus(core.firstData.hero, hard, core.firstData.floorId, null, core.initStatus.maps); - - core.status.isStarting = true; + core.resetStatus(core.firstData.hero, hard, null, null, core.initStatus.maps); + var nowLoc = core.clone(core.getHeroLoc()); + core.setHeroLoc('x', -1); + core.setHeroLoc('y', -1); if (core.isset(seed)) { core.setFlag('__seed__', seed); @@ -106,15 +107,15 @@ events.prototype.startGame = function (hard, seed, route, callback) { } else core.utils.__init_seed(); - core.events.setInitData(hard); core.clearMap('all'); + core.clearMap('curtain'); core.clearStatusBar(); var post_start = function () { - core.status.isStarting = false; + core.control.triggerStatusBar('show'); - core.changeFloor(core.status.floorId, null, core.status.hero.loc, null, function() { + core.changeFloor(core.firstData.floorId, null, nowLoc, null, function() { if (core.isset(callback)) callback(); }, true); @@ -125,7 +126,7 @@ events.prototype.startGame = function (hard, seed, route, callback) { formData.append('name', core.firstData.name); formData.append('version', core.firstData.version); formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); - formData.append('hard', core.encodeBase64(hard)); + formData.append('hard', core.encodeBase64(core.status.hard)); formData.append('hardCode', core.getFlag('hard', 0)); formData.append('base64', 1); @@ -133,23 +134,36 @@ events.prototype.startGame = function (hard, seed, route, callback) { }) } - core.insertAction(core.clone(core.firstData.startText), null, null, function() { - if (!core.status.replay.replaying && core.flags.showBattleAnimateConfirm) { // 是否提供“开启战斗动画”的选择项 - core.status.event.selection = core.flags.battleAnimate ? 0 : 1; - core.ui.drawConfirmBox("你想开启战斗动画吗?\n之后可以在菜单栏中开启或关闭。\n(强烈建议新手开启此项)", function () { - core.flags.battleAnimate = true; - core.setLocalStorage('battleAnimate', true); + var real_start = function () { + core.insertAction(core.clone(core.firstData.startText), null, null, function() { + if (!core.flags.startUsingCanvas && !core.status.replay.replaying && core.flags.showBattleAnimateConfirm) { // 是否提供“开启战斗动画”的选择项 + core.status.event.selection = core.flags.battleAnimate ? 0 : 1; + core.ui.drawConfirmBox("你想开启战斗动画吗?\n之后可以在菜单栏中开启或关闭。\n(强烈建议新手开启此项)", function () { + core.flags.battleAnimate = true; + core.setLocalStorage('battleAnimate', true); + post_start(); + }, function () { + core.flags.battleAnimate = false; + core.setLocalStorage('battleAnimate', false); + post_start(); + }); + } + else { post_start(); - }, function () { - core.flags.battleAnimate = false; - core.setLocalStorage('battleAnimate', false); - post_start(); - }); - } - else { - post_start(); - } - }); + } + }); + } + + if (core.flags.startUsingCanvas) { + core.control.triggerStatusBar('hide'); + core.insertAction(core.clone(core.firstData.startCanvas), null, null, function() { + real_start(); + }); + } + else { + core.events.setInitData(hard); + real_start(); + } if (core.isset(route)) { core.startReplay(route); @@ -157,6 +171,12 @@ events.prototype.startGame = function (hard, seed, route, callback) { } + if (core.flags.startUsingCanvas) { + core.dom.startPanel.style.display = 'none'; + start(); + return; + } + if (core.isset(route)) { core.dom.startPanel.style.display = 'none'; start(); @@ -290,12 +310,7 @@ events.prototype.gameOver = function (ending, fromReplay, norank) { } else { - if (core.isset(core.values.maxValidHp) && core.status.hero.hp>core.values.maxValidHp) { - core.drawText("作弊可耻!", function () { - core.restart(); - }); - } - else if (core.hasFlag('debug')) { + if (core.hasFlag('debug')) { core.drawText("\t[系统提示]调试模式下无法上传成绩", function () { core.restart(); }) @@ -438,12 +453,15 @@ events.prototype.doAction = function() { && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) data.loc = [[core.calValue(data.loc[0]), core.calValue(data.loc[1])]]; if (core.isset(data.time) && data.time>0 && (!core.isset(data.floorId) || data.floorId==core.status.floorId)) { - core.animateBlock(data.loc,'show', data.time, function () { - data.loc.forEach(function (t) { - core.showBlock(t[0],t[1],data.floorId); - }) - core.events.doAction(); - }); + if (data.async) { + core.animateBlock(data.loc, 'show', data.time); + this.doAction(); + } + else { + core.animateBlock(data.loc,'show', data.time, function () { + core.events.doAction(); + }); + } } else { data.loc.forEach(function (t) { @@ -461,13 +479,16 @@ events.prototype.doAction = function() { if (core.isset(data.time) && data.time>0 && (!core.isset(data.floorId) || data.floorId==core.status.floorId)) { data.loc.forEach(function (t) { core.hideBlock(t[0],t[1],data.floorId); - }) - core.animateBlock(data.loc,'hide',data.time, function () { - data.loc.forEach(function (t) { - core.removeBlock(t[0],t[1],data.floorId) - }) - core.events.doAction(); }); + if (data.async) { + core.animateBlock(data.loc, 'hide', data.time); + this.doAction(); + } + else { + core.animateBlock(data.loc,'hide', data.time, function () { + core.events.doAction(); + }); + } } else { data.loc.forEach(function (t) { @@ -1059,7 +1080,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 +1123,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); // 重新获得事件 @@ -1312,6 +1343,7 @@ events.prototype.trigger = function (x, y) { events.prototype.setFloorName = function (floorId) { floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; // 根据文字判断是否斜体 var floorName = core.status.maps[floorId].name || ""; if (typeof floorName == 'number') floorName = ""+floorName; @@ -1336,7 +1368,11 @@ events.prototype.setFloorName = function (floorId) { ////// 楼层切换 ////// events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback, fromLoad) { - if (!core.isset(floorId)) floorId = core.status.floorId; + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) { + if (core.isset(callback)) callback(); + return; + } if (floorId == ':before') { var index=core.floorIds.indexOf(core.status.floorId); @@ -1495,33 +1531,40 @@ events.prototype.animateImage = function (type, image, loc, time, keep, callback } clearInterval(core.interval.tipAnimate); - core.setAlpha('data', 1); - var opacityVal = 0; - if (type == 'hide') opacityVal = 1; + var alpha = 0; + if (type == 'hide') alpha = 1; + + var x = core.calValue(loc[0]), y = core.calValue(loc[1]); if (type == 'hide' && keep) { - core.clearMap('image'); + core.clearMap('image', x, y, image.width, image.height); } - - core.setOpacity('data', opacityVal); - var x = core.calValue(loc[0]), y = core.calValue(loc[1]); + core.setAlpha('data', alpha); core.canvas.data.drawImage(image, x, y); + core.setAlpha('data', 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) { + if (type=='show') alpha += 0.1; + else alpha -= 0.1; + core.clearMap('data', x, y, image.width, image.height); + if (alpha >=1 || alpha<=0) { + delete core.animateFrame.asyncId[animate]; clearInterval(animate); if (type == 'show' && keep) core.canvas.image.drawImage(image, x, y); - core.clearMap('data'); - core.setOpacity('data', 1); - // core.status.replay.animate=false; + core.setAlpha('data', 1); if (core.isset(callback)) callback(); } + else { + core.setAlpha('data', alpha); + core.canvas.data.drawImage(image, x, y); + core.setAlpha('data', 1); + } }, time / 10); + + core.animateFrame.asyncId[animate] = true; } ////// 移动图片 ////// @@ -1529,7 +1572,6 @@ events.prototype.moveImage = function (image, from, to, time, keep, callback) { time = time || 1000; clearInterval(core.interval.tipAnimate); core.setAlpha('data', 1); - core.setOpacity('data', 1); var width = image.width, height = image.height; @@ -1554,13 +1596,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 +1630,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 +1696,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..2c9c5f83 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -211,6 +211,7 @@ maps.prototype.save = function(maps, floorId) { ////// 更改地图画布的尺寸 maps.prototype.resizeMap = function(floorId) { floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; core.bigmap.width = core.floors[floorId].width || 13; core.bigmap.height = core.floors[floorId].height || 13; var cwidth = core.bigmap.width * 32; @@ -229,7 +230,7 @@ maps.prototype.resizeMap = function(floorId) { ////// 将存档中的地图信息重新读取出来 ////// maps.prototype.load = function (data, floorId) { - if (floorId == undefined) { + if (!core.isset(floorId)) { var map = {}; core.floorIds.forEach(function (id) { map[id] = core.maps.loadFloor(id, data[id]); @@ -266,7 +267,8 @@ maps.prototype.canMoveHero = function(x,y,direction,floorId) { if (!core.isset(x)) x=core.getHeroLoc('x'); if (!core.isset(y)) y=core.getHeroLoc('y'); if (!core.isset(direction)) direction=core.getHeroLoc('direction'); - if (!core.isset(floorId)) floorId=core.status.floorId; + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return false; // 检查当前块的cannotMove if (core.isset(core.floors[floorId].cannotMove)) { @@ -384,6 +386,17 @@ maps.prototype.drawBlock = function (block, animate, dx, dy) { dx = dx || 0; dy = dy || 0; + if (core.isset(block.name)) { + core.canvas[block.name].clearRect(block.x * 32, block.y * 32, 32, 32); + if (block.name == 'bg') { + var groundId = (core.status.maps||core.floors)[core.status.floorId].defaultGround || "ground"; + var blockIcon = core.material.icons.terrains[groundId]; + core.canvas.bg.drawImage(core.material.images.terrains, 0, blockIcon * 32, 32, 32, block.x * 32, block.y * 32, 32, 32); + } + core.canvas[block.name].drawImage(image, x * 32, y * 32, 32, 32, block.x * 32, block.y * 32, 32, 32); + return; + } + core.canvas.event.clearRect(block.x * 32 + dx, block.y * 32 + dy, 32, 32); core.canvas.event.drawImage(image, x * 32, y * height + height-32, 32, 32, block.x * 32 + dx, block.y * 32 + dy, 32, 32); if (height>32) { @@ -394,6 +407,7 @@ maps.prototype.drawBlock = function (block, animate, dx, dy) { maps.prototype.getBgFgMapArray = function (floorId, name) { floorId = floorId||core.status.floorId; + if (!core.isset(floorId)) return []; var width = core.floors[floorId].width || 13; var height = core.floors[floorId].height || 13; @@ -415,8 +429,9 @@ maps.prototype.getBgFgMapArray = function (floorId, name) { } ////// 背景/前景图块的绘制 ////// -maps.prototype.drawBgFgMap = function (floorId, canvas, name) { +maps.prototype.drawBgFgMap = function (floorId, canvas, name, animate) { floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; var width = core.floors[floorId].width || 13; var height = core.floors[floorId].height || 13; @@ -428,10 +443,15 @@ maps.prototype.drawBgFgMap = function (floorId, canvas, name) { for (var y = 0; y < height; y++) { if (arr[y][x]>0) { var block = core.maps.initBlock(x, y, arr[y][x]); + this.addInfo(block); + block.name = name; if (core.isset(block.event)) { var id = block.event.id, cls = block.event.cls; - if (cls == 'autotile') + if (cls == 'autotile') { core.drawAutotile(canvas, arr, block, 32, 0, 0); + if (animate) + core.status.autotileAnimateObjs.blocks.push(core.clone(block)); + } else if (cls == 'tileset') { var offset = core.icons.getTilesetOffset(id); if (offset!=null) { @@ -443,18 +463,30 @@ maps.prototype.drawBgFgMap = function (floorId, canvas, name) { canvas.drawImage(core.material.images.airwall, 32*x, 32*y); } } - else - canvas.drawImage(core.material.images[cls], 0, core.material.icons[cls][id] * 32, 32, 32, x * 32, y * 32, 32, 32); + else { + if (animate) { + this.drawBlock(block); + this.addGlobalAnimate(block); + } + else { + canvas.drawImage(core.material.images[cls], 0, core.material.icons[cls][id] * 32, 32, 32, x * 32, y * 32, 32, 32); + } + } } } } } - + core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); } ////// 绘制某张地图 ////// maps.prototype.drawMap = function (mapName, callback) { mapName = mapName || core.status.floorId; + if (!core.isset(mapName)) { + if (core.isset(callback)) + callback(); + return; + } core.clearMap('all'); core.removeGlobalAnimate(null, null, true); @@ -511,8 +543,8 @@ maps.prototype.drawMap = function (mapName, callback) { } }); - core.maps.drawBgFgMap(mapName, core.canvas.bg, "bg"); - core.maps.drawBgFgMap(mapName, core.canvas.fg, "fg"); + core.maps.drawBgFgMap(mapName, core.canvas.bg, "bg", true); + core.maps.drawBgFgMap(mapName, core.canvas.fg, "fg", true); } if (main.mode=='editor'){ @@ -531,7 +563,6 @@ maps.prototype.drawMap = function (mapName, callback) { core.status.floorId = mapName; core.status.thisMap = core.status.maps[mapName]; var drawEvent = function(){ - core.status.autotileAnimateObjs = {"status": 0, "blocks": [], "map": null}; var mapData = core.status.maps[core.status.floorId]; var mapBlocks = mapData.blocks; @@ -707,7 +738,8 @@ maps.prototype.enemyExists = function (x, y, id,floorId) { ////// 获得某个点的block ////// maps.prototype.getBlock = function (x, y, floorId, showDisable) { - if (!core.isset(floorId)) floorId=core.status.floorId; + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return null; var blocks = core.status.maps[floorId].blocks; for (var n=0;n=1 || opacityVal<=0) { + if (type=='show') alpha += 0.1; + else alpha -= 0.1; + clear(); + if (alpha >=1 || alpha<=0) { + delete core.animateFrame.asyncId[animate]; clearInterval(animate); - core.clearMap('route'); - core.setOpacity('route', 1); - // core.status.replay.animate=false; + core.setAlpha('route', 1); + if (type == 'show') { + loc.forEach(function (t) { + core.showBlock(t[0],t[1],data.floorId); + }); + } + else { + loc.forEach(function (t) { + core.removeBlock(t[0],t[1],data.floorId); + }); + } if (core.isset(callback)) callback(); } + else { + core.setAlpha('route', alpha); + draw(); + } }, time / 10 / core.status.replay.speed); + + core.animateFrame.asyncId[animate] = true; } ////// 将某个块从禁用变成启用状态 ////// -maps.prototype.showBlock = function(x, y, floodId) { - floodId = floodId || core.status.floorId; - var block = core.getBlock(x,y,floodId,true); +maps.prototype.showBlock = function(x, y, floorId) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + var block = core.getBlock(x,y,floorId,true); if (block==null) return; // 不存在 block=block.block; // 本身是禁用事件,启用之 if (block.disable) { block.disable = false; // 在本层,添加动画 - if (floodId == core.status.floorId && core.isset(block.event)) { + if (floorId == core.status.floorId && core.isset(block.event)) { core.drawBlock(block); core.addGlobalAnimate(block); core.syncGlobalAnimate(); @@ -1085,6 +1143,7 @@ maps.prototype.showBlock = function(x, y, floodId) { ////// 只隐藏但不删除某块 ////// maps.prototype.hideBlock = function (x, y, floorId) { floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; var block = core.getBlock(x,y,floorId,true); if (block==null) return; // 不存在 @@ -1106,6 +1165,7 @@ maps.prototype.hideBlock = function (x, y, floorId) { ////// 将某个块从启用变成禁用状态 ////// maps.prototype.removeBlock = function (x, y, floorId) { floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; var block = core.getBlock(x,y,floorId,true); if (block==null) return; // 不存在 @@ -1129,6 +1189,8 @@ maps.prototype.removeBlock = function (x, y, floorId) { ////// 根据block的索引删除该块 ////// maps.prototype.removeBlockById = function (index, floorId) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; var blocks = core.status.maps[floorId].blocks, block = blocks[index]; var x=block.x, y=block.y; @@ -1154,6 +1216,8 @@ maps.prototype.removeBlockById = function (index, floorId) { ////// 一次性删除多个block ////// maps.prototype.removeBlockByIds = function (floorId, ids) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; ids.sort(function (a,b) {return b-a}).forEach(function (id) { core.removeBlockById(id, floorId); }); @@ -1162,6 +1226,7 @@ maps.prototype.removeBlockByIds = function (floorId, ids) { ////// 改变图块 ////// maps.prototype.setBlock = function (number, x, y, floorId) { floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; if (x<0 || x>=core.bigmap.width || y<0 || y>=core.bigmap.height) return; @@ -1187,6 +1252,7 @@ maps.prototype.setBlock = function (number, x, y, floorId) { ////// 改变图层块 ////// maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) { floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; if (x<0 || x>=core.bigmap.width || y<0 || y>=core.bigmap.height) return; if (name!='bg' && name!='fg') return; @@ -1207,24 +1273,23 @@ maps.prototype.addGlobalAnimate = function (b) { block.status = 0; core.status.globalAnimateObjs.push(block); - } ////// 删除一个或所有全局动画 ////// -maps.prototype.removeGlobalAnimate = function (x, y, all) { +maps.prototype.removeGlobalAnimate = function (x, y, all, name) { if (main.mode=='editor' && main.editor.disableGlobalAnimate) return; if (all) { core.status.globalAnimateObjs = []; - core.status.autotileAnimateObjs = {}; + core.status.autotileAnimateObjs = {"status": 0, "blocks": [], "map": null, "bgmap": null, "fgmap": null}; return; } - core.status.globalAnimateObjs = core.status.globalAnimateObjs.filter(function (block) {return block.x!=x || block.y!=y;}); + core.status.globalAnimateObjs = core.status.globalAnimateObjs.filter(function (block) {return block.x!=x || block.y!=y || block.name!=name;}); // 检查Autotile if (core.isset(core.status.autotileAnimateObjs.blocks)) { - core.status.autotileAnimateObjs.blocks = core.status.autotileAnimateObjs.blocks.filter(function (block) {return block.x!=x || block.y!=y;}); + core.status.autotileAnimateObjs.blocks = core.status.autotileAnimateObjs.blocks.filter(function (block) {return block.x!=x || block.y!=y || block.name!=name;}); core.status.autotileAnimateObjs.map[y][x] = 0; } @@ -1286,6 +1351,7 @@ maps.prototype.drawAnimateFrame = function (animate, centerX, centerY, index) { core.canvas.animate.drawImage(image, -realWidth/2 - core.bigmap.offsetX, -realHeight/2 - core.bigmap.offsetY, realWidth, realHeight); core.loadCanvas('animate'); } + core.setAlpha('animate', 1); }) } @@ -1338,7 +1404,8 @@ maps.prototype.setFloorImage = function (type, loc, floorId, callback) { if (type!='show') type='hide'; if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; - floorId = floorId||core.status.floorId; + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; if (loc.length==0) return; loc.forEach(function (t) { @@ -1360,7 +1427,8 @@ maps.prototype.setBgFgMap = function (type, name, loc, floorId, callback) { if (name!='fg') name='bg'; if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; - floorId = floorId||core.status.floorId; + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; if (loc.length==0) return; loc.forEach(function (t) { @@ -1379,7 +1447,8 @@ maps.prototype.setBgFgMap = function (type, name, loc, floorId, callback) { } maps.prototype.resetMap = function(floorId) { - var floorId = floorId||core.status.floorId; + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; core.status.maps[floorId] = this.loadFloor(floorId); if (floorId==core.status.floorId) { this.drawMap(floorId, function () { diff --git a/libs/ui.js b/libs/ui.js index 948e9912..635d0221 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -144,7 +144,7 @@ ui.prototype.setAlpha = function (map, alpha) { else core.canvas[map].globalAlpha = alpha; } -////// 设置某个canvas的透明度 ////// +////// 设置某个canvas的透明度;尽量不要使用本函数,而是全部换成setAlpha实现 ////// ui.prototype.setOpacity = function (map, opacity) { if (map == 'all') { for (var m in core.canvas) { @@ -186,10 +186,9 @@ ui.prototype.closePanel = function () { ////// 左上角绘制一段提示 ////// ui.prototype.drawTip = function (text, itemIcon) { - var textX, textY, width, height, hide = false, opacityVal = 0; + var textX, textY, width, height, hide = false, alpha = 0; clearInterval(core.interval.tipAnimate); core.setFont('data', "16px Arial"); - core.setOpacity('data', 0); core.canvas.data.textAlign = 'left'; if (!core.isset(itemIcon)) { textX = 16; @@ -205,22 +204,22 @@ ui.prototype.drawTip = function (text, itemIcon) { } core.interval.tipAnimate = window.setInterval(function () { if (hide) { - opacityVal -= 0.1; + alpha -= 0.1; } else { - opacityVal += 0.1; + alpha += 0.1; } - core.setOpacity('data', opacityVal); - core.clearMap('data', 5, 5, 400, height); + core.clearMap('data', 5, 5, 416, height); + core.setAlpha('data', alpha); core.fillRect('data', 5, 5, width, height, '#000'); if (core.isset(itemIcon)) { core.canvas.data.drawImage(core.material.images.items, 0, itemIcon * 32, 32, 32, 10, 8, 32, 32); } core.fillText('data', text, textX + 5, textY + 15, '#fff'); - if (opacityVal > 0.6 || opacityVal < 0) { + core.setAlpha('data', 1); + if (alpha > 0.6 || alpha < 0) { if (hide) { - core.clearMap('data', 5, 5, 400, height); - core.setOpacity('data', 1); + core.clearMap('data', 5, 5, 416, height); clearInterval(core.interval.tipAnimate); return; } @@ -231,8 +230,7 @@ ui.prototype.drawTip = function (text, itemIcon) { core.timeout.getItemTipTimeout = null; }, 750); } - opacityVal = 0.6; - core.setOpacity('data', opacityVal); + alpha = 0.6; } } }, 30); @@ -500,6 +498,20 @@ ui.prototype.drawTextBox = function(content, showAll) { core.status.boxAnimateObjs = []; core.clearMap('ui'); + // drawImage + content = content.replace(/(\f|\\f)\[(.*?)]/g, function (text, sympol, str) { + var ss = str.split(","); + if (ss.length!=3 && ss.length!=5) return ""; + var img = core.material.images.images[ss[0]]; + if (!core.isset(img)) return ""; + // 绘制 + if (ss.length==3) + core.canvas.ui.drawImage(img, parseFloat(ss[1]), parseFloat(ss[2])); + else + core.canvas.ui.drawImage(img, 0, 0, img.width, img.height, parseFloat(ss[1]), parseFloat(ss[2]), parseFloat(ss[3]), parseFloat(ss[4])); + return ""; + }); + var globalFont = core.status.globalAttribute.font; var font = textfont + 'px '+globalFont; if (textAttribute.bold) font = "bold "+font; @@ -519,9 +531,13 @@ ui.prototype.drawTextBox = function(content, showAll) { width = validWidth + leftSpace + rightSpace; // left必须在7~416-7-width区间内,以保证left>=7,right<=416-7 left = core.clamp(32*px+16-width/2, 7, 416-7-width); + + left -= core.bigmap.offsetX; + right = left + width; } + var content_left = left + leftSpace; var height = 30 + (textfont+5)*core.splitLines("ui", realContent, validWidth, font).length; if (core.isset(name)) height += titlefont + 5; @@ -541,20 +557,24 @@ ui.prototype.drawTextBox = function(content, showAll) { else if (position=='up') { if (px==null || py==null) top = 5 + offset; - else + else { top = 32 * py - height - ydelta - yoffset; + top -= core.bigmap.offsetY; + } } else if (position=='down') { if (px==null || py==null) top = 416 - height - 5 - offset; - else + else { top = 32 * py + 32 + yoffset; + top -= core.bigmap.offsetY; + } } var bottom = top + height; if (isWindowSkin) { core.setAlpha('ui', alpha); - this.drawWindowSkin(background,'ui',left,top,width,height,position,px==null?null:px*32,py==null?null:py*32); + this.drawWindowSkin(background,'ui',left,top,width,height,position,px==null?null:px*32-core.bigmap.offsetX,py==null?null:py*32-core.bigmap.offsetY); core.setAlpha('ui', 1); } else { @@ -569,17 +589,17 @@ ui.prototype.drawTextBox = function(content, showAll) { canvas.moveTo(left,top); // 上边缘 if (position=='down' && core.isset(px) && core.isset(py)) { - canvas.lineTo(32*px+xoffset, top); - canvas.lineTo(32*px+16, top-yoffset); - canvas.lineTo(32*(px+1)-xoffset, top); + canvas.lineTo(32*px+xoffset - core.bigmap.offsetX, top); + canvas.lineTo(32*px+16 - core.bigmap.offsetX, top-yoffset); + canvas.lineTo(32*(px+1)-xoffset - core.bigmap.offsetX, top); } canvas.lineTo(right, top); canvas.lineTo(right, bottom); // 下边缘 if (position=='up' && core.isset(px) && core.isset(py)) { - canvas.lineTo(32*(px+1)-xoffset, bottom); - canvas.lineTo(32*px+16, bottom+yoffset); - canvas.lineTo(32*px+xoffset, bottom); + canvas.lineTo(32*(px+1)-xoffset - core.bigmap.offsetX, bottom); + canvas.lineTo(32*px+16 - core.bigmap.offsetX, bottom+yoffset); + canvas.lineTo(32*px+xoffset - core.bigmap.offsetX, bottom); } canvas.lineTo(left, bottom); canvas.closePath(); @@ -911,7 +931,7 @@ ui.prototype.drawSettings = function () { core.status.event.id = 'settings'; this.drawChoices(null, [ - "系统设置", "虚拟键盘", "浏览地图", "绘图模式", "同步存档", "数据统计", "查看评论", "操作帮助", "关于本塔", "返回标题", "返回游戏" + "系统设置", "虚拟键盘", "浏览地图", "绘图模式", "同步存档", "游戏信息", "返回标题", "返回游戏" ]); } @@ -1010,16 +1030,13 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) { var top = (416-height)/2, bottom = height; - // 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.fillRect('ui', left, top, right, bottom, 'rgba(0,0,0,0.85)'); core.setAlpha('ui', 1); core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2); core.clearMap('data'); clearInterval(core.interval.tipAnimate); core.setAlpha('data', 1); - core.setOpacity('data', 1); core.status.boxAnimateObjs = []; var globalFont = core.status.globalAttribute.font; @@ -1307,6 +1324,13 @@ ui.prototype.drawReplay = function () { ]); } +ui.prototype.drawGameInfo = function () { + core.status.event.id = 'gameInfo'; + this.drawChoices(null, [ + "数据统计", "查看评论", "操作帮助", "关于本塔", "返回上级菜单" + ]); +} + ////// 绘制分页 ////// ui.prototype.drawPagination = function (page, totalPage, top) { // if (totalPage13 || mh>13)) text+=" ["+(x-6)+","+(y-6)+"]"; var textX = 16, textY = 18, width = textX + core.canvas.data.measureText(text).width + 16, height = 42; - core.fillRect('data', 5, 5, width, height, '#000'); - core.setOpacity('data', 0.4); - core.fillText('data', text, textX + 5, textY + 15, '#fff'); - + core.fillRect('data', 5, 5, width, height, 'rgba(0,0,0,0.4)'); + core.fillText('data', text, textX + 5, textY + 15, 'rgba(255,255,255,0.6)'); } ////// 绘制道具栏 ////// @@ -2574,7 +2591,6 @@ ui.prototype.drawPaint = function () { core.clearMap('route'); core.setAlpha('route', 1); - core.setOpacity('route', 1); // 将已有的内容绘制到route上 var value = core.paint[core.status.floorId]; diff --git a/main.js b/main.js index 9285f889..2ff39470 100644 --- a/main.js +++ b/main.js @@ -98,7 +98,14 @@ function main() { 'shop': document.getElementById("img-shop"), 'save': document.getElementById("img-save"), 'load': document.getElementById("img-load"), - 'settings': document.getElementById("img-settings") + 'settings': document.getElementById("img-settings"), + 'btn1': document.getElementById("img-btn1"), + 'btn2': document.getElementById("img-btn2"), + 'btn3': document.getElementById("img-btn3"), + 'btn4': document.getElementById("img-btn4"), + 'btn5': document.getElementById("img-btn5"), + 'btn6': document.getElementById("img-btn6"), + 'btn7': document.getElementById("img-btn7") }, 'icons': { 'floor': 0, @@ -132,6 +139,13 @@ function main() { 'erase': 27, 'empty': 28, 'exit': 29, + 'btn1': 30, + 'btn2': 31, + 'btn3': 32, + 'btn4': 33, + 'btn5': 34, + 'btn6': 35, + 'btn7': 36 }, 'floor': document.getElementById('floor'), 'name': document.getElementById('name'), @@ -386,7 +400,9 @@ main.dom.data.ontouchend = function (e) { } ////// 点击状态栏中的怪物手册时 ////// -main.statusBar.image.book.onclick = function () { +main.statusBar.image.book.onclick = function (e) { + e.stopPropagation(); + if (core.isset(core.status.replay) && core.status.replay.replaying) { core.triggerReplay(); return; @@ -402,7 +418,8 @@ main.statusBar.image.book.onclick = function () { } ////// 点击状态栏中的楼层传送器/装备栏时 ////// -main.statusBar.image.fly.onclick = function () { +main.statusBar.image.fly.onclick = function (e) { + e.stopPropagation(); // 播放录像时 if (core.isset(core.status.replay) && core.status.replay.replaying) { @@ -427,7 +444,8 @@ main.statusBar.image.fly.onclick = function () { } ////// 点击状态栏中的工具箱时 ////// -main.statusBar.image.toolbox.onclick = function () { +main.statusBar.image.toolbox.onclick = function (e) { + e.stopPropagation(); if (core.isset(core.status.replay) && core.status.replay.replaying) { core.rewindReplay(); @@ -445,7 +463,8 @@ main.statusBar.image.toolbox.onclick = function () { } ////// 双击状态栏中的工具箱时 ////// -main.statusBar.image.toolbox.ondblclick = function () { +main.statusBar.image.toolbox.ondblclick = function (e) { + e.stopPropagation(); if (core.isset(core.status.replay) && core.status.replay.replaying) { core.rewindReplay(); @@ -458,7 +477,8 @@ main.statusBar.image.toolbox.ondblclick = function () { } ////// 点击状态栏中的快捷商店时 ////// -main.statusBar.image.shop.onclick = function () { +main.statusBar.image.shop.onclick = function (e) { + e.stopPropagation(); if (core.isset(core.status.replay) && core.status.replay.replaying) { core.bookReplay(); @@ -470,7 +490,8 @@ main.statusBar.image.shop.onclick = function () { } ////// 点击状态栏中的存档按钮时 ////// -main.statusBar.image.save.onclick = function () { +main.statusBar.image.save.onclick = function (e) { + e.stopPropagation(); if (core.isset(core.status.replay) && core.status.replay.replaying) { core.speedDownReplay(); @@ -487,7 +508,8 @@ main.statusBar.image.save.onclick = function () { } ////// 点击状态栏中的读档按钮时 ////// -main.statusBar.image.load.onclick = function () { +main.statusBar.image.load.onclick = function (e) { + e.stopPropagation(); if (core.isset(core.status.replay) && core.status.replay.replaying) { core.speedUpReplay(); @@ -504,7 +526,8 @@ main.statusBar.image.load.onclick = function () { } ////// 点击状态栏中的系统菜单时 ////// -main.statusBar.image.settings.onclick = function () { +main.statusBar.image.settings.onclick = function (e) { + e.stopPropagation(); if (core.isset(core.status.replay) && core.status.replay.replaying) { core.saveReplay(); @@ -520,18 +543,53 @@ main.statusBar.image.settings.onclick = function () { main.core.openSettings(true); } +////// 点击工具栏时 ////// +main.dom.toolBar.onclick = function () { + if (core.isset(core.status.replay) && core.status.replay.replaying) + return; + main.core.control.setToolbarButton(!core.domStyle.toolbarBtn); +} + +////// 手机端的按钮1-7 ////// +main.statusBar.image.btn1.onclick = function (e) { + e.stopPropagation(); + main.core.onkeyUp({"keyCode": 49}); +}; + +main.statusBar.image.btn2.onclick = function (e) { + e.stopPropagation(); + main.core.onkeyUp({"keyCode": 50}); +}; + +main.statusBar.image.btn3.onclick = function (e) { + e.stopPropagation(); + main.core.onkeyUp({"keyCode": 51}); +}; + +main.statusBar.image.btn4.onclick = function (e) { + e.stopPropagation(); + main.core.onkeyUp({"keyCode": 52}); +}; + +main.statusBar.image.btn5.onclick = function (e) { + e.stopPropagation(); + main.core.onkeyUp({"keyCode": 53}); +}; + +main.statusBar.image.btn6.onclick = function (e) { + e.stopPropagation(); + main.core.onkeyUp({"keyCode": 54}); +}; + +main.statusBar.image.btn7.onclick = function (e) { + e.stopPropagation(); + main.core.onkeyUp({"keyCode": 55}); +}; + ////// 点击“开始游戏”时 ////// main.dom.playGame.onclick = function () { main.dom.startButtons.style.display='none'; - - if (main.core.isset(main.core.musicStatus) && main.core.musicStatus.startDirectly - && main.core.musicStatus.bgmStatus) { - if (main.core.musicStatus.playingBgm==null - || core.material.bgms[main.core.musicStatus.playingBgm].paused) { - main.core.musicStatus.playingBgm=null; - main.core.playBgm(main.core.bgms[0]); - } - } + main.core.control.checkBgm(); if (main.core.isset(main.core.flags.startDirectly) && main.core.flags.startDirectly) { core.events.startGame(""); @@ -543,32 +601,14 @@ main.dom.playGame.onclick = function () { ////// 点击“载入游戏”时 ////// main.dom.loadGame.onclick = function() { - - if (main.core.isset(main.core.musicStatus) && main.core.musicStatus.startDirectly - && main.core.musicStatus.bgmStatus) { - if (main.core.musicStatus.playingBgm==null - || core.material.bgms[main.core.musicStatus.playingBgm].paused) { - main.core.musicStatus.playingBgm=null; - main.core.playBgm(main.core.bgms[0]); - } - } - + main.core.control.checkBgm(); main.core.load(); } ////// 点击“录像回放”时 ////// main.dom.replayGame.onclick = function () { - - if (main.core.isset(main.core.musicStatus) && main.core.musicStatus.startDirectly - && main.core.musicStatus.bgmStatus) { - if (main.core.musicStatus.playingBgm==null - || core.material.bgms[main.core.musicStatus.playingBgm].paused) { - main.core.musicStatus.playingBgm=null; - main.core.playBgm(main.core.bgms[0]); - } - } - - core.chooseReplayFile(); + main.core.control.checkBgm(); + main.core.chooseReplayFile(); } diff --git a/project/data.js b/project/data.js index d2697561..9b4ac12e 100644 --- a/project/data.js +++ b/project/data.js @@ -1,4 +1,4 @@ -var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = +var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = { "main": { "floorIds": [ @@ -103,6 +103,126 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "flags": {}, "steps": 0 }, + "startCanvas": [ + { + "type": "comment", + "text": "在这里可以用事件来自定义绘制标题界面的背景图等" + }, + { + "type": "showImage", + "name": "bg.jpg", + "loc": [ + 0, + 0 + ] + }, + { + "type": "comment", + "text": "给用户提供选择项,这里简单的使用了choices事件" + }, + { + "type": "comment", + "text": "也可以贴按钮图然后使用循环处理+等待操作来完成" + }, + { + "type": "choices", + "choices": [ + { + "text": "开始游戏", + "action": [ + { + "type": "comment", + "text": "检查bgm状态,下同" + }, + { + "type": "function", + "function": "function(){\ncore.control.checkBgm()\n}" + }, + { + "type": "if", + "condition": "core.flags.startDirectly", + "true": [ + { + "type": "comment", + "text": "直接开始游戏,设置初始化数据" + }, + { + "type": "function", + "function": "function(){\ncore.events.setInitData('')\n}" + } + ], + "false": [ + { + "type": "comment", + "text": "动态生成难度选择项" + }, + { + "type": "function", + "function": "function(){\nvar choices = [];\nmain.levelChoose.forEach(function (one) {\n\tchoices.push({\"text\": one[0], \"action\": [\n\t\t{\"type\": \"function\", \"function\": \"function() { core.status.hard = '\"+one[1]+\"'; core.events.setInitData('\"+one[1]+\"'); }\"}\n\t]});\n})\ncore.insertAction({\"type\": \"choices\", \"choices\": choices});\n}" + } + ] + }, + { + "type": "showImage" + }, + { + "type": "comment", + "text": "成功选择难度" + } + ] + }, + { + "text": "读取存档", + "action": [ + { + "type": "function", + "function": "function(){\ncore.control.checkBgm()\n}" + }, + { + "type": "showImage" + }, + { + "type": "comment", + "text": "这段代码会结束事件,打开读档页面,读取存档或重新开始" + }, + { + "type": "function", + "function": "function(){\ncore.insertAction([{\"type\": \"exit\"}], null, null, function() {\n\tcore.status.played = false;\n\tcore.load();\n})\n}" + }, + { + "type": "comment", + "text": "不管读档有没有成功,都会重新开始,这个地方不会被执行到" + } + ] + }, + { + "text": "回放录像", + "action": [ + { + "type": "function", + "function": "function(){\ncore.control.checkBgm()\n}" + }, + { + "type": "comment", + "text": "这段代码会结束事件,选择录像文件,播放录像或重新开始" + }, + { + "type": "function", + "function": "function(){\ncore.insertAction([{\"type\": \"exit\"}], null, null, function() {\n\tcore.restart();\n\tcore.chooseReplayFile();\n})\n}" + }, + { + "type": "comment", + "text": "不管录像有没有成功,都会重新开始,这个地方不会被执行到" + } + ] + } + ] + }, + { + "type": "comment", + "text": "接下来会执行startText中的事件" + } + ], "startText": [ "Hi,欢迎来到 HTML5 魔塔样板!\n\n本样板由艾之葵制作,可以让你在不会写任何代码\n的情况下也能做出属于自己的H5魔塔!", "这里游戏开始时的剧情。\n定义在data.js的startText处。\n\n你可以在这里写上自己的内容。", @@ -217,7 +337,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "counterAttack": 0.1, "purify": 3, "hatred": 2, - "maxValidHp": null, + "moveSpeed": 100, "animateSpeed": 300 }, "flags": { @@ -248,6 +368,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "hatredDecrease": true, "betweenAttackCeil": false, "useLoop": false, + "startUsingCanvas": false, "startDirectly": false, "canOpenBattleAnimate": true, "showBattleAnimateConfirm": false, diff --git a/project/functions.js b/project/functions.js index c6ee7084..ef3be11d 100644 --- a/project/functions.js +++ b/project/functions.js @@ -1,4 +1,4 @@ -var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = +var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { "events": { "initGame": function() { @@ -59,7 +59,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.stopReplay(); core.waitHeroToStop(function() { core.removeGlobalAnimate(0,0,true); - core.clearMap('all'); // 清空全地图 + core.clearMap('all'); core.clearMap('curtain'); // 清空全地图 // 请注意: // 成绩统计时是按照hp进行上传并排名,因此光在这里改${status:hp}是无效的 // 如需按照其他的的分数统计方式,请先将hp设置为你的得分 @@ -93,6 +93,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = visited.push(floorId); core.setFlag("__visited__", visited); } + // 每次抵达楼层时执行的事件 + if (!fromLoad) { + core.insertAction(core.floors[floorId].eachArrive); + } }, "addPoint": function (enemy) { // 加点事件 diff --git a/project/images/icons.png b/project/images/icons.png index 75301f33..c5a383c6 100644 Binary files a/project/images/icons.png and b/project/images/icons.png differ diff --git a/常用工具/地图生成器.exe b/常用工具/地图生成器.exe index 98510404..a17d95e4 100644 Binary files a/常用工具/地图生成器.exe and b/常用工具/地图生成器.exe differ