commit
eb4406f408
@ -57,13 +57,16 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
|
||||
|
||||
* [x] 怪物和NPC的行走图和朝向问题
|
||||
* [x] 可以引入WindowSkin作为对话框的背景素材
|
||||
* [x] \r可以动态调整剧情文本的颜色
|
||||
* [x] 允许使用\t[标题,1.png]来绘制大头像图
|
||||
* [x] 对话框的宽度可以根据文本长度自动调整
|
||||
* [x] \r[red]可以动态调整剧情文本的颜色
|
||||
* [x] 升级事件改用事件编辑器完成
|
||||
* [x] 每层楼都增添该层的并行事件处理
|
||||
* [x] 新增快捷键:N返回标题;P查看评论;O打开工程
|
||||
* [x] 道具可以设置是否在回放时绘制道具栏或直接使用
|
||||
* [x] 追加素材一次可以追加多个
|
||||
* [x] 可以同时异步移动/跳跃勇士和多个NPC
|
||||
* [x] 可以同时异步移动两张或以上的图片了
|
||||
* [x] 追加素材一次可以追加多个
|
||||
* [x] 菜单栏中新增虚拟键盘的弹出
|
||||
* [x] 修复所有已知Bug;部分细节优化
|
||||
|
||||
|
||||
@ -1084,45 +1084,48 @@ return code;
|
||||
*/;
|
||||
|
||||
move_s
|
||||
: '移动事件' 'x' PosString? ',' 'y' PosString? '动画时间' Int? '不消失' Bool BGNL? StepString Newline
|
||||
: '移动事件' 'x' PosString? ',' 'y' PosString? '动画时间' Int? '不消失' Bool '不等待执行完毕' Bool BGNL? StepString Newline
|
||||
|
||||
|
||||
/* move_s
|
||||
tooltip : move: 让某个NPC/怪物移动,位置可不填代表当前事件
|
||||
helpUrl : https://h5mota.com/games/template/docs/#/event?id=move%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AAnpc%E6%80%AA%E7%89%A9%E7%A7%BB%E5%8A%A8
|
||||
default : ["","",500,false,"上右3下2左上左2"]
|
||||
default : ["","",500,false,false,"上右3下2左上左2"]
|
||||
colour : this.eventColor
|
||||
var floorstr = '';
|
||||
if (PosString_0 && PosString_1) {
|
||||
floorstr = ', "loc": ['+PosString_0+','+PosString_1+']';
|
||||
}
|
||||
Int_0 = Int_0 ?(', "time": '+Int_0):'';
|
||||
var code = '{"type": "move"'+floorstr+''+Int_0+', "steps": '+JSON.stringify(StepString_0)+', "keep": '+Bool_0+'},\n';
|
||||
Bool_0 = Bool_0?', "keep": true':'';
|
||||
Bool_1 = Bool_1?', "async": true':'';
|
||||
var code = '{"type": "move"'+floorstr+Int_0+Bool_0+Bool_1+', "steps": '+JSON.stringify(StepString_0)+'},\n';
|
||||
return code;
|
||||
*/;
|
||||
|
||||
moveHero_s
|
||||
: '移动勇士' '动画时间' Int? BGNL? StepString Newline
|
||||
: '移动勇士' '动画时间' Int? '不等待执行完毕' Bool BGNL? StepString Newline
|
||||
|
||||
|
||||
/* moveHero_s
|
||||
tooltip : moveHero:移动勇士,用这种方式移动勇士的过程中将无视一切地形, 无视一切事件, 中毒状态也不会扣血
|
||||
helpUrl : https://h5mota.com/games/template/docs/#/event?id=movehero%EF%BC%9A%E7%A7%BB%E5%8A%A8%E5%8B%87%E5%A3%AB
|
||||
default : [500,"上右3下2左上左2"]
|
||||
default : [500,false,"上右3下2左上左2"]
|
||||
colour : this.dataColor
|
||||
Int_0 = Int_0 ?(', "time": '+Int_0):'';
|
||||
var code = '{"type": "moveHero"'+Int_0+', "steps": '+JSON.stringify(StepString_0)+'},\n';
|
||||
Bool_0 = Bool_0?', "async": true':'';
|
||||
var code = '{"type": "moveHero"'+Int_0+Bool_0+', "steps": '+JSON.stringify(StepString_0)+'},\n';
|
||||
return code;
|
||||
*/;
|
||||
|
||||
jump_s
|
||||
: '跳跃事件' '起始 x' PosString? ',' 'y' PosString? '终止 x' PosString? ',' 'y' PosString? '动画时间' Int? '不消失' Bool Newline
|
||||
: '跳跃事件' '起始 x' PosString? ',' 'y' PosString? '终止 x' PosString? ',' 'y' PosString? '动画时间' Int? '不消失' Bool '不等待执行完毕' Bool Newline
|
||||
|
||||
|
||||
/* jump_s
|
||||
tooltip : jump: 让某个NPC/怪物跳跃
|
||||
helpUrl : https://h5mota.com/games/template/docs/#/event?id=jump%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AANPC%2F%E6%80%AA%E7%89%A9%E8%B7%B3%E8%B7%83
|
||||
default : ["","","","",500,true]
|
||||
default : ["","","","",500,true,false]
|
||||
colour : this.eventColor
|
||||
var floorstr = '';
|
||||
if (PosString_0 && PosString_1) {
|
||||
@ -1132,25 +1135,28 @@ if (PosString_2 && PosString_3) {
|
||||
floorstr += ', "to": ['+PosString_2+','+PosString_3+']';
|
||||
}
|
||||
Int_0 = Int_0 ?(', "time": '+Int_0):'';
|
||||
var code = '{"type": "jump"'+floorstr+''+Int_0+', "keep": '+Bool_0+'},\n';
|
||||
Bool_0 = Bool_0?', "keep": true':'';
|
||||
Bool_1 = Bool_1?', "async": true':'';
|
||||
var code = '{"type": "jump"'+floorstr+''+Int_0+Bool_0+Bool_1+'},\n';
|
||||
return code;
|
||||
*/;
|
||||
|
||||
jumpHero_s
|
||||
: '跳跃勇士' 'x' PosString? ',' 'y' PosString? '动画时间' Int? Newline
|
||||
: '跳跃勇士' 'x' PosString? ',' 'y' PosString? '动画时间' Int? '不等待执行完毕' Bool Newline
|
||||
|
||||
|
||||
/* jumpHero_s
|
||||
tooltip : jumpHero: 跳跃勇士
|
||||
helpUrl : https://h5mota.com/games/template/docs/#/event?id=jumpHero%EF%BC%9A%E8%B7%B3%E8%B7%83%E5%8B%87%E5%A3%AB
|
||||
default : ["","",500]
|
||||
default : ["","",500,false]
|
||||
colour : this.dataColor
|
||||
var floorstr = '';
|
||||
if (PosString_0 && PosString_1) {
|
||||
floorstr = ', "loc": ['+PosString_0+','+PosString_1+']';
|
||||
}
|
||||
Int_0 = Int_0 ?(', "time": '+Int_0):'';
|
||||
var code = '{"type": "jumpHero"'+floorstr+Int_0+'},\n';
|
||||
Bool_0 = Bool_0?', "async": true':'';
|
||||
var code = '{"type": "jumpHero"'+floorstr+Int_0+Bool_0+'},\n';
|
||||
return code;
|
||||
*/;
|
||||
|
||||
@ -1910,22 +1916,22 @@ ActionParser.prototype.parseAction = function() {
|
||||
case "move": // 移动事件
|
||||
data.loc=data.loc||['',''];
|
||||
this.next = MotaActionBlocks['move_s'].xmlText([
|
||||
data.loc[0],data.loc[1],data.time||0,data.keep,this.StepString(data.steps),this.next]);
|
||||
data.loc[0],data.loc[1],data.time||0,data.keep||false,data.async||false,this.StepString(data.steps),this.next]);
|
||||
break;
|
||||
case "moveHero":
|
||||
this.next = MotaActionBlocks['moveHero_s'].xmlText([
|
||||
data.time||0,this.StepString(data.steps),this.next]);
|
||||
data.time||0,data.async||false,this.StepString(data.steps),this.next]);
|
||||
break;
|
||||
case "jump": // 跳跃事件
|
||||
data.from=data.from||['',''];
|
||||
data.to=data.to||['',''];
|
||||
this.next = MotaActionBlocks['jump_s'].xmlText([
|
||||
data.from[0],data.from[1],data.to[0],data.to[1],data.time||0,data.keep,this.next]);
|
||||
data.from[0],data.from[1],data.to[0],data.to[1],data.time||0,data.keep||false,data.async||false,this.next]);
|
||||
break;
|
||||
case "jumpHero": // 跳跃勇士
|
||||
data.loc=data.loc||['','']
|
||||
this.next = MotaActionBlocks['jumpHero_s'].xmlText([
|
||||
data.loc[0],data.loc[1],data.time||0,this.next]);
|
||||
data.loc[0],data.loc[1],data.time||0,data.async||false,this.next]);
|
||||
break;
|
||||
case "changeFloor": // 楼层转换
|
||||
data.loc=data.loc||['','']
|
||||
|
||||
@ -305,7 +305,7 @@ floorId指定的是目标楼层的唯一标识符(ID)。
|
||||
|
||||
**从2.1.1开始,楼层属性中提供了`upFloor`和`downFloor`两项。如果设置此项(比如`"upFloor": [2,3]`),则写stair:upFloor或者楼传器的落点将用此点来替换楼梯位置(即类似于RM中的上箭头)。**
|
||||
|
||||
## 剧情文本控制与界面皮肤
|
||||
## 剧情文本控制与对话框效果
|
||||
|
||||
在写剧情文本时,可以:
|
||||
|
||||
@ -314,6 +314,8 @@ floorId指定的是目标楼层的唯一标识符(ID)。
|
||||
- 使用`\r[...]`来动态修改局部文本的颜色,如`\r[red]`。
|
||||
- 使用`${}`来计算一个表达式的值,如`${status:atk+status:def}`。
|
||||
|
||||
从V2.5.2开始,也允许绘制一张头像图在对话框中,只要通过`\t[1.png]`或`\t[标题,1.png]`的写法。
|
||||
|
||||
详细信息请参见[剧情文本控制](event#text:显示一段文字(剧情))中的说明。
|
||||
|
||||
从V2.5.2开始,可以用一张WindowSkin图片作为对话框的背景皮肤。
|
||||
@ -324,6 +326,14 @@ floorId指定的是目标楼层的唯一标识符(ID)。
|
||||
|
||||
!> 关于对话框效果请注意,现在是采用WindowSkin的右下角两个32x32的图片作为对话框尖角进行绘制。因此请尽量使用群文件或网盘的常用素材中给出的WindowSkin素材(均已进行对话框适配)。如需使用来自第三方的WindowSkin素材,请自行注意对话框的尖角问题,或弃用`\b`效果。
|
||||
|
||||
另外一点是,V2.5.2以后,对话框`\b`可以根据文字长度来自动控制文本框宽度,其基本控制原理如下:
|
||||
|
||||
- 如果用户存在手动换行`\n`,则选取**最长的一段话**作为文本框宽度。
|
||||
- 如果用户不存在手动换行,则会将文本框宽度调整为**尽量刚好达到三行**的最佳宽度。
|
||||
- 文本框宽度存在上下界,最终宽度一定会控制在该范围内。
|
||||
|
||||
该自动调整仅对`\b`的对话框效果有效。非对话框仍然会绘制整个界面的宽度。
|
||||
|
||||
## 大地图
|
||||
|
||||
从V2.4开始,H5魔塔开始支持大地图。
|
||||
|
||||
@ -207,6 +207,8 @@
|
||||
|
||||
对于hero和怪物,也可以不写名字代表使用默认值。
|
||||
|
||||
从V2.5.2以后,新增了绘制大头像的功能。绘制大头像图的基本写法是`\t[1.png]`或者`\t[标题,1.png]`。
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
"一段普通文字",
|
||||
@ -216,9 +218,13 @@
|
||||
"\t[blackMagician]如果使用怪物的默认名称也可以简写怪物id",
|
||||
"\t[小妖精,fairy]这是一段小妖精说的话,使用仙子(fairy)的图标",
|
||||
"\t[你赢了]直接显示标题为【你赢了】",
|
||||
"\t[1.png]绘制1.png这个头像图",
|
||||
"\t[标题,1.png]同时绘制标题和1.png这个头像图"
|
||||
]
|
||||
```
|
||||
|
||||
!> 大头像的头像图需要在全塔属性中注册,且必须是png格式,不可以用jpg或者其他格式,请自行转换。
|
||||
|
||||
除此以外,我们还能实现“对话框效果”,只要有`\b[...]`就可以。
|
||||
|
||||
- `\b[up]` 直接显示在当前点上方。同样把这里的up换成down则为下方。
|
||||
@ -990,7 +996,7 @@ level为天气的强度等级,在1-10之间。1级为最弱,10级为最强
|
||||
{"type": "move", "time": 750, "loc": [x,y], "steps": [// 动画效果,time为移动速度(比如这里每750ms一步),loc为位置可选,steps为移动数组
|
||||
{"direction": "right", "value": 2},// 这里steps 的效果为向右移动2步,在向下移动一步并消失
|
||||
"down" // 如果该方向上只移动一步则可以这样简写,效果等价于上面value为1
|
||||
], "keep": true }, // keep可选,如果为true则不消失,否则渐变消失
|
||||
], "keep": true, "async":true }, // keep可选,如果为true则不消失,否则渐变消失;async可选,如果为true则异步执行。
|
||||
]
|
||||
```
|
||||
|
||||
@ -1026,7 +1032,9 @@ keep为一个可选项,代表该事件移动完毕后是否消失。如果该
|
||||
}
|
||||
```
|
||||
|
||||
即,在移动的到达点指定一个初始禁用的相同NPC,然后move事件中指定immediateHide使立刻消失,并show该到达点坐标使其立刻显示(看起来就像没有消失),然后就可以触发目标点的事件了。
|
||||
即,在移动的到达点指定一个事件,然后move事件中指定"keep":true,然后就可以触发目标点的事件了。
|
||||
|
||||
async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。
|
||||
|
||||
### moveHero:移动勇士
|
||||
|
||||
@ -1036,7 +1044,7 @@ keep为一个可选项,代表该事件移动完毕后是否消失。如果该
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
{"type": "moveHero", "time": 750, "steps": [// 动画效果,time为移动速度(比如这里每750ms一步),steps为移动数组
|
||||
{"type": "moveHero", "time": 750, "async": true, "steps": [// 动画效果,time为移动速度(比如这里每750ms一步),steps为移动数组
|
||||
{"direction": "right", "value": 2},// 这里steps 的效果为向右移动2步,在向下移动一步并消失
|
||||
"down" // 如果该方向上只移动一步则可以这样简写,效果等价于上面value为1
|
||||
]},
|
||||
@ -1047,6 +1055,8 @@ keep为一个可选项,代表该事件移动完毕后是否消失。如果该
|
||||
|
||||
不过值得注意的是,用这种方式移动勇士的过程中将无视一切地形,无视一切事件,中毒状态也不会扣血。
|
||||
|
||||
async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。
|
||||
|
||||
### jump:让某个NPC/怪物跳跃
|
||||
|
||||
如果我们需要移动某个NPC或怪物,可以使用`{"type": "jump"}`。
|
||||
@ -1055,7 +1065,7 @@ keep为一个可选项,代表该事件移动完毕后是否消失。如果该
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
{"type": "jump", "from": [3,6], "to": [2,1], "time": 750, "keep": true},
|
||||
{"type": "jump", "from": [3,6], "to": [2,1], "time": 750, "keep": true, "async": true},
|
||||
]
|
||||
```
|
||||
|
||||
@ -1069,6 +1079,8 @@ keep为一个可选项,同上代表该跳跃完毕后是否不消失。如果
|
||||
|
||||
如果指定了`"keep": true`,则相当于会在目标地点触发一个`setBlock`事件;如需能继续对话交互请在目标地点再写事件。
|
||||
|
||||
async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。
|
||||
|
||||
### jumpHero:跳跃勇士
|
||||
|
||||
如果我们需要跳跃勇士,可以使用`{"type": "jumpHero"}`。
|
||||
@ -1077,7 +1089,7 @@ keep为一个可选项,同上代表该跳跃完毕后是否不消失。如果
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
{"type": "jump", "loc": [3,6], "time": 750},
|
||||
{"type": "jump", "loc": [3,6], "time": 750, "async": true},
|
||||
]
|
||||
```
|
||||
|
||||
@ -1085,6 +1097,8 @@ loc为目标坐标,可以忽略表示原地跳跃(请注意是原地跳跃
|
||||
|
||||
time选项为该跳跃所需要用到的时间。
|
||||
|
||||
async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。
|
||||
|
||||
### playBgm:播放背景音乐
|
||||
|
||||
使用playBgm可以播放一个背景音乐。
|
||||
|
||||
@ -832,12 +832,8 @@ control.prototype.moveHero = function (direction, callback) {
|
||||
|
||||
/////// 使用事件让勇士移动。这个函数将不会触发任何事件 //////
|
||||
control.prototype.eventMoveHero = function(steps, time, callback) {
|
||||
|
||||
time = time || 100;
|
||||
|
||||
core.clearMap('ui');
|
||||
core.setAlpha('ui', 1.0);
|
||||
|
||||
// 要运行的轨迹:将steps展开
|
||||
var moveSteps=[];
|
||||
steps.forEach(function (e) {
|
||||
@ -864,14 +860,11 @@ control.prototype.eventMoveHero = function(steps, time, callback) {
|
||||
'right': {'x': 1, 'y': 0}
|
||||
};
|
||||
|
||||
// core.status.replay.animate=true;
|
||||
|
||||
var animate=window.setInterval(function() {
|
||||
var x=core.getHeroLoc('x'), y=core.getHeroLoc('y');
|
||||
if (moveSteps.length==0) {
|
||||
clearInterval(animate);
|
||||
core.drawHero(null, x, y);
|
||||
// core.status.replay.animate=false;
|
||||
if (core.isset(callback)) callback();
|
||||
}
|
||||
else {
|
||||
@ -902,9 +895,6 @@ control.prototype.jumpHero = function (ex, ey, time, callback) {
|
||||
if (!core.isset(ey)) ey=sy;
|
||||
|
||||
time = time || 500;
|
||||
core.clearMap('ui');
|
||||
core.setAlpha('ui', 1.0);
|
||||
// core.status.replay.animate=true;
|
||||
|
||||
core.playSound('jump.mp3');
|
||||
|
||||
@ -954,7 +944,6 @@ control.prototype.jumpHero = function (ex, ey, time, callback) {
|
||||
core.setHeroLoc('x', ex);
|
||||
core.setHeroLoc('y', ey);
|
||||
core.drawHero();
|
||||
// core.status.replay.animate=false;
|
||||
if (core.isset(callback)) callback();
|
||||
}
|
||||
|
||||
|
||||
@ -598,14 +598,26 @@ events.prototype.doAction = function() {
|
||||
x=core.calValue(data.loc[0]);
|
||||
y=core.calValue(data.loc[1]);
|
||||
}
|
||||
core.moveBlock(x,y,data.steps,data.time,data.keep,function() {
|
||||
core.events.doAction();
|
||||
})
|
||||
if (data.async) {
|
||||
core.moveBlock(x,y,data.steps,data.time,data.keep);
|
||||
this.doAction();
|
||||
}
|
||||
else {
|
||||
core.moveBlock(x,y,data.steps,data.time,data.keep,function() {
|
||||
core.events.doAction();
|
||||
})
|
||||
}
|
||||
break;
|
||||
case "moveHero":
|
||||
core.eventMoveHero(data.steps,data.time,function() {
|
||||
core.events.doAction();
|
||||
});
|
||||
if (data.async) {
|
||||
core.eventMoveHero(data.steps, data.time);
|
||||
this.doAction();
|
||||
}
|
||||
else {
|
||||
core.eventMoveHero(data.steps,data.time,function() {
|
||||
core.events.doAction();
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "jump": // 跳跃事件
|
||||
{
|
||||
@ -618,9 +630,15 @@ events.prototype.doAction = function() {
|
||||
ex=core.calValue(data.to[0]);
|
||||
ey=core.calValue(data.to[1]);
|
||||
}
|
||||
core.jumpBlock(sx,sy,ex,ey,data.time,data.keep,function() {
|
||||
core.events.doAction();
|
||||
});
|
||||
if (data.async) {
|
||||
core.jumpBlock(sx,sy,ex,ey,data.time,data.keep);
|
||||
this.doAction();
|
||||
}
|
||||
else {
|
||||
core.jumpBlock(sx,sy,ex,ey,data.time,data.keep,function() {
|
||||
core.events.doAction();
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "jumpHero":
|
||||
@ -630,9 +648,15 @@ events.prototype.doAction = function() {
|
||||
ex=core.calValue(data.loc[0]);
|
||||
ey=core.calValue(data.loc[1]);
|
||||
}
|
||||
core.jumpHero(ex,ey,data.time,function() {
|
||||
core.events.doAction();
|
||||
});
|
||||
if (data.async) {
|
||||
core.jumpHero(ex,ey,data.time);
|
||||
this.doAction();
|
||||
}
|
||||
else {
|
||||
core.jumpHero(ex,ey,data.time,function() {
|
||||
core.events.doAction();
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "changeFloor": // 楼层转换
|
||||
|
||||
51
libs/maps.js
51
libs/maps.js
@ -738,8 +738,6 @@ maps.prototype.getBlockCls = function (x, y, floorId, showDisable) {
|
||||
maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
|
||||
time = time || 500;
|
||||
|
||||
core.clearMap('route');
|
||||
|
||||
var block = core.getBlock(x,y);
|
||||
if (block==null) {// 不存在
|
||||
if (core.isset(callback)) callback();
|
||||
@ -747,14 +745,9 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
|
||||
}
|
||||
var id = block.block.id;
|
||||
|
||||
// core.status.replay.animate=true;
|
||||
|
||||
// 需要删除该块
|
||||
core.removeBlock(x,y);
|
||||
|
||||
core.clearMap('ui');
|
||||
core.setAlpha('ui', 1.0);
|
||||
|
||||
block=block.block;
|
||||
|
||||
var image, bx, by, height = block.event.height || 32;
|
||||
@ -786,8 +779,8 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
|
||||
faceIds = block.event.faceIds||{};
|
||||
}
|
||||
|
||||
var opacityVal = 1;
|
||||
core.setOpacity('route', opacityVal);
|
||||
var alpha = 1;
|
||||
core.setAlpha('route', alpha);
|
||||
core.canvas.route.drawImage(image, bx * 32, by * height, 32, height, block.x * 32, block.y * 32 +32 - height, 32, height);
|
||||
|
||||
// 要运行的轨迹:将steps展开
|
||||
@ -834,15 +827,11 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
|
||||
|
||||
// 已经移动完毕,消失
|
||||
if (moveSteps.length==0) {
|
||||
if (keep) opacityVal=0;
|
||||
else opacityVal -= 0.06;
|
||||
core.setOpacity('route', opacityVal);
|
||||
if (keep) alpha=0;
|
||||
else alpha -= 0.06;
|
||||
core.clearMap('route', nowX, nowY-height+32, 32, height);
|
||||
core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, nowX, nowY-height+32, 32, height);
|
||||
if (opacityVal<=0) {
|
||||
if (alpha<=0) {
|
||||
clearInterval(animate);
|
||||
core.clearMap('route');
|
||||
core.setOpacity('route', 1);
|
||||
// 不消失
|
||||
if (keep) {
|
||||
core.setBlock(id, nowX/32, nowY/32);
|
||||
@ -851,6 +840,11 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
|
||||
// core.status.replay.animate=false;
|
||||
if (core.isset(callback)) callback();
|
||||
}
|
||||
else {
|
||||
core.setAlpha('route', alpha);
|
||||
core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, nowX, nowY-height+32, 32, height);
|
||||
core.setAlpha('route', 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 移动中
|
||||
@ -865,10 +859,10 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
|
||||
}
|
||||
}
|
||||
|
||||
core.clearMap('route', nowX, nowY-height+32, 32, height);
|
||||
step++;
|
||||
nowX+=scan[direction].x*2;
|
||||
nowY+=scan[direction].y*2;
|
||||
core.clearMap('route', nowX-32, nowY-32, 96, 96);
|
||||
// 绘制
|
||||
core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, nowX, nowY-height+32, 32, height);
|
||||
if (step==16) {
|
||||
@ -883,7 +877,6 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
|
||||
////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 //////
|
||||
maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) {
|
||||
time = time || 500;
|
||||
core.clearMap('route');
|
||||
var block = core.getBlock(sx,sy);
|
||||
if (block==null) {
|
||||
if (core.isset(callback)) callback();
|
||||
@ -891,12 +884,8 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) {
|
||||
}
|
||||
var id = block.block.id;
|
||||
|
||||
// core.status.replay.animate=true;
|
||||
|
||||
// 需要删除该块
|
||||
core.removeBlock(sx,sy);
|
||||
core.clearMap('ui');
|
||||
core.setAlpha('ui', 1.0);
|
||||
|
||||
block=block.block;
|
||||
var image, bx, by, height = block.event.height || 32;
|
||||
@ -926,8 +915,8 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) {
|
||||
by = core.material.icons[block.event.cls][block.event.id];
|
||||
}
|
||||
|
||||
var opacityVal = 1;
|
||||
core.setOpacity('route', opacityVal);
|
||||
var alpha = 1;
|
||||
core.setAlpha('route', alpha);
|
||||
core.canvas.route.drawImage(image, bx*32, by * height, 32, height, block.x * 32, block.y * 32 +32 - height, 32, height);
|
||||
|
||||
core.playSound('jump.mp3');
|
||||
@ -977,12 +966,10 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) {
|
||||
core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, drawX(), drawY()-height+32, 32, height);
|
||||
}
|
||||
else {
|
||||
if (keep) opacityVal=0;
|
||||
else opacityVal -= 0.06;
|
||||
core.setOpacity('route', opacityVal);
|
||||
if (keep) alpha=0;
|
||||
else alpha -= 0.06;
|
||||
core.clearMap('route', drawX(), drawY()-height+32, 32, height);
|
||||
core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, drawX(), drawY()-height+32, 32, height);
|
||||
if (opacityVal<=0) {
|
||||
if (alpha<=0) {
|
||||
clearInterval(animate);
|
||||
core.clearMap('route');
|
||||
core.setOpacity('route', 1);
|
||||
@ -990,9 +977,13 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) {
|
||||
core.setBlock(id, ex, ey);
|
||||
core.showBlock(ex, ey);
|
||||
}
|
||||
// core.status.replay.animate=false;
|
||||
if (core.isset(callback)) callback();
|
||||
}
|
||||
else {
|
||||
core.setAlpha('route', alpha);
|
||||
core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, drawX(), drawY()-height+32, 32, height);
|
||||
core.setAlpha('route', 1);
|
||||
}
|
||||
}
|
||||
|
||||
}, time / 16 / core.status.replay.speed);
|
||||
|
||||
96
libs/ui.js
96
libs/ui.js
@ -314,21 +314,29 @@ ui.prototype.getTitleAndIcon = function (content) {
|
||||
content=content.substring(index+1);
|
||||
var ss=str.split(",");
|
||||
if (ss.length==1) {
|
||||
id=ss[0];
|
||||
if (id=='hero') name = core.status.hero.name;
|
||||
else if (core.isset(core.material.enemys[id])) {
|
||||
name = core.material.enemys[id].name;
|
||||
getInfo(id);
|
||||
if (/^[-\w.]+\.png$/.test(ss[0])) {
|
||||
image = core.material.images.images[ss[0]];
|
||||
}
|
||||
else {
|
||||
name=id;
|
||||
id='npc';
|
||||
id=ss[0];
|
||||
if (id=='hero') name = core.status.hero.name;
|
||||
else if (core.isset(core.material.enemys[id])) {
|
||||
name = core.material.enemys[id].name;
|
||||
getInfo(id);
|
||||
}
|
||||
else {
|
||||
name=id;
|
||||
id='npc';
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
name=ss[0];
|
||||
id = 'npc';
|
||||
if (ss[1]=='hero') id = 'hero';
|
||||
else if (/^[-\w.]+\.png$/.test(ss[1])) {
|
||||
image = core.material.images.images[ss[1]];
|
||||
}
|
||||
else getInfo(ss[1]);
|
||||
}
|
||||
}
|
||||
@ -390,9 +398,32 @@ ui.prototype.drawWindowSkin = function(background,canvas,x,y,w,h,direction,px,py
|
||||
// 仿RM窗口皮肤 ↑
|
||||
}
|
||||
|
||||
// 绘制纯色的背景框
|
||||
ui.prototype.drawPureBackground = function (background,canvas,borderColor,x,y,w,h,direction,px,py) {
|
||||
// 计算有效文本框的宽度
|
||||
ui.prototype.calTextBoxWidth = function (canvas, content, min_width, max_width) {
|
||||
// 无限长度自动换行
|
||||
var allLines = core.splitLines(canvas, content);
|
||||
|
||||
// 如果不存在手动换行,则二分自动换行
|
||||
if (allLines.length == 1) {
|
||||
var prefer_lines = 3;
|
||||
var start = Math.floor(min_width), end = Math.floor(max_width);
|
||||
while (start < end) {
|
||||
var mid = Math.floor((start+end)/2);
|
||||
if (core.splitLines(canvas, content, mid).length < prefer_lines)
|
||||
end = mid;
|
||||
else
|
||||
start = mid + 1;
|
||||
}
|
||||
return mid;
|
||||
}
|
||||
// 存在手动换行:以最长的为准
|
||||
else {
|
||||
var w = 0;
|
||||
allLines.forEach(function (t) {
|
||||
w = Math.max(w, core.canvas[canvas].measureText(t).width);
|
||||
});
|
||||
return core.clamp(w, min_width, max_width);
|
||||
}
|
||||
}
|
||||
|
||||
////// 绘制一个对话框 //////
|
||||
@ -469,17 +500,36 @@ ui.prototype.drawTextBox = function(content, showAll) {
|
||||
core.status.boxAnimateObjs = [];
|
||||
core.clearMap('ui');
|
||||
|
||||
var left=7, right=416-left, width = right-left;
|
||||
var content_left = left + 25;
|
||||
if (id=='hero' || core.isset(icon)) content_left=left+63;
|
||||
|
||||
var validWidth = right-content_left - 10;
|
||||
var font = textfont + 'px Verdana';
|
||||
if (textAttribute.bold) font = "bold "+font;
|
||||
var realContent = content.replace(/(\r|\\r)(\[.*?])?/g, "");
|
||||
|
||||
var height = 20 + (textfont+5)*(core.splitLines("ui", realContent, validWidth, font).length+1)
|
||||
+ (id=='hero'?core.material.icons.hero.height-10:core.isset(name)?iconHeight-10:0);
|
||||
var leftSpace = 25, rightSpace = 12;
|
||||
if (core.isset(px) && core.isset(py)) leftSpace = 20;
|
||||
if (id=='hero' || core.isset(icon)) leftSpace = 62; // 行走图:15+32+15
|
||||
else if (core.isset(image)) leftSpace = 90; // 大头像:10+70+10
|
||||
var left = 7, right = 416 - left, width = right - left, validWidth = width - leftSpace - rightSpace;
|
||||
|
||||
// 对话框效果:改为动态计算
|
||||
if (core.isset(px) && core.isset(py)) {
|
||||
var min_width = 220 - leftSpace, max_width = validWidth;
|
||||
core.setFont('ui', font);
|
||||
validWidth = this.calTextBoxWidth('ui', realContent, min_width, max_width);
|
||||
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);
|
||||
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;
|
||||
if (id == 'hero')
|
||||
height = Math.max(height, core.material.icons.hero.height+50);
|
||||
else if (core.isset(icon))
|
||||
height = Math.max(height, iconHeight+50);
|
||||
else if (core.isset(image))
|
||||
height = Math.max(height, 90);
|
||||
|
||||
var xoffset = 11, yoffset = 16;
|
||||
|
||||
@ -539,10 +589,10 @@ ui.prototype.drawTextBox = function(content, showAll) {
|
||||
// 名称
|
||||
core.canvas.ui.textAlign = "left";
|
||||
|
||||
var content_top = top + 35;
|
||||
var content_top = top + 15 + textfont;
|
||||
if (core.isset(id)) {
|
||||
|
||||
content_top = top+57;
|
||||
content_top += (titlefont + 5);
|
||||
core.setFillStyle('ui', titleColor);
|
||||
core.setStrokeStyle('ui', titleColor);
|
||||
|
||||
@ -551,17 +601,17 @@ ui.prototype.drawTextBox = function(content, showAll) {
|
||||
core.setAlpha('ui', alpha);
|
||||
core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, heroHeight+2, null, 2);
|
||||
core.setAlpha('ui', 1);
|
||||
core.fillText('ui', name, content_left, top + 30, null, 'bold '+titlefont+'px Verdana');
|
||||
core.fillText('ui', name, content_left, top + 8 + titlefont, null, 'bold '+titlefont+'px Verdana');
|
||||
core.clearMap('ui', left + 15, top + 40, 32, heroHeight);
|
||||
core.fillRect('ui', left + 15, top + 40, 32, heroHeight, core.material.groundPattern);
|
||||
var heroIcon = core.material.icons.hero['down'];
|
||||
core.canvas.ui.drawImage(core.material.images.hero, heroIcon.stop * 32, heroIcon.loc * heroHeight, 32, heroHeight, left+15, top+40, 32, heroHeight);
|
||||
}
|
||||
else {
|
||||
core.fillText('ui', name, content_left, top + 30, null, 'bold '+titlefont+'px Verdana');
|
||||
core.fillText('ui', name, content_left, top + 8 + titlefont, null, 'bold '+titlefont+'px Verdana');
|
||||
if (core.isset(icon)) {
|
||||
core.setAlpha('ui', alpha);
|
||||
core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, iconHeight + 2, null, 2);
|
||||
core.strokeRect('ui', left + 15 - 1, top + 40-1, 34, iconHeight + 2, null, 2);
|
||||
core.setAlpha('ui', 1);
|
||||
core.status.boxAnimateObjs = [];
|
||||
core.status.boxAnimateObjs.push({
|
||||
@ -570,11 +620,13 @@ ui.prototype.drawTextBox = function(content, showAll) {
|
||||
'image': image,
|
||||
'pos': icon*iconHeight
|
||||
});
|
||||
|
||||
core.drawBoxAnimate();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (core.isset(image) && !core.isset(icon)) {
|
||||
core.canvas.ui.drawImage(image, 0, 0, image.width, image.height, left+10, top+10, 70, 70);
|
||||
}
|
||||
|
||||
var offsetx = content_left, offsety = content_top;
|
||||
core.setFont('ui', font);
|
||||
|
||||
@ -79,7 +79,7 @@ utils.prototype.splitLines = function(canvas, text, maxLength, font) {
|
||||
else {
|
||||
var toAdd = text.substring(last, i+1);
|
||||
var width = core.canvas[canvas].measureText(toAdd).width;
|
||||
if (width>maxLength) {
|
||||
if (core.isset(maxLength) && width>maxLength) {
|
||||
contents.push(text.substring(last, i));
|
||||
last=i;
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ main.floors.sample0=
|
||||
[ 88, 89, 90, 91, 92, 93, 94, 2, 81, 82, 83, 84, 86]
|
||||
],
|
||||
"firstArrive": [
|
||||
{"type": "setText", "background": "winskin.png"},
|
||||
"\t[样板提示]首次到达某层可以触发 firstArrive 事件,该事件可类似于RMXP中的“自动执行脚本”。\n\n本事件支持一切的事件类型,常常用来触发对话,例如:",
|
||||
"\t[hero]\b[up,hero]我是谁?我从哪来?我又要到哪去?",
|
||||
"\t[仙子,fairy]你问我...?我也不知道啊...",
|
||||
|
||||
7
更新说明.txt
7
更新说明.txt
@ -2,13 +2,16 @@
|
||||
|
||||
怪物和NPC的行走图和朝向问题(详见文档)
|
||||
可以引入WindowSkin作为对话框的背景素材
|
||||
\r可以动态调整剧情文本的颜色
|
||||
允许使用\t[标题,1.png]来绘制大头像图
|
||||
对话框的宽度可以根据文本长度自动调整
|
||||
\r[red]可以动态调整剧情文本的颜色
|
||||
升级事件改用事件编辑器完成
|
||||
每层楼都增添该层的并行事件处理
|
||||
新增快捷键:N返回标题;P查看评论;O打开工程
|
||||
道具可以设置是否在回放时绘制道具栏或直接使用
|
||||
追加素材一次可以追加多个
|
||||
可以同时异步移动/跳跃勇士和多个NPC
|
||||
可以同时异步移动两张或以上的图片了
|
||||
追加素材一次可以追加多个
|
||||
菜单栏中新增虚拟键盘的弹出
|
||||
修复所有已知Bug;部分细节优化
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user