diff --git a/README.md b/README.md
index 68a5c0d2..db47a83d 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,7 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
│ └─ *.png # 对应的某个具体的图片素材
├── /libs/ # JS源代码目录
│ ├─ /floors/ # 剧本文件,记录了每个地图的数据和事件
+│ ├─ /thirdparty/ # 游戏所用到的第三方库文件
│ ├─ core.js # 系统核心文件
│ ├─ data.js # 记录了勇士的初始化信息、各个全局变量和全局Flag值
│ ├─ enemys.js # 记录了怪物的信息,包括怪物的数据和特殊属性、伤害计算公式、临界值计算等。
@@ -44,9 +45,10 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
## 更新说明
-### 2017.12.31 V1.3
+### 2018.1.1 V1.3
* [x] 支持全键盘操作。
+* [x] 支持将某个图片作为某层的背景素材。
* [x] 便捷PS工具支持更改图片色相。
* [x] 支持经验升级(进阶/境界塔)。
* [x] 打败怪物可以进行加点(加点塔)。
diff --git a/_server/css/editor.css b/_server/css/editor.css
new file mode 100644
index 00000000..02b25b10
--- /dev/null
+++ b/_server/css/editor.css
@@ -0,0 +1,297 @@
+
+html,body,div,img{margin:0;padding:0;}
+body{
+ font-family: Roboto,"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;;
+ background-color: #F5F5F5;
+}
+/* ::-webkit-scrollbar {
+ width: 5px;
+} */
+.main {
+ max-width: 100%;
+ min-height: 500px;
+ margin: 0 auto;
+}
+#left, #mid, #right{
+ border-radius: 2px;
+ box-sizing: border-box;
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
+}
+#left{
+ position: absolute;
+ left: 5px;
+ top: 10px;
+ width: 435px;
+ height: 630px;
+}
+
+#editArea{
+ position: absolute;
+ width: 100%;
+ height: 70%;
+ left: 0;
+ top: 0;
+ /* padding: 10px 5px; */
+ box-sizing: border-box;
+}
+#pout{
+ display: block;
+ width: 410px;
+ height: 100%;
+ box-sizing: border-box;
+ margin-left: 22px;
+ margin-top: 23px;
+ line-height: 20px;
+ font-size: 12.3px;
+ font-family: 'Lucida Console', Monaco, monospace;
+ white-space: pre;
+ border: 1px solid #ddd;
+ border-radius: 2px;
+}
+#editTip{
+ position: absolute;
+ width: 100%;
+ height: 80px;
+ bottom:10px;
+ left: 10px;
+}
+#editArea p{
+ margin: 10px;
+ display: block;
+ width: 70%;
+ line-height: 20px;
+ text-align: left;
+ font-size: 14px;
+}
+#editTip .btn{
+ float: right;
+ margin-right: 20px;
+ margin-top: 5px;
+}
+
+#mid{
+ position: absolute;
+ left: 448px;
+ top: 10px;
+ width: 440px;
+ height: 630px;
+}
+.map {
+ position: absolute;
+ left: 20px;
+ top: 21px;
+ width: 416px;
+ height: 416px;
+}
+#mid .tools{
+ position: absolute;
+ width: 425px;
+ height: 180px;
+ left: 0;
+ bottom: 0;
+ border-top: 1px solid #ccc;
+ padding: 10px 5px;
+ margin-left: 8px;;
+ box-sizing: border-box;
+}
+#tip{
+ float: right;
+ width: 50%;
+ height: 95%;
+ padding: 5px 10px 10px 10px;
+ margin-right: 0;
+ box-sizing: border-box;
+ border: 1px solid #ccc;
+ border-radius: 2px;
+ font-size: 15px;
+ line-height: 14px;
+}
+.files {
+ width: 50%;
+ height: 120px;
+ /* padding: 10px; */
+ margin-top: 15px;
+}
+.input{
+ display: block;
+ max-width: 150px;
+ height: 20px;
+ padding: 6px 12px;
+ font-size: 14px;
+ margin-top: 10px;
+ color: #555;
+ background-color: #fff;
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
+}
+#bgSelect{
+ width: 50%;
+ height: 100px;
+ margin-top: 10px;
+}
+#bgSelect span{
+ /* display: block; */
+ font-size: 14px;
+ line-height: 30px;
+}
+#printOut{
+ margin-top: 10px;
+ height: 20px;
+
+}
+.btn {
+ width: 80px;
+ border-radius: 2px;
+ line-height: 30px;
+ margin: 0;
+ min-width: 50px;
+ padding: 0 5px;
+ display: inline-block;
+ margin-top: 5px;
+ font-size: 14px;
+ font-weight: 400;
+ /* text-transform: uppercase; */
+ letter-spacing: 0;
+ overflow: hidden;
+ cursor: pointer;
+ text-decoration: none;
+ text-align: center;
+ vertical-align: middle;
+ border: 0;
+ background: rgba(158,158,158,.2);
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.14), 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 3px 0 rgba(0,0,0,.12);
+ color: #fff;
+ background-color: #26A69A;
+}
+.btn:hover {
+ background-color: #009688;
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
+}
+#right{
+ position: absolute;
+ left: 900px;
+ top: 10px;
+ width: 440px;
+ height: 630px;
+ /* border: 1px solid rgb(238, 13, 13); */
+}
+#iconLib{
+ position: absolute;
+ width: 435px;
+ height: 620px;
+ left: 5px;
+ top: 5px;
+ overflow: auto;
+}
+.gameCanvas {
+ position: absolute;
+}
+#dataSelection{
+ position: absolute;
+ /* top:0;
+ left:320px; */
+ z-index:75;
+ width:26px;
+ height:26px;
+ margin: 3px 0 0 3px;
+ padding:0;
+ /* display: none; */
+ box-sizing: border-box;
+ background-color:rgba(255, 255, 255, 0.0);
+ border: 1px solid #000;
+ box-shadow: 0 0 0 2px #fff,
+ 0 0 0 3px #000;
+}
+.warnText{
+ color: #D50000;
+ font-weight: 700;
+ font-size: 14px;
+}
+.infoText{
+ color: #2196F3;
+}
+.successText{
+ color: #00897B
+}
+
+table, td {
+ border: 1px solid #fff;
+ color: #fff;
+ cursor:crosshair;
+}
+table.col{
+ position: relative;
+
+ text-align: center;
+ border-collapse: collapse;
+}
+table.col td{
+ background-color: #4DB6AC;
+}
+#arrColMark td{
+ width: 16px;
+}
+#arrColMark {
+ top: 2px;
+ left: 36px;
+ width: 385px;
+ height: 16px;
+ font-size: 13px;
+}
+#mapColMark {
+ top: 2px;
+ left: 19px;
+ width: 418px;
+ height: 16px;
+ font-size: 13px;
+}
+#mapColMark td{
+ width: 29px;
+}
+#mapColMark td:hover .colBlock{
+ position: absolute;
+ top: 19px;
+ height: 416px;
+ width: 32px;
+ z-index: 100;
+ background-color: rgba(38,166,154,.5);
+}
+table.row{
+ position: relative;
+ text-align: right;
+ vertical-align:middle;
+ border-collapse: collapse;
+}
+table.row td{
+ background-color: #4C221B;
+}
+#arrRowMark{
+ top: 5px;
+ left: 2px;
+ width: 16px;
+ height: 262px;
+ font-size: 12px;
+}
+#mapRowMark{
+ top: 1px;
+ left: 2px;
+ width: 16px;
+ height: 416px;
+ font-size: 12px;
+}
+#mapRowMark td{
+ height: 29px;
+}
+#mapRowMark td:hover .rowBlock{
+ position: absolute;
+ left: 18px;
+ height: 32px;
+ width: 416px;
+ z-index: 100;
+ background-color: rgba(76,34,27,.5);
+}
+/* for vue dom */
+[v-cloak] {
+ display: none !important;
+}
diff --git a/_server/vm.js b/_server/vm.js
index e198d040..4c1644bf 100644
--- a/_server/vm.js
+++ b/_server/vm.js
@@ -187,7 +187,7 @@ var tip = new Vue({
isClearBlock: false,
geneMapSuccess: false,
timer: null,
- msgs: [ //分别编号1,2,3,4,5,6,7,8;奇数警告,偶数成功
+ msgs: [ //分别编号1,2,3,4,5,6,7,8,9,10;奇数警告,偶数成功
"当前未选择任何图块,请先在右边选择要画的图块!",
"生成地图成功!可点击复制按钮复制地图数组到剪切板",
"生成失败! 地图中有未定义的图块,建议先用其他有效图块覆盖或点击清除地图!",
@@ -195,7 +195,9 @@ var tip = new Vue({
"复制失败!",
"复制成功!可直接粘贴到楼层文件的地图数组中。",
"复制失败!当前还没有数据",
- "修改成功!可点击复制按钮复制地图数组到剪切板"
+ "修改成功!可点击复制按钮复制地图数组到剪切板",
+ "选择背景图片失败!文件名格式错误或图片不存在!",
+ "更新背景图片成功!",
],
mapMsg: '',
whichShow: 0,
@@ -255,12 +257,31 @@ var bgSelect = new Vue({
el: '#bgSelect',
data: {
bgs: {},
- selectedBg: 'ground'
+ selectedBg: 'ground',
+ imgname: ''
},
watch:{
selectedBg: function(){
editor.bgY = this.bgs.indexOf(this.selectedBg);
editor.drawMapBg();
}
+ },
+ methods: {
+ updatebg: function(){
+ tip.whichShow = 0;
+ var regx = /\S+\.(png|bmp|jpg|jpeg|gif)$/i;
+ if(regx.test(this.imgname)){
+ var url = 'images/'+this.imgname;
+ editor.loadImg(url).then(function(img){
+ editor.drawMapBg(img);
+ tip.whichShow = 10;
+ }).catch(function(err){
+ console.log(err);
+ tip.whichShow = 9;
+ });
+ }else{
+ tip.whichShow = 9;
+ }
+ }
}
})
\ No newline at end of file
diff --git a/docs/api.md b/docs/api.md
index d1b609f4..c62c21c7 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -1,13 +1,44 @@
# 附录:API列表
+?> 上次更新时间:* {docsify-updated} * 如不是最新版,请Ctrl+F5强制刷新缓存。
+
所有系统支持的API都列在了这里。所有可能被用到的API都在前面用\*标记。
可以在chrome浏览器的控制台中(`ctrl+shift+I`,找到Console)中直接进行调用,以查看效果。
-!> **`main.js`:游戏入口。所有其他JS文件都是被此文件加载。**
+!> **`main.js`:游戏入口,所有其他JS文件都是被此文件加载。**
``` js
-
+main.init // 初始化
+main.loaderJs // 动态加载所有核心JS文件
+main,loaderFloors // 动态加载所有楼层(剧本)
+main.loadMod // 加载某一个JS文件
+main.loadFloor // 加载某一个楼层
+main.setMainTipsText // 加载过程提示
+window.onresize // 窗口大小变化时
+main.dom.body.onkeydown // 在界面上按下某按键时
+main.dom.body.onkeydown // 在界面上放开某按键时
+main.dom.body.onselectstart // 开始选择时
+main.dom.data.onmousedown // 鼠标按下时
+main.dom.data.onmousemove // 鼠标移动时
+main.dom.data.onmouseup // 鼠标放开时
+main.dom.data.onmousewheel // 鼠标滑轮滚动时
+main.dom.data.ontouchstart // 手指在触摸屏开始触摸时
+main.dom.data.ontouchmove // 手指在触摸屏上移动时
+main.dom.data.ontouchend // 手指离开触摸屏时
+main.statusBar.image.book.onclick // 点击状态栏中的怪物手册时
+main.statusBar.image.fly.onclick // 点击状态栏中的楼层传送器时
+main.statusBar.image.toolbox.onclick // 点击状态栏中的工具箱时
+main.statusBar.image.shop.onclick // 点击状态栏中的快捷商店时
+main.statusBar.image.save.onclick // 点击状态栏中的存档按钮时
+main.statusBar.image.load.onclick // 点击状态栏中的读档按钮时
+main.statusBar.image.settings.onclick // 点击状态栏中的系统菜单时
+main.dom.playGame.onclick // 点击“开始游戏”时
+main.dom.loadGame.onclick // 点击“载入游戏”时
+main.dom.aboutGame.onclick // 点击“关于本塔”时
+main.dom.easyLevel.onclick // 点击“简单难度”时
+main.dom.normalLevel.onclick // 点击“普通难度”时
+main.dom.hardLevel.onclick // 点击“困难难度”时
```
!> **`core.js`:系统核心文件。所有核心逻辑处理都在此文件完成。**
@@ -97,7 +128,6 @@ core.setOpacity // 设置某个canvas的透明度
core.setFillStyle // 设置某个canvas的绘制属性(如颜色等)
* core.drawMap(mapId, callback) // 绘制某张地图。mapId为地图Id,绘制完毕将执行callback回调函数。
core.drawAutotile // 绘制Autotile
-core.drawAutotileBlock // 绘制Autotile的某一块
* core.noPassExists(x,y) // 某个点是否不可通行
core.noPass // 某个点是否在区域内且不可通行
* core.npcExists(x,y) // 某个点是否存在NPC
@@ -291,6 +321,7 @@ core.maps.addChangeFloor // 向该楼层添加剧本的楼层转换事件
core.maps.initMaps // 初始化所有地图
core.maps.save // 将当前地图重新变成数字,以便于存档
core.maps.load // 将存档中的地图信息重新读取出来
+core.maps.getMapArray // 将当前地图重新变成二维数组形式
```
!> `ui.js` 定义了各种界面的绘制。
diff --git a/docs/element.md b/docs/element.md
index 50459e42..ef764af5 100644
--- a/docs/element.md
+++ b/docs/element.md
@@ -1,5 +1,7 @@
# 元件说明
+?> 上次更新时间:* {docsify-updated} *
+
在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。
请打开样板0层 `sample0.js` 进行参照对比。
@@ -30,7 +32,7 @@
## 怪物
-本塔支持的怪物列表参见`enemys.js`。其与images目录下的`enemys.png`素材按顺序一一对应。如不知道怪物素材长啥样的请打开`enemys.png`对比查看。
+本塔支持的怪物列表参见`enemys.js`。其与images目录下的`enemys.png`素材按顺序一一对应。如不知道怪物素材长啥样的请打开`enemys.png`对比查看。
如有自己的怪物素材需求请参见[自定义素材](personalization#自定义素材)的内容。
怪物可以有特殊属性,每个怪物可以有多个自定义属性。
@@ -70,6 +72,7 @@ enemys.prototype.getSpecialText = function (enemyId) {
多属性可采用数组的写法,比如`'special': [1,3]`视为同时拥有先攻和坚固属性;`'special': [5,10,14,18]`视为拥有3连击、魔防、诅咒、阻击四个属性。
本塔支持战斗动画,在`data.js`中存在三个全局选项:`canOpenBattleAnimate`, `showBattleAnimateConfirm`, `battleAnimate`。
+
- `canOpenBattleAnimate`代表是否允许用户开启战斗动画。如果你添加了一些自定义属性,且不想修改战斗界面的UI,则可以将其关闭。
- `showBattleAnimateConfirm`代表是否在游戏开始时给用户提供开启动画的选项。对于一些偏向于萌新的塔,可以开启此项。
- `battleAnimate`代表是否默认开启战斗动画。此项会被用户存储的设置给覆盖。
@@ -117,7 +120,7 @@ N连击怪物的special是6,且我们可以为它定义n代表实际连击数
如有额外需求,可参见[自定义怪物属性](personalization#自定义自定义怪物属性),里面讲了如何设置一个新的怪物属性。
-### 路障,楼梯,传送门
+## 路障,楼梯,传送门
血网的伤害数值、中毒后每步伤害数值、衰弱时暂时攻防下降的数值,都在 `data.js` 的values内定义。
@@ -143,7 +146,7 @@ floorId指定的是目标楼层的唯一标识符(ID)。

-### 背景音乐
+## 背景音乐
本塔支持BGM和SE的播放。
@@ -169,17 +172,19 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
定义完毕后,我们可以调用`playBgm`/`playSound`事件来播放对应的音乐/音效,有关事件的详细介绍请参见[事件](event)。
**另外,考虑到用户的流量问题,将遵循如下规则:**
+
- **如果用户当前使用的电脑,则默认开启音乐效果,并播放默认BGM**
- **如果用户当前使用的手机,且处于Wifi状态,则默认开启音乐效果,并播放默认BGM**
- **其他情况,将默认关闭音乐效果,只有在用户在菜单栏中点击“音乐开关”后才会播放音乐**
!> iOS平台以及部分浏览器不支持获得当前网络状态,此时即使在使用Wifi也必须要用户点击“音乐开关”才能播放音乐。
-### 操作说明
+## 操作说明
本塔主要支持鼠标(触摸屏)操作和键盘操作。
鼠标(触摸屏)操作说明如下:
+
- **点状态栏中图标:** 进行对应的操作
- **点任意块:** 寻路并移动
- **点任意块并拖动:** 指定寻路路线
@@ -187,6 +192,7 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
- **双击勇士:** 轻按(仅在轻按开关打开时有效)
键盘操作快捷键如下:
+
- **[CTRL]** 跳过对话
- **[X]** 打开/关闭怪物手册
- **[G]** 打开/关闭楼层传送器
@@ -213,4 +219,3 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
==========================================================================================
[继续阅读下一章:事件](event)
-
diff --git a/docs/event.md b/docs/event.md
index a1525c3c..58d0917e 100644
--- a/docs/event.md
+++ b/docs/event.md
@@ -1,5 +1,7 @@
# 事件
+?> 上次更新时间:* {docsify-updated} *
+
本章内将对样板所支持的事件进行介绍。
## 事件的机制
@@ -29,6 +31,7 @@
"x,y": {
"trigger": "action", // 触发的trigger, action代表自定义事件
"enable": true, // 该事件初始状态下是否处于启用状态
+ "noPass": true, // 该点是否不可通行。true代表不可通行,false代表可通行。
"data": [ // 实际执行的事件列表
// 事件1
// 事件2
@@ -53,6 +56,7 @@
"x,y": {
// 除非你要覆盖该点已存在的系统默认事件,否则"trigger": "action"可以省略
"enable": true, // 该事件初始状态下是否处于启用状态
+ "noPass": true, // 该点是否不可通行。true代表不可通行,false代表可通行。
"data": [ // 实际执行的事件列表
// 事件1
// 事件2
@@ -71,6 +75,28 @@
"x,y": {
// 除非你要覆盖该点已存在的系统默认事件,否则"trigger": "action"可以省略
// 该事件初始状态下是启用状态,则可以省略"enable": true;如果是禁用状态则必须加上"enable": false
+ "noPass": true, // 该点是否不可通行。true代表不可通行,false代表可通行。
+ "data": [ // 实际执行的事件列表
+ // 事件1
+ // 事件2
+ // ...
+ ]
+ }
+}
+```
+
+`"noPass"`为该点是否可通行的标记。`true`代表该点不可通行,`false`代表该点可通行。
+
+对于目前所有的素材,都存在默认的是否可通行状态。如果你在该点指定`noPass`,则原本的可通行状态会被覆盖。
+
+因此,除非你想覆盖默认的可通行选项(比如将一个空地设为不可通行),否则该项可以忽略。
+
+``` js
+"events": { // 该楼的所有可能事件列表
+ "x,y": {
+ // 除非你要覆盖该点已存在的系统默认事件,否则"trigger": "action"可以省略
+ // 该事件初始状态下是启用状态,则可以省略"enable": true;如果是禁用状态则必须加上"enable": false
+ // 除非你想覆盖系统默认的可通行状态,否则"noPass"项可以忽略
"data": [ // 实际执行的事件列表
// 事件1
// 事件2
@@ -86,7 +112,7 @@
``` js
"events": { // 该楼的所有可能事件列表
- // 如果大括号里只有"data"项(没有"action"或"enable"),则可以省略到只剩下中括号
+ // 如果大括号里只有"data"项(没有"action", "enable"或"noPass"),则可以省略到只剩下中括号
"x,y": [ // 实际执行的事件列表
// 事件1
// 事件2
@@ -97,7 +123,7 @@
这种简写方式可以极大方便地造塔者进行造塔。
-!> **请注意:如果该点初始的`enable`为`false`,或者该点本身有系统默认事件且需要覆盖(`trigger`),则必须采用上面那种大括号写的方式来定义。**
+!> **请注意:如果该点初始的`enable`为`false`,或者该点本身有系统默认事件且需要覆盖(`trigger`),或者你想覆盖该点的默认通行状态,则必须采用上面那种大括号写的方式来定义。**
@@ -941,6 +967,26 @@ events.prototype.addPoint = function (enemy) {
当且仅当勇士第一次到达某层时,将会触发此事件。可以利用此事件来显示一些剧情,或再让它调用 `{"type": "trigger"}` 来继续调用其他的事件。
+## 战前剧情
+
+有时候光战后事件`afterBattle`是不够的,我们可能还需要战前剧情,例如Boss战之前和Boss进行一段对话。
+
+要使用战前剧情,首先你需要覆盖该店的系统默认事件,改成你自己的自定义事件,然后在战前剧情后调用`{"type": "battle"}`强制战斗。
+
+值得注意的是,使用这种自定义事件来覆盖系统的默认战斗事件时,可以增加`displayDamage`代表该点是否需要显伤。此项可省略,默认为有显伤。
+
+``` js
+"x,y": { // (x,y)为该怪物坐标
+ "trigger": "action", // 覆盖该点本身默认事件,变成自定义事件
+ "displayDamage": true, // 覆盖后,该点是否有显伤;此项可忽略,默认为有。
+ "data": [ // 该点的自定义事件列表
+ // ... 战前剧情
+ {"type": "battle", "id": "xxx"}, // 强制战斗
+ // ... 战后剧情;请注意上面的强制战斗不会使怪物消失,如有需要请调动{"type": "hide"}
+ ]
+}
+```
+
## 经验升级(进阶/境界塔)
本塔也支持经验升级,即用户杀怪获得经验后,可以到达某些数值自动进阶,全面提升属性。
@@ -1015,9 +1061,8 @@ events.prototype.setInitData = function (hard) {
当获胜`{"type": "win"}`事件发生时,将调用`events.js`中的win事件。其显示一段恭喜文字,并重新开始游戏。
``` js
-////// 游戏结束事件 //////
+////// 游戏获胜事件 //////
events.prototype.win = function(reason) {
- // 获胜
core.waitHeroToStop(function() {
core.removeGlobalAnimate(0,0,true);
core.clearMap('all'); // 清空全地图
@@ -1035,8 +1080,8 @@ events.prototype.win = function(reason) {
当失败(`{"type": "lose"}`,或者被怪强制战斗打死、被领域怪扣血死、中毒导致扣血死,路障导致扣血死等等)事件发生时,将调用`events.js`中的`lose`事件。其直接显示一段文字,并重新开始游戏。
``` js
+////// 游戏失败事件 //////
events.prototype.lose = function(reason) {
- // 失败
core.waitHeroToStop(function() {
core.drawText([
"\t[结局1]你死了。\n如题。"
diff --git a/docs/index.html b/docs/index.html
index 8065a5e4..79028c98 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -6,6 +6,7 @@
+
@@ -19,7 +20,7 @@
repo: 'https://github.com/ckcz123/mota-js',
// basepath: '../docs/',
- // Search Support
+ // Search Support
// search: {
// maxAge: 43200000, // 过期时间,单位毫秒,默认一天
// paths: 'auto',
@@ -37,10 +38,12 @@
loadSidebar: '_sidebar.md',
subMaxLevel: 2,
autoHeader: true,
+ auto2top: true,
+ mergeNavbar: true,
+ formatUpdated: '{YYYY}-{MM}-{DD} {HH}:{mm}:{ss}',
}
- //离线模式
if (typeof navigator.serviceWorker !== 'undefined') {
- navigator.serviceWorker.register('serviceWorker.js')
+ navigator.serviceWorker.register('serviceWorker.js')
}
diff --git a/docs/index.md b/docs/index.md
index ad17349c..9f0059ef 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,5 +1,7 @@
# HTML5 魔塔样板说明文档
+?> 上次更新时间:* {docsify-updated} *
+
众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。
但是,现在我们有了HTML5。 HTML5的画布(canvas)以及它被Android/iOS内置浏览器所支持的特性,可以让我们做出真正意义上的全平台覆盖的魔塔。
@@ -11,7 +13,7 @@
继续查看文档的详细介绍,让你学会如何使用这一个样板来制作属于自己的HTML5魔塔。
-视频教程地址:http://www.bilibili.com/video/av17608025/ ,配合本教程观看效果更佳~
+视频教程地址:[http://www.bilibili.com/video/av17608025/](http://www.bilibili.com/video/av17608025/) ,配合本教程观看效果更佳~
==========================================================================================
diff --git a/docs/personalization.md b/docs/personalization.md
index d63c4883..9b4eb0ca 100644
--- a/docs/personalization.md
+++ b/docs/personalization.md
@@ -1,5 +1,7 @@
# 个性化
+?> 上次更新时间:* {docsify-updated} *
+
有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。
## 自定义素材
@@ -21,6 +23,41 @@
如果你需要某个素材已经存在,则可以直接将其覆盖images目录下的同名文件,就能看到效果。
+### 使用自己的图片作为某层楼的背景素材
+
+由于HTML5功能(素材)有限,导致了对很多比较复杂的素材(比如房子内)等无法有着较好的绘图方式。
+
+为了解决这个问题,我们允许用户自己放置一张图片作为某一层的背景素材。
+
+要启用这个功能,我们首先需要在`main.js`中将可能的图片进行加载。
+
+``` js
+this.pngs = [ // 在此存放所有可能的背景图片;背景图片最好是416*416像素,其他分辨率会被强制缩放成416*416
+ // 建议对于较大的图片,在网上使用在线的“图片压缩工具”来进行压缩,以节省流量
+ "bg.png", // "yewai.png",
+];
+```
+
+!> 背景素材只支持png格式,且会被强制缩放到416*416。
+
+!> 请使用网上的一些[在线图片压缩工具](http://www.asqql.com/gifzip/)对png图片进行压缩,以节省流量。一张500KB的png图片可以被压缩到20-30KB,显示效果不会有太大差异。
+
+之后,我们可以在每层剧本的`"png": "xxx"`里来定义该层的默认背景图片素材。
+
+``` js
+"png": "bg.png", // 背景图;你可以选择一张png图片来作为背景素材。
+```
+
+你的图片背景素材将会覆盖原来本身的背景层。
+
+**如果你需要让某些点不可通行(比如你建了个房子,墙壁和家具等位置不让通行),则需在`events`中指定`{"noPass": false}`,参见[自定义事件](event#自定义事件)的写法。
+
+``` js
+"events": {
+ "x,y": {"noPass": true} // (x,y)点不可通行
+}
+```
+
### 使用便捷PS工具生成素材
如果我们有更多的素材要求,我们可以使用“便捷PS工具”进行处理。
@@ -52,7 +89,6 @@
如果需要添加一个素材到游戏,则必须为其分配一个唯一标识符,并同时修改`icons.js`和`maps.js`两个文件。
-
#### 新添加自定义地形(路面、墙壁等)
如果你在terrains.png中新增了一行:
diff --git a/docs/serviceWorker.js b/docs/serviceWorker.js
index ab031ac1..34634e1e 100644
--- a/docs/serviceWorker.js
+++ b/docs/serviceWorker.js
@@ -1,31 +1,31 @@
const RUNTIME = 'docsify'
const HOSTNAME_WHITELIST = [
- self.location.hostname,
- 'fonts.gstatic.com',
- 'fonts.googleapis.com',
- 'unpkg.com'
+ self.location.hostname,
+ 'fonts.gstatic.com',
+ 'fonts.googleapis.com',
+ 'cdn.bootcss.com'
]
// The Util Function to hack URLs of intercepted requests
const getFixedUrl = (req) => {
- var now = Date.now()
- var url = new URL(req.url)
+ var now = Date.now()
+ var url = new URL(req.url)
- // 1. fixed http URL
- // Just keep syncing with location.protocol
- // fetch(httpURL) belongs to active mixed content.
- // And fetch(httpRequest) is not supported yet.
- url.protocol = self.location.protocol
+ // 1. fixed http URL
+ // Just keep syncing with location.protocol
+ // fetch(httpURL) belongs to active mixed content.
+ // And fetch(httpRequest) is not supported yet.
+ url.protocol = self.location.protocol
- // 2. add query for caching-busting.
- // Github Pages served with Cache-Control: max-age=600
- // max-age on mutable content is error-prone, with SW life of bugs can even extend.
- // Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
- // Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
- if (url.hostname === self.location.hostname) {
- url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
- }
- return url.href
+ // 2. add query for caching-busting.
+ // Github Pages served with Cache-Control: max-age=600
+ // max-age on mutable content is error-prone, with SW life of bugs can even extend.
+ // Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
+ // Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
+ if (url.hostname === self.location.hostname) {
+ url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
+ }
+ return url.href
}
/**
@@ -35,7 +35,7 @@ const getFixedUrl = (req) => {
* waitUntil(): activating ====> activated
*/
self.addEventListener('activate', event => {
- event.waitUntil(self.clients.claim())
+ event.waitUntil(self.clients.claim())
})
/**
@@ -45,8 +45,8 @@ self.addEventListener('activate', event => {
* void respondWith(Promise r)
*/
self.addEventListener('fetch', event => {
- // Skip some of cross-origin requests, like those for Google Analytics.
- if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
+ // Skip some of cross-origin requests, like those for Google Analytics.
+ if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
// Stale-while-revalidate
// similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
// Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
@@ -60,16 +60,16 @@ self.addEventListener('fetch', event => {
// If there’s nothing in cache, wait for the fetch.
// If neither yields a response, return offline pages.
event.respondWith(
- Promise.race([fetched.catch(_ => cached), cached])
- .then(resp => resp || fetched)
- .catch(_ => { /* eat any errors */ })
- )
+ Promise.race([fetched.catch(_ => cached), cached])
+.then(resp => resp || fetched)
+.catch(_ => { /* eat any errors */ })
+)
// Update the cache with the version we fetched (only for ok status)
event.waitUntil(
- Promise.all([fetchedCopy, caches.open(RUNTIME)])
- .then(([response, cache]) => response.ok && cache.put(event.request, response))
+ Promise.all([fetchedCopy, caches.open(RUNTIME)])
+ .then(([response, cache]) => response.ok && cache.put(event.request, response))
.catch(_ => { /* eat any errors */ })
- )
- }
-})
+)
+}
+})
\ No newline at end of file
diff --git a/docs/start.md b/docs/start.md
index 10300b46..8ddde2af 100644
--- a/docs/start.md
+++ b/docs/start.md
@@ -1,5 +1,7 @@
# 快速上手
+?> 上次更新时间:* {docsify-updated} *
+
在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔!
## 前置需求
@@ -8,8 +10,8 @@
- Windows 8以上操作系统;Windows 7需要安装.Net Framework 4.0。(能打开同目录下的“启动服务.exe”即可)
- 任一款现代浏览器。强烈推荐Chrome。
-- 一个很好的文本编辑器。推荐带有高亮染色、错误提示等效果。例如:WebStorm,VSCode,或者至少也要Sublime Text。
-([VSCode下载地址](https://code.visualstudio.com/),群里的群文件中也有,强烈推荐之。)
+- 一个很好的文本编辑器。推荐带有高亮染色、错误提示等效果。例如:WebStorm,VSCode,或者至少也要Sublime Text。
+ - ([VSCode下载地址](https://code.visualstudio.com/),群里的群文件中也有,强烈推荐之。)
只要满足了上述条件,你就可以开始做自己的塔啦!
diff --git a/drawMapGUI.html b/drawMapGUI.html
index cd84aa5a..e6051f11 100644
--- a/drawMapGUI.html
+++ b/drawMapGUI.html
@@ -2,304 +2,7 @@
-
+
@@ -349,14 +52,19 @@
+
@@ -496,15 +204,10 @@