diff --git a/_server/data.comment.js b/_server/data.comment.js index 681abdf8..c3262c4d 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", @@ -560,6 +567,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/docs/event.md b/docs/event.md index 686891a6..0b376eb2 100644 --- a/docs/event.md +++ b/docs/event.md @@ -2124,7 +2124,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 ded9701f..5a957c5b 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:数据层;用来绘制一些顶层的或更新比较快的数据,如左上角的提示,战斗界面中数据的变化等等。 @@ -560,6 +560,23 @@ this.myfunc = function(x) { 通过这种,将脚本和自定义事件混用的方式,可以达到和RM中公共事件类似的效果,即一个调用触发一系列事件。 --> + +## 标题界面事件化 + +从V2.5.3开始,我们可以将标题界面的绘制和游戏开始用事件来完成。可以通过绘制画布、 + +全塔属性,flags中的startUsingCanvas可以决定是否开启标题界面事件化。 + +然后就可以使用“事件流”的形式来绘制标题界面、提供选项等等。 + +在这里可以调用任意事件。例如,可以贴若干个图,可以事件切换楼层到某个剧情层再执行若干事件,等等。 + +关于选项,样板默认给出的是最简单的choices事件;你也可以使用贴按钮图,循环处理+等待操作来定制自己的按钮点击效果。 + +!> 开始游戏、读取存档、录像回放的效果已经默认给出,请不要修改或删减这些内容,以免出现问题。 + +标题界面事件全部处理完后,将再继续执行startText事件。 + ## 自定义状态栏(新增显示项) 在V2.2以后,我们可以自定义状态栏背景图(全塔属性 - statusLeftBackground)等等。 diff --git a/libs/control.js b/libs/control.js index f8a49d01..72758e6d 100644 --- a/libs/control.js +++ b/libs/control.js @@ -233,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'; @@ -1040,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}, @@ -1520,16 +1529,13 @@ control.prototype.setFg = function(color, time, callback) { ////// 更新全地图显伤 ////// 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; // 没有怪物手册 @@ -1673,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 () { }) @@ -2690,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() { diff --git a/libs/events.js b/libs/events.js index 091ab206..30d82948 100644 --- a/libs/events.js +++ b/libs/events.js @@ -91,14 +91,12 @@ events.prototype.initGame = function () { ////// 游戏开始事件 ////// events.prototype.startGame = function (hard, seed, route, callback) { - if (core.status.isStarting) return; - core.status.isStarting = true; - 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 +104,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 +123,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 +131,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 +168,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(); @@ -1322,6 +1339,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; @@ -1346,7 +1364,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); diff --git a/libs/maps.js b/libs/maps.js index dca3c6b4..3c1d91d8 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)) { @@ -405,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; @@ -428,6 +431,7 @@ maps.prototype.getBgFgMapArray = function (floorId, 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; @@ -478,6 +482,11 @@ maps.prototype.drawBgFgMap = function (floorId, canvas, name, animate) { ////// 绘制某张地图 ////// 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); @@ -729,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=core.bigmap.width || y<0 || y>=core.bigmap.height) return; @@ -1216,6 +1234,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; @@ -1366,7 +1385,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) { @@ -1388,7 +1408,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) { @@ -1407,7 +1428,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/main.js b/main.js index 9285f889..592e56f7 100644 --- a/main.js +++ b/main.js @@ -523,15 +523,7 @@ main.statusBar.image.settings.onclick = function () { ////// 点击“开始游戏”时 ////// 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 +535,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..107c1140 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你可以在这里写上自己的内容。", @@ -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 350d5a04..ef3be11d 100644 --- a/project/functions.js +++ b/project/functions.js @@ -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设置为你的得分