mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-02-28 17:37:07 +08:00
feat: 新的渲染系统
This commit is contained in:
parent
af38d2e47e
commit
2f8fbd375c
@ -802,11 +802,19 @@ control.prototype.setHeroMoveInterval = function (callback) {
|
|||||||
if (core.status.replay.speed > 6) toAdd = 4;
|
if (core.status.replay.speed > 6) toAdd = 4;
|
||||||
if (core.status.replay.speed > 12) toAdd = 8;
|
if (core.status.replay.speed > 12) toAdd = 8;
|
||||||
|
|
||||||
|
Mota.r(() => {
|
||||||
|
const render = Mota.require('module', 'Render').heroRender;
|
||||||
|
render.move(true);
|
||||||
|
});
|
||||||
|
|
||||||
core.interval.heroMoveInterval = window.setInterval(function () {
|
core.interval.heroMoveInterval = window.setInterval(function () {
|
||||||
|
render.offset += toAdd * 4;
|
||||||
core.status.heroMoving += toAdd;
|
core.status.heroMoving += toAdd;
|
||||||
if (core.status.heroMoving >= 8) {
|
if (core.status.heroMoving >= 8) {
|
||||||
clearInterval(core.interval.heroMoveInterval);
|
clearInterval(core.interval.heroMoveInterval);
|
||||||
core.status.heroMoving = 0;
|
core.status.heroMoving = 0;
|
||||||
|
render.offset = 0;
|
||||||
|
render.move(false);
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
}
|
}
|
||||||
}, ((core.values.moveSpeed / 8) * toAdd) / core.status.replay.speed);
|
}, ((core.values.moveSpeed / 8) * toAdd) / core.status.replay.speed);
|
||||||
@ -1003,22 +1011,32 @@ control.prototype.tryMoveDirectly = function (destX, destY) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
////// 绘制勇士 //////
|
////// 绘制勇士 //////
|
||||||
control.prototype.drawHero = function (status, offset, frame) {
|
control.prototype.drawHero = function (status, offset = 0, frame) {
|
||||||
if (!core.isPlaying() || !core.status.floorId || core.status.gameOver)
|
if (!core.isPlaying() || !core.status.floorId || core.status.gameOver)
|
||||||
return;
|
return;
|
||||||
|
if (main.mode === 'play') {
|
||||||
|
Mota.require('module', 'Render').heroRender.draw();
|
||||||
|
if (!core.hasFlag('__lockViewport__')) {
|
||||||
|
const { x, y, direction } = core.status.hero.loc;
|
||||||
|
var way = core.utils.scan2[direction];
|
||||||
|
var dx = way.x,
|
||||||
|
dy = way.y;
|
||||||
|
var offsetX =
|
||||||
|
typeof offset == 'number' ? dx * offset : offset.x || 0;
|
||||||
|
var offsetY =
|
||||||
|
typeof offset == 'number' ? dy * offset : offset.y || 0;
|
||||||
|
offset = { x: offsetX, y: offsetY, offset: offset };
|
||||||
|
this._drawHero_updateViewport(x, y, offset);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var x = core.getHeroLoc('x'),
|
var x = core.getHeroLoc('x'),
|
||||||
y = core.getHeroLoc('y'),
|
y = core.getHeroLoc('y'),
|
||||||
direction = core.getHeroLoc('direction');
|
direction = core.getHeroLoc('direction');
|
||||||
status = status || 'stop';
|
status = status || 'stop';
|
||||||
if (!offset) offset = 0;
|
if (!offset) offset = 0;
|
||||||
|
|
||||||
var way = core.utils.scan2[direction];
|
|
||||||
var dx = way.x,
|
|
||||||
dy = way.y;
|
|
||||||
var offsetX = typeof offset == 'number' ? dx * offset : offset.x || 0;
|
|
||||||
var offsetY = typeof offset == 'number' ? dy * offset : offset.y || 0;
|
|
||||||
offset = { x: offsetX, y: offsetY, offset: offset };
|
|
||||||
|
|
||||||
core.clearAutomaticRouteNode(x + dx, y + dy);
|
core.clearAutomaticRouteNode(x + dx, y + dy);
|
||||||
core.clearMap('hero');
|
core.clearMap('hero');
|
||||||
core.status.heroCenter.px = 32 * x + offsetX + 16;
|
core.status.heroCenter.px = 32 * x + offsetX + 16;
|
||||||
@ -1030,9 +1048,6 @@ control.prototype.drawHero = function (status, offset, frame) {
|
|||||||
delete core.canvas.hero._px;
|
delete core.canvas.hero._px;
|
||||||
delete core.canvas.hero._py;
|
delete core.canvas.hero._py;
|
||||||
core.status.preview.enabled = false;
|
core.status.preview.enabled = false;
|
||||||
if (!core.hasFlag('__lockViewport__')) {
|
|
||||||
this._drawHero_updateViewport(x, y, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._drawHero_draw(direction, x, y, status, offset, frame);
|
this._drawHero_draw(direction, x, y, status, offset, frame);
|
||||||
};
|
};
|
||||||
@ -3499,75 +3514,6 @@ control.prototype.hideStatusBar = function (showToolbox) {
|
|||||||
////// 改变工具栏为按钮1-8 //////
|
////// 改变工具栏为按钮1-8 //////
|
||||||
control.prototype.setToolbarButton = function (useButton) {
|
control.prototype.setToolbarButton = function (useButton) {
|
||||||
// Deprecated. Use CustomToolbar instead.
|
// Deprecated. Use CustomToolbar instead.
|
||||||
return;
|
|
||||||
if (!core.domStyle.showStatusBar) {
|
|
||||||
// 隐藏状态栏时检查竖屏
|
|
||||||
if (!core.domStyle.isVertical && !core.flags.extendToolbar) {
|
|
||||||
for (var i = 0; i < core.dom.tools.length; ++i)
|
|
||||||
core.dom.tools[i].style.display = 'none';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!core.hasFlag('showToolbox')) return;
|
|
||||||
else core.dom.tools.hard.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useButton == null) useButton = core.domStyle.toolbarBtn;
|
|
||||||
if (!core.domStyle.isVertical && !core.flags.extendToolbar)
|
|
||||||
useButton = false;
|
|
||||||
core.domStyle.toolbarBtn = useButton;
|
|
||||||
|
|
||||||
if (useButton) {
|
|
||||||
[
|
|
||||||
'book',
|
|
||||||
'fly',
|
|
||||||
'toolbox',
|
|
||||||
'keyboard',
|
|
||||||
'shop',
|
|
||||||
'save',
|
|
||||||
'load',
|
|
||||||
'settings'
|
|
||||||
].forEach(function (t) {
|
|
||||||
core.statusBar.image[t].style.display = 'none';
|
|
||||||
});
|
|
||||||
[
|
|
||||||
'btn1',
|
|
||||||
'btn2',
|
|
||||||
'btn3',
|
|
||||||
'btn4',
|
|
||||||
'btn5',
|
|
||||||
'btn6',
|
|
||||||
'btn7',
|
|
||||||
'btn8'
|
|
||||||
].forEach(function (t) {
|
|
||||||
core.statusBar.image[t].style.display = 'block';
|
|
||||||
});
|
|
||||||
main.statusBar.image.btn8.style.filter = core.getLocalStorage('altKey')
|
|
||||||
? 'sepia(1) contrast(1.5)'
|
|
||||||
: '';
|
|
||||||
} else {
|
|
||||||
[
|
|
||||||
'btn1',
|
|
||||||
'btn2',
|
|
||||||
'btn3',
|
|
||||||
'btn4',
|
|
||||||
'btn5',
|
|
||||||
'btn6',
|
|
||||||
'btn7',
|
|
||||||
'btn8'
|
|
||||||
].forEach(function (t) {
|
|
||||||
core.statusBar.image[t].style.display = 'none';
|
|
||||||
});
|
|
||||||
['book', 'fly', 'toolbox', 'save', 'load', 'settings'].forEach(
|
|
||||||
function (t) {
|
|
||||||
core.statusBar.image[t].style.display = 'block';
|
|
||||||
}
|
|
||||||
);
|
|
||||||
core.statusBar.image.keyboard.style.display =
|
|
||||||
core.statusBar.image.shop.style.display =
|
|
||||||
core.domStyle.isVertical || core.flags.extendToolbar
|
|
||||||
? 'block'
|
|
||||||
: 'none';
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////// ------ resize处理 ------ //
|
////// ------ resize处理 ------ //
|
||||||
@ -3789,16 +3735,4 @@ control.prototype._resize_toolBar = function (obj) {
|
|||||||
|
|
||||||
control.prototype._resize_tools = function (obj) {
|
control.prototype._resize_tools = function (obj) {
|
||||||
// Deprecated. Use CustomToolbar instead.
|
// Deprecated. Use CustomToolbar instead.
|
||||||
// var toolsHeight = 32 * core.domStyle.scale;
|
|
||||||
// var toolsMarginLeft;
|
|
||||||
// toolsMarginLeft = (core._HALF_WIDTH_ - 3) * 3 * core.domStyle.scale;
|
|
||||||
// for (var i = 0; i < core.dom.tools.length; ++i) {
|
|
||||||
// var style = core.dom.tools[i].style;
|
|
||||||
// style.height = toolsHeight + 'px';
|
|
||||||
// style.marginLeft = toolsMarginLeft + 'px';
|
|
||||||
// style.marginTop = 3 * core.domStyle.scale + 'px';
|
|
||||||
// }
|
|
||||||
// core.dom.hard.style.lineHeight = toolsHeight + 'px';
|
|
||||||
// core.dom.hard.style.width =
|
|
||||||
// obj.outerWidth - 9 * toolsMarginLeft - 8.5 * toolsHeight - 12 + 'px';
|
|
||||||
};
|
};
|
||||||
|
@ -843,6 +843,7 @@ events.prototype._changeFloor_afterChange = function (info, callback) {
|
|||||||
|
|
||||||
events.prototype.changingFloor = function (floorId, heroLoc) {
|
events.prototype.changingFloor = function (floorId, heroLoc) {
|
||||||
this.eventdata.changingFloor(floorId, heroLoc);
|
this.eventdata.changingFloor(floorId, heroLoc);
|
||||||
|
Mota.require('var', 'hook').emit('changingFloor', floorId, heroLoc);
|
||||||
};
|
};
|
||||||
|
|
||||||
////// 转换楼层结束的事件 //////
|
////// 转换楼层结束的事件 //////
|
||||||
@ -4252,6 +4253,7 @@ events.prototype._vibrate_update = function (shakeInfo) {
|
|||||||
/////// 使用事件让勇士移动。这个函数将不会触发任何事件 //////
|
/////// 使用事件让勇士移动。这个函数将不会触发任何事件 //////
|
||||||
events.prototype.eventMoveHero = function (steps, time, callback) {
|
events.prototype.eventMoveHero = function (steps, time, callback) {
|
||||||
time = time || core.values.moveSpeed;
|
time = time || core.values.moveSpeed;
|
||||||
|
// const render = Mota.require('module', 'Render').heroRender;
|
||||||
var step = 0,
|
var step = 0,
|
||||||
moveSteps = (steps || [])
|
moveSteps = (steps || [])
|
||||||
.map(function (t) {
|
.map(function (t) {
|
||||||
@ -4275,9 +4277,11 @@ events.prototype.eventMoveHero = function (steps, time, callback) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
core.status.heroMoving = -1;
|
core.status.heroMoving = -1;
|
||||||
|
// render.move(false);
|
||||||
var _run = function () {
|
var _run = function () {
|
||||||
var cb = function () {
|
var cb = function () {
|
||||||
core.status.heroMoving = 0;
|
core.status.heroMoving = 0;
|
||||||
|
// render.move(false);
|
||||||
core.drawHero();
|
core.drawHero();
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
};
|
};
|
||||||
@ -4339,15 +4343,18 @@ events.prototype.jumpHero = function (ex, ey, time, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
events.prototype._jumpHero_doJump = function (jumpInfo, callback) {
|
events.prototype._jumpHero_doJump = function (jumpInfo, callback) {
|
||||||
|
// const render = Mota.require('module', 'Render').heroRender;
|
||||||
var cb = function () {
|
var cb = function () {
|
||||||
core.setHeroLoc('x', jumpInfo.ex);
|
core.setHeroLoc('x', jumpInfo.ex);
|
||||||
core.setHeroLoc('y', jumpInfo.ey);
|
core.setHeroLoc('y', jumpInfo.ey);
|
||||||
|
render.move(false);
|
||||||
core.status.heroMoving = 0;
|
core.status.heroMoving = 0;
|
||||||
core.drawHero();
|
core.drawHero();
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
};
|
};
|
||||||
|
|
||||||
core.status.heroMoving = -1;
|
core.status.heroMoving = -1;
|
||||||
|
// render.move(false);
|
||||||
var animate = window.setInterval(function () {
|
var animate = window.setInterval(function () {
|
||||||
if (jumpInfo.jump_count > 0) core.events._jumpHero_jumping(jumpInfo);
|
if (jumpInfo.jump_count > 0) core.events._jumpHero_jumping(jumpInfo);
|
||||||
else {
|
else {
|
||||||
@ -4386,6 +4393,7 @@ events.prototype.setHeroIcon = function (name, noDraw) {
|
|||||||
core.material.images.hero = img;
|
core.material.images.hero = img;
|
||||||
core.material.icons.hero.width = img.width / 4;
|
core.material.icons.hero.width = img.width / 4;
|
||||||
core.material.icons.hero.height = img.height / 4;
|
core.material.icons.hero.height = img.height / 4;
|
||||||
|
// Mota.require('module', 'Render').heroRender.setHero();
|
||||||
if (!noDraw) core.drawHero();
|
if (!noDraw) core.drawHero();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -738,28 +738,29 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"need": "100000",
|
"need": "100000",
|
||||||
"title": "中级智人",
|
"title": "高级智人",
|
||||||
"clear": true,
|
"clear": true,
|
||||||
"action": [
|
"action": [
|
||||||
{
|
{
|
||||||
"type": "setValue",
|
"type": "setValue",
|
||||||
"name": "status:mdef",
|
"name": "status:mdef",
|
||||||
"operator": "+=",
|
"operator": "+=",
|
||||||
"value": "2000"
|
"value": "10000"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "setValue",
|
"type": "setValue",
|
||||||
"name": "status:atk",
|
"name": "status:atk",
|
||||||
"operator": "+=",
|
"operator": "+=",
|
||||||
"value": "25"
|
"value": "250"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "setValue",
|
"type": "setValue",
|
||||||
"name": "status:def",
|
"name": "status:def",
|
||||||
"operator": "+=",
|
"operator": "+=",
|
||||||
"value": "25"
|
"value": "250"
|
||||||
},
|
},
|
||||||
"恭喜升级!攻防+25,智慧+2000!"
|
"恭喜升级!攻防+250,智慧+10000!",
|
||||||
|
"这是这个游戏的最后一级,第三章的玩法会改变,不再设置等级"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -16,7 +16,11 @@ main.floors.MT59=
|
|||||||
"firstArrive": [],
|
"firstArrive": [],
|
||||||
"eachArrive": [],
|
"eachArrive": [],
|
||||||
"parallelDo": "",
|
"parallelDo": "",
|
||||||
"events": {},
|
"events": {
|
||||||
|
"12,5": [
|
||||||
|
"注意这个boss现在不是必打的,只要能打过去苍蓝殿上方区域的那个黄卫兵就能去上面的区域了,之后回头再来清这个boss也可以"
|
||||||
|
]
|
||||||
|
},
|
||||||
"changeFloor": {
|
"changeFloor": {
|
||||||
"14,7": {
|
"14,7": {
|
||||||
"floorId": "MT58",
|
"floorId": "MT58",
|
||||||
@ -113,7 +117,7 @@ main.floors.MT59=
|
|||||||
[648,491, 28,491,648, 0,648, 0,648,648,648,648, 0, 29,648],
|
[648,491, 28,491,648, 0,648, 0,648,648,648,648, 0, 29,648],
|
||||||
[648, 27,468, 27,648,487,648, 21,648, 27, 0,648, 27, 0,648],
|
[648, 27,468, 27,648,487,648, 21,648, 27, 0,648, 27, 0,648],
|
||||||
[648, 0, 28, 0, 85, 0,648,487,648, 0, 29,657, 0, 28,648],
|
[648, 0, 28, 0, 85, 0,648,487,648, 0, 29,657, 0, 28,648],
|
||||||
[648,648,648,648,648,390,648,390,648,484,648,648,648,648,648],
|
[648,648,648,648,648,390,648,390,648,484,648,648,129,648,648],
|
||||||
[648,482, 0,482,648, 0,249, 0,648,539,648,482, 0,482,648],
|
[648,482, 0,482,648, 0,249, 0,648,539,648,482, 0,482,648],
|
||||||
[648, 0,666, 0,492,403,648,648,648, 0,492, 0,381, 0, 94],
|
[648, 0,666, 0,492,403,648,648,648, 0,492, 0,381, 0, 94],
|
||||||
[648,482, 0,482,648, 0,249, 0,648,539,648,482, 0,482,648],
|
[648,482, 0,482,648, 0,249, 0,648,539,648,482, 0,482,648],
|
||||||
|
@ -21,10 +21,10 @@ main.floors.MT69=
|
|||||||
"提示一个本地图的较优解法:从此处直接向右走,然后反过来把红骑士杀了,就基本上没光环了"
|
"提示一个本地图的较优解法:从此处直接向右走,然后反过来把红骑士杀了,就基本上没光环了"
|
||||||
],
|
],
|
||||||
"2,7": [
|
"2,7": [
|
||||||
"中间的那个木牌会提示一种较优解法"
|
"不要被这一层吓到了(,实际上光环只有四个黄光环,其他的都是黄光环产生的。如果实在想不到解法,中间的那个木牌会提示一种较优解法"
|
||||||
],
|
],
|
||||||
"6,13": [
|
"6,13": [
|
||||||
"中间的那个木牌会提示一种较优解法"
|
"不要被这一层吓到了(,实际上光环只有四个黄光环,其他的都是黄光环产生的。如果实在想不到解法,中间的那个木牌会提示一种较优解法"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"changeFloor": {
|
"changeFloor": {
|
||||||
|
@ -29,6 +29,13 @@ main.floors.MT73=
|
|||||||
7,
|
7,
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"7,0": {
|
||||||
|
"floorId": "MT74",
|
||||||
|
"loc": [
|
||||||
|
7,
|
||||||
|
14
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"beforeBattle": {},
|
"beforeBattle": {},
|
||||||
|
@ -17,7 +17,22 @@ main.floors.MT74=
|
|||||||
"eachArrive": [],
|
"eachArrive": [],
|
||||||
"parallelDo": "",
|
"parallelDo": "",
|
||||||
"events": {},
|
"events": {},
|
||||||
"changeFloor": {},
|
"changeFloor": {
|
||||||
|
"7,0": {
|
||||||
|
"floorId": "MT75",
|
||||||
|
"loc": [
|
||||||
|
7,
|
||||||
|
14
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"7,14": {
|
||||||
|
"floorId": "MT73",
|
||||||
|
"loc": [
|
||||||
|
7,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"beforeBattle": {},
|
"beforeBattle": {},
|
||||||
"afterBattle": {},
|
"afterBattle": {},
|
||||||
"afterGetItem": {},
|
"afterGetItem": {},
|
||||||
@ -26,21 +41,21 @@ main.floors.MT74=
|
|||||||
"cannotMove": {},
|
"cannotMove": {},
|
||||||
"cannotMoveIn": {},
|
"cannotMoveIn": {},
|
||||||
"map": [
|
"map": [
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648,648,648,648,648,648, 91,648,648,648,648,648,648,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,430,472,420,648, 0, 0, 0, 0, 0,648,420,472,430,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648, 85,648,648, 0, 0, 0, 0, 0,648,648, 85,648,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648, 0, 0, 0,648, 0, 0, 0, 0, 0,648, 0, 0, 0,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648, 0,487, 0,648, 0, 0, 0, 0, 0,648, 0,487, 0,648],
|
||||||
[ 0, 0, 0, 0, 0,103, 0, 0, 0,103, 0, 0, 0, 0, 0],
|
[648, 0, 0, 0,648,103, 0, 0, 0,103,648, 0, 0, 0,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648,492,648,648, 0, 0, 0, 0, 0,648,648,492,648,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[ 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648,492,648,648, 0, 0, 0, 0, 0,648,648,492,648,648],
|
||||||
[ 0, 0, 0, 0, 0,103, 0, 0, 0,103, 0, 0, 0, 0, 0],
|
[648, 0, 0, 0,648,103, 0, 0, 0,103,648, 0, 0, 0,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648, 0,487, 0,648, 0, 0, 0, 0, 0,648, 0,487, 0,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648, 0, 0, 0,648, 0, 0, 0, 0, 0,648, 0, 0, 0,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648, 85,648,648, 0, 0, 0, 0, 0,648,648, 85,648,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,430,472,420,648, 0, 0, 0, 0, 0,648,420,472,430,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
[648,648,648,648,648,648,648, 93,648,648,648,648,648,648,648]
|
||||||
],
|
],
|
||||||
"bgmap": [
|
"bgmap": [
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
@ -17,7 +17,15 @@ main.floors.MT75=
|
|||||||
"eachArrive": [],
|
"eachArrive": [],
|
||||||
"parallelDo": "",
|
"parallelDo": "",
|
||||||
"events": {},
|
"events": {},
|
||||||
"changeFloor": {},
|
"changeFloor": {
|
||||||
|
"7,14": {
|
||||||
|
"floorId": "MT74",
|
||||||
|
"loc": [
|
||||||
|
7,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"beforeBattle": {},
|
"beforeBattle": {},
|
||||||
"afterBattle": {},
|
"afterBattle": {},
|
||||||
"afterGetItem": {},
|
"afterGetItem": {},
|
||||||
@ -26,21 +34,21 @@ main.floors.MT75=
|
|||||||
"cannotMove": {},
|
"cannotMove": {},
|
||||||
"cannotMoveIn": {},
|
"cannotMoveIn": {},
|
||||||
"map": [
|
"map": [
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648,648,648,648,648,648,648,648,648,648,648,648,648,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,491,491,494,491,494, 0, 0, 0,494,491,494,491,491,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648,648,648,648,648, 0, 0, 0,648,648,648,648,648,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,484,484,492,484,492, 0, 0, 0,492,484,492,484,484,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648,648,648,648,648, 0, 0, 0,648,648,648,648,648,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648, 0, 0, 0, 0,103, 0, 0, 0,103, 0, 0, 0, 0,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[ 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648, 0, 0, 0, 0,103, 0, 0, 0,103, 0, 0, 0, 0,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648,648,648,648,648, 0, 0, 0,648,648,648,648,648,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,484,484,492,484,492, 0, 0, 0,492,484,492,484,484,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,648,648,648,648,648, 0, 0, 0,648,648,648,648,648,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[648,491,491,494,491,494, 0, 0, 0,494,491,494,491,491,648],
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
[648,648,648,648,648,648,648, 93,648,648,648,648,648,648,648]
|
||||||
],
|
],
|
||||||
"bgmap": [
|
"bgmap": [
|
||||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
@ -226,27 +226,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
|||||||
if (core.flags.flyRecordPosition) {
|
if (core.flags.flyRecordPosition) {
|
||||||
loc = core.getFlag('__leaveLoc__', {})[toId] || null;
|
loc = core.getFlag('__leaveLoc__', {})[toId] || null;
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
core.status.maps[toId].flyPoint != null &&
|
|
||||||
core.status.maps[toId].flyPoint.length == 2
|
|
||||||
) {
|
|
||||||
loc = {
|
|
||||||
x: core.status.maps[toId].flyPoint[0],
|
|
||||||
y: core.status.maps[toId].flyPoint[1]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (loc == null) {
|
|
||||||
// 获得两个楼层的索引,以决定是上楼梯还是下楼梯
|
|
||||||
var fromIndex = core.floorIds.indexOf(fromId),
|
|
||||||
toIndex = core.floorIds.indexOf(toId);
|
|
||||||
var stair = fromIndex <= toIndex ? 'downFloor' : 'upFloor';
|
|
||||||
// 地下层:同层传送至上楼梯
|
|
||||||
if (
|
|
||||||
fromIndex == toIndex &&
|
|
||||||
core.status.maps[fromId].underGround
|
|
||||||
)
|
|
||||||
stair = 'upFloor';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记录录像
|
// 记录录像
|
||||||
core.status.route.push('fly:' + toId);
|
core.status.route.push('fly:' + toId);
|
||||||
|
@ -1048,7 +1048,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
|
|||||||
},
|
},
|
||||||
"I472": {
|
"I472": {
|
||||||
"cls": "items",
|
"cls": "items",
|
||||||
"name": "新物品",
|
"name": "传奇绿宝石",
|
||||||
"text": ",防御+${core.values.blueGem}",
|
"text": ",防御+${core.values.blueGem}",
|
||||||
"itemEffect": "core.status.hero.mdef += Math.round(640 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1))",
|
"itemEffect": "core.status.hero.mdef += Math.round(640 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1))",
|
||||||
"itemEffectTip": ",智慧+${Math.round(640 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1))}",
|
"itemEffectTip": ",智慧+${Math.round(640 * core.status.thisMap.ratio / core.getFlag(\"hard\") * (Mota.Plugin.require('skillTree_g').getSkillLevel(12) / 20 + 1))}",
|
||||||
|
@ -392,6 +392,7 @@ p#name {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#hero {
|
#hero {
|
||||||
|
display: none;
|
||||||
z-index: 40;
|
z-index: 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
/** 是否是高清画布 */
|
/** 是否是高清画布 */
|
||||||
highResolution: boolean = true;
|
highResolution: boolean = true;
|
||||||
|
|
||||||
|
scale: number = 1;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -41,6 +43,7 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
if (this.autoScale && this.highResolution) {
|
if (this.autoScale && this.highResolution) {
|
||||||
ratio *= core.domStyle.scale;
|
ratio *= core.domStyle.scale;
|
||||||
}
|
}
|
||||||
|
this.scale = ratio;
|
||||||
this.canvas.width = width * ratio;
|
this.canvas.width = width * ratio;
|
||||||
this.canvas.height = height * ratio;
|
this.canvas.height = height * ratio;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
@ -82,7 +85,13 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
newCanvas.setHD(canvas.highResolution);
|
newCanvas.setHD(canvas.highResolution);
|
||||||
newCanvas.withGameScale(canvas.autoScale);
|
newCanvas.withGameScale(canvas.autoScale);
|
||||||
newCanvas.size(canvas.width, canvas.height);
|
newCanvas.size(canvas.width, canvas.height);
|
||||||
newCanvas.ctx.drawImage(canvas.canvas, 0, 0);
|
newCanvas.ctx.drawImage(
|
||||||
|
canvas.canvas,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height
|
||||||
|
);
|
||||||
return newCanvas;
|
return newCanvas;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,6 +153,7 @@ export class MotaCanvas2D extends MotaOffscreenCanvas2D {
|
|||||||
this.canvas.style.width = `${width}px`;
|
this.canvas.style.width = `${width}px`;
|
||||||
this.canvas.style.height = `${height}px`;
|
this.canvas.style.height = `${height}px`;
|
||||||
}
|
}
|
||||||
|
this.scale = ratio;
|
||||||
this.canvas.width = width * ratio;
|
this.canvas.width = width * ratio;
|
||||||
this.canvas.height = height * ratio;
|
this.canvas.height = height * ratio;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
|
@ -114,18 +114,18 @@ Mota.require('var', 'hook').once('reset', () => {
|
|||||||
Shadow.update(true);
|
Shadow.update(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Mota.rewrite(core.events, 'changingFloor', 'add', (_, floorId) => {
|
|
||||||
if (!main.replayChecking) {
|
|
||||||
Shadow.clearBuffer();
|
|
||||||
Shadow.update();
|
|
||||||
setCanvasFilterByFloorId(floorId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Mota.rewrite(core.control, 'loadData', 'add', () => {
|
Mota.rewrite(core.control, 'loadData', 'add', () => {
|
||||||
if (!main.replayChecking) {
|
if (!main.replayChecking) {
|
||||||
Shadow.update(true);
|
Shadow.update(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Mota.require('var', 'hook').on('changingFloor', (floorId) => {
|
||||||
|
if (!main.replayChecking) {
|
||||||
|
Shadow.clearBuffer();
|
||||||
|
Shadow.update();
|
||||||
|
setCanvasFilterByFloorId(floorId);
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
// 深度测试着色器
|
// 深度测试着色器
|
||||||
|
@ -60,6 +60,15 @@ import { ResourceController } from './loader/controller';
|
|||||||
import { logger } from './common/logger';
|
import { logger } from './common/logger';
|
||||||
import { Danmaku } from './main/custom/danmaku';
|
import { Danmaku } from './main/custom/danmaku';
|
||||||
import * as Shadow from './fx/shadow';
|
import * as Shadow from './fx/shadow';
|
||||||
|
import { MotaCanvas2D } from './fx/canvas2d';
|
||||||
|
import * as portal from './fx/portal';
|
||||||
|
import { heroRender } from './render/hero';
|
||||||
|
import { MotaRenderer } from './render/render';
|
||||||
|
import { Container } from './render/container';
|
||||||
|
import { Sprite } from './render/sprite';
|
||||||
|
import { Camera } from './render/camera';
|
||||||
|
import { Image, Text } from './render/preset/misc';
|
||||||
|
import { RenderItem } from './render/item';
|
||||||
|
|
||||||
// ----- 类注册
|
// ----- 类注册
|
||||||
Mota.register('class', 'AudioPlayer', AudioPlayer);
|
Mota.register('class', 'AudioPlayer', AudioPlayer);
|
||||||
@ -78,6 +87,7 @@ Mota.register('class', 'UiController', UiController);
|
|||||||
Mota.register('class', 'MComponent', MComponent);
|
Mota.register('class', 'MComponent', MComponent);
|
||||||
Mota.register('class', 'ResourceController', ResourceController);
|
Mota.register('class', 'ResourceController', ResourceController);
|
||||||
Mota.register('class', 'Danmaku', Danmaku);
|
Mota.register('class', 'Danmaku', Danmaku);
|
||||||
|
Mota.register('class', 'MotaCanvas2D', MotaCanvas2D);
|
||||||
// ----- 函数注册
|
// ----- 函数注册
|
||||||
Mota.register('fn', 'm', m);
|
Mota.register('fn', 'm', m);
|
||||||
Mota.register('fn', 'unwrapBinary', unwarpBinary);
|
Mota.register('fn', 'unwrapBinary', unwarpBinary);
|
||||||
@ -133,6 +143,19 @@ Mota.register('module', 'UIComponents', {
|
|||||||
});
|
});
|
||||||
Mota.register('module', 'MCGenerator', MCGenerator);
|
Mota.register('module', 'MCGenerator', MCGenerator);
|
||||||
Mota.register('module', 'Shadow', Shadow);
|
Mota.register('module', 'Shadow', Shadow);
|
||||||
|
Mota.register('module', 'Effect', {
|
||||||
|
Portal: portal
|
||||||
|
});
|
||||||
|
Mota.register('module', 'Render', {
|
||||||
|
heroRender,
|
||||||
|
MotaRenderer,
|
||||||
|
Container,
|
||||||
|
Sprite,
|
||||||
|
Camera,
|
||||||
|
Text,
|
||||||
|
Image,
|
||||||
|
RenderItem
|
||||||
|
});
|
||||||
|
|
||||||
main.renderLoaded = true;
|
main.renderLoaded = true;
|
||||||
Mota.require('var', 'hook').emit('renderLoaded');
|
Mota.require('var', 'hook').emit('renderLoaded');
|
||||||
|
@ -17,3 +17,5 @@ export interface ResponseBase {
|
|||||||
code: number;
|
code: number;
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CSSObj = Partial<Record<CanParseCss, string>>;
|
||||||
|
@ -27,6 +27,8 @@ import {
|
|||||||
FolderOpenOutlined,
|
FolderOpenOutlined,
|
||||||
LayoutOutlined,
|
LayoutOutlined,
|
||||||
MessageOutlined,
|
MessageOutlined,
|
||||||
|
RetweetOutlined,
|
||||||
|
RollbackOutlined,
|
||||||
SwapOutlined
|
SwapOutlined
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
import { generateKeyboardEvent } from '../custom/keyboard';
|
import { generateKeyboardEvent } from '../custom/keyboard';
|
||||||
@ -888,7 +890,7 @@ Mota.require('var', 'hook').once('reset', () => {
|
|||||||
() => {
|
() => {
|
||||||
core.doSL('autoSave', 'load');
|
core.doSL('autoSave', 'load');
|
||||||
},
|
},
|
||||||
h(BackwardOutlined)
|
h(RollbackOutlined)
|
||||||
);
|
);
|
||||||
CustomToolbar.misc.register(
|
CustomToolbar.misc.register(
|
||||||
'redo',
|
'redo',
|
||||||
@ -896,7 +898,7 @@ Mota.require('var', 'hook').once('reset', () => {
|
|||||||
() => {
|
() => {
|
||||||
core.doSL('autoSave', 'reload');
|
core.doSL('autoSave', 'reload');
|
||||||
},
|
},
|
||||||
h(SwapOutlined)
|
h(RetweetOutlined)
|
||||||
);
|
);
|
||||||
CustomToolbar.misc.register(
|
CustomToolbar.misc.register(
|
||||||
'setting',
|
'setting',
|
||||||
|
@ -474,6 +474,7 @@ mainSetting
|
|||||||
new MotaSetting()
|
new MotaSetting()
|
||||||
.register('paraLight', '野外阴影', true, COM.Boolean)
|
.register('paraLight', '野外阴影', true, COM.Boolean)
|
||||||
.register('frag', '打怪特效', true, COM.Boolean)
|
.register('frag', '打怪特效', true, COM.Boolean)
|
||||||
|
.register('portalParticle', '传送门特效', true, COM.Boolean)
|
||||||
)
|
)
|
||||||
.register(
|
.register(
|
||||||
'ui',
|
'ui',
|
||||||
@ -512,6 +513,7 @@ loading.once('coreInit', () => {
|
|||||||
'utils.autoScale': !!storage.getValue('utils.autoScale', true),
|
'utils.autoScale': !!storage.getValue('utils.autoScale', true),
|
||||||
'fx.paraLight': !!storage.getValue('fx.paraLight', true),
|
'fx.paraLight': !!storage.getValue('fx.paraLight', true),
|
||||||
'fx.frag': !!storage.getValue('fx.frag', true),
|
'fx.frag': !!storage.getValue('fx.frag', true),
|
||||||
|
'fx.portalParticle': !!storage.getValue('fx.portalParticle', true),
|
||||||
'ui.mapScale': storage.getValue(
|
'ui.mapScale': storage.getValue(
|
||||||
'ui.mapScale',
|
'ui.mapScale',
|
||||||
isMobile ? 300 : Math.floor(window.innerWidth / 600) * 50
|
isMobile ? 300 : Math.floor(window.innerWidth / 600) * 50
|
||||||
@ -565,7 +567,8 @@ mainSetting
|
|||||||
.setDescription('ui.danmaku', '是否显示弹幕')
|
.setDescription('ui.danmaku', '是否显示弹幕')
|
||||||
.setDescription('ui.danmakuSpeed', '弹幕速度,刷新或开关弹幕显示后起效')
|
.setDescription('ui.danmakuSpeed', '弹幕速度,刷新或开关弹幕显示后起效')
|
||||||
.setDescription('screen.fontSizeStatus', `修改状态栏的字体大小`)
|
.setDescription('screen.fontSizeStatus', `修改状态栏的字体大小`)
|
||||||
.setDescription('screen.blur', '打开任意ui界面时是否有背景虚化效果,移动端打开后可能会有掉帧或者发热现象。关闭ui后生效');
|
.setDescription('screen.blur', '打开任意ui界面时是否有背景虚化效果,移动端打开后可能会有掉帧或者发热现象。关闭ui后生效')
|
||||||
|
.setDescription('fx.portalParticle', '是否启用苍蓝之殿的传送门粒子特效,启用后可能对性能及设备发热有所影响');
|
||||||
|
|
||||||
function setFontSize() {
|
function setFontSize() {
|
||||||
const absoluteSize = storage.getValue(
|
const absoluteSize = storage.getValue(
|
||||||
|
184
src/core/render/camera.ts
Normal file
184
src/core/render/camera.ts
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import { ReadonlyMat3, ReadonlyVec3, mat3, vec2, vec3 } from 'gl-matrix';
|
||||||
|
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
|
||||||
|
|
||||||
|
interface CameraEvent extends EmitableEvent {}
|
||||||
|
|
||||||
|
export class Camera extends EventEmitter<CameraEvent> {
|
||||||
|
mat: mat3 = mat3.create();
|
||||||
|
|
||||||
|
x: number = 0;
|
||||||
|
y: number = 0;
|
||||||
|
scaleX: number = 1;
|
||||||
|
scaleY: number = 1;
|
||||||
|
rad: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重设摄像机的所有参数
|
||||||
|
*/
|
||||||
|
reset() {
|
||||||
|
mat3.identity(this.mat);
|
||||||
|
this.x = 0;
|
||||||
|
this.y = 0;
|
||||||
|
this.scaleX = 1;
|
||||||
|
this.scaleY = 1;
|
||||||
|
this.rad = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改摄像机的缩放,叠加关系
|
||||||
|
*/
|
||||||
|
scale(x: number, y: number = x) {
|
||||||
|
mat3.scale(this.mat, this.mat, [x, y]);
|
||||||
|
this.scaleX *= x;
|
||||||
|
this.scaleY *= y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动摄像机,叠加关系
|
||||||
|
*/
|
||||||
|
move(x: number, y: number) {
|
||||||
|
mat3.translate(this.mat, this.mat, [x, y]);
|
||||||
|
this.x += x;
|
||||||
|
this.y += y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旋转摄像机,叠加关系
|
||||||
|
*/
|
||||||
|
rotate(rad: number) {
|
||||||
|
mat3.rotate(this.mat, this.mat, rad);
|
||||||
|
this.rad += rad;
|
||||||
|
if (this.rad >= Math.PI * 2) {
|
||||||
|
const n = Math.floor(this.rad / Math.PI / 2);
|
||||||
|
this.rad -= n * Math.PI * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置摄像机的缩放,非叠加关系
|
||||||
|
*/
|
||||||
|
setScale(x: number, y: number = x) {
|
||||||
|
mat3.scale(this.mat, this.mat, [x / this.scaleX, y / this.scaleY]);
|
||||||
|
this.scaleX = x;
|
||||||
|
this.scaleY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置摄像机的位置,非叠加关系
|
||||||
|
*/
|
||||||
|
setTranslate(x: number, y: number) {
|
||||||
|
mat3.translate(this.mat, this.mat, [x - this.x, y - this.y]);
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置摄像机的旋转,非叠加关系
|
||||||
|
*/
|
||||||
|
setRotate(rad: number) {
|
||||||
|
mat3.rotate(this.mat, this.mat, rad - this.rad);
|
||||||
|
this.rad = rad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置摄像机的变换矩阵,叠加模式
|
||||||
|
* @param a 水平缩放
|
||||||
|
* @param b 垂直倾斜
|
||||||
|
* @param c 水平倾斜
|
||||||
|
* @param d 垂直缩放
|
||||||
|
* @param e 水平移动
|
||||||
|
* @param f 垂直移动
|
||||||
|
*/
|
||||||
|
transform(
|
||||||
|
a: number,
|
||||||
|
b: number,
|
||||||
|
c: number,
|
||||||
|
d: number,
|
||||||
|
e: number,
|
||||||
|
f: number
|
||||||
|
) {
|
||||||
|
mat3.multiply(
|
||||||
|
this.mat,
|
||||||
|
this.mat,
|
||||||
|
mat3.fromValues(a, b, 0, c, d, 0, e, f, 1)
|
||||||
|
);
|
||||||
|
this.calAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置摄像机的变换矩阵,非叠加模式
|
||||||
|
* @param a 水平缩放
|
||||||
|
* @param b 垂直倾斜
|
||||||
|
* @param c 水平倾斜
|
||||||
|
* @param d 垂直缩放
|
||||||
|
* @param e 水平移动
|
||||||
|
* @param f 垂直移动
|
||||||
|
*/
|
||||||
|
setTransform(
|
||||||
|
a: number,
|
||||||
|
b: number,
|
||||||
|
c: number,
|
||||||
|
d: number,
|
||||||
|
e: number,
|
||||||
|
f: number
|
||||||
|
) {
|
||||||
|
mat3.set(this.mat, a, b, 0, c, d, 0, e, f, 1);
|
||||||
|
this.calAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新计算 translation scaling rotation
|
||||||
|
*/
|
||||||
|
calAttributes() {
|
||||||
|
const [x, y] = getTranslation(this.mat);
|
||||||
|
const [scaleX, scaleY] = getScaling(this.mat);
|
||||||
|
const rad = getRotation(this.mat);
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.scaleX = scaleX;
|
||||||
|
this.scaleY = scaleY;
|
||||||
|
this.rad = rad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据摄像机的信息,将一个点转换为计算后的位置
|
||||||
|
* @param camera 摄像机
|
||||||
|
* @param x 横坐标
|
||||||
|
* @param y 纵坐标
|
||||||
|
*/
|
||||||
|
static transformed(camera: Camera, x: number, y: number) {
|
||||||
|
return multiplyVec3(camera.mat, [x, y, 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据摄像机的信息,将一个计算后的位置逆转换为原位置
|
||||||
|
* @param camera 摄像机
|
||||||
|
* @param x 横坐标
|
||||||
|
* @param y 纵坐标
|
||||||
|
*/
|
||||||
|
static untransformed(camera: Camera, x: number, y: number) {
|
||||||
|
const invert = mat3.create();
|
||||||
|
mat3.invert(invert, camera.mat);
|
||||||
|
return multiplyVec3(invert, [x, y, 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function multiplyVec3(mat: ReadonlyMat3, vec: ReadonlyVec3) {
|
||||||
|
return vec3.fromValues(
|
||||||
|
mat[0] * vec[0] + mat[3] * vec[1] + mat[6] * vec[2],
|
||||||
|
mat[1] * vec[0] + mat[4] * vec[1] + mat[7] * vec[2],
|
||||||
|
mat[2] * vec[0] + mat[5] * vec[1] + mat[8] * vec[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTranslation(mat: ReadonlyMat3): vec2 {
|
||||||
|
return [mat[6], mat[7]];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScaling(mat: ReadonlyMat3): vec2 {
|
||||||
|
return [Math.hypot(mat[0], mat[3]), Math.hypot(mat[1], mat[4])];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRotation(mat: ReadonlyMat3): number {
|
||||||
|
return Math.atan2(mat[3], mat[0]);
|
||||||
|
}
|
61
src/core/render/container.ts
Normal file
61
src/core/render/container.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
||||||
|
import { Camera } from './camera';
|
||||||
|
import {
|
||||||
|
ICanvasCachedRenderItem,
|
||||||
|
RenderItem,
|
||||||
|
RenderItemPosition,
|
||||||
|
withCacheRender
|
||||||
|
} from './item';
|
||||||
|
|
||||||
|
export class Container extends RenderItem implements ICanvasCachedRenderItem {
|
||||||
|
children: RenderItem[] = [];
|
||||||
|
sortedChildren: RenderItem[] = [];
|
||||||
|
|
||||||
|
canvas: MotaOffscreenCanvas2D;
|
||||||
|
|
||||||
|
constructor(type: RenderItemPosition = 'static') {
|
||||||
|
super();
|
||||||
|
this.canvas = new MotaOffscreenCanvas2D();
|
||||||
|
this.type = type;
|
||||||
|
this.canvas.withGameScale(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(
|
||||||
|
canvas: HTMLCanvasElement,
|
||||||
|
ctx: CanvasRenderingContext2D,
|
||||||
|
camera: Camera
|
||||||
|
): void {
|
||||||
|
this.emit('beforeUpdate', this);
|
||||||
|
withCacheRender(this, canvas, ctx, camera, c => {
|
||||||
|
this.sortedChildren.forEach(v => {
|
||||||
|
v.render(c.canvas, c.ctx, camera);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.emit('afterUpdate', this);
|
||||||
|
}
|
||||||
|
|
||||||
|
size(width: number, height: number) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.canvas.size(width, height);
|
||||||
|
this.writing = this.using;
|
||||||
|
this.update(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos(x: number, y: number) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加子元素到这个容器上,然后在下一个tick执行更新
|
||||||
|
* @param children 要添加的子元素
|
||||||
|
*/
|
||||||
|
appendChild(children: RenderItem[]) {
|
||||||
|
children.forEach(v => (v.parent = this));
|
||||||
|
this.children.push(...children);
|
||||||
|
this.sortedChildren = this.children
|
||||||
|
.slice()
|
||||||
|
.sort((a, b) => a.zIndex - b.zIndex);
|
||||||
|
}
|
||||||
|
}
|
174
src/core/render/hero.ts
Normal file
174
src/core/render/hero.ts
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
import { Ticker } from 'mutate-animate';
|
||||||
|
import { MotaCanvas2D } from '../fx/canvas2d';
|
||||||
|
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
|
||||||
|
import { debounce } from 'lodash-es';
|
||||||
|
|
||||||
|
// 重写样板的勇士绘制
|
||||||
|
|
||||||
|
const canvas = MotaCanvas2D.for('@hero', false);
|
||||||
|
|
||||||
|
Mota.require('var', 'loading').once('coreInit', () => {
|
||||||
|
canvas.withGameScale(true);
|
||||||
|
canvas.setHD(false);
|
||||||
|
canvas.size(480, 480);
|
||||||
|
canvas.pos(0, 0);
|
||||||
|
canvas.css(`z-index: 40`);
|
||||||
|
canvas.canvas.classList.add('no-anti-aliasing');
|
||||||
|
canvas.setTarget(core.dom.gameDraw);
|
||||||
|
canvas.mount();
|
||||||
|
});
|
||||||
|
|
||||||
|
const DIR_INDEX: Record<Dir, number> = {
|
||||||
|
down: 0,
|
||||||
|
left: 1,
|
||||||
|
right: 2,
|
||||||
|
up: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
interface HeroDrawItem {
|
||||||
|
id: AllIds | 'hero';
|
||||||
|
image: HTMLCanvasElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HeroDrawing extends HeroDrawItem {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
dir: Dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HeroRendererEvent extends EmitableEvent {
|
||||||
|
beforeDraw: () => void;
|
||||||
|
afterDraw: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetMoving = debounce((render: HeroRenderer) => {
|
||||||
|
render.moving = 0;
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
export class HeroRenderer extends EventEmitter<HeroRendererEvent> {
|
||||||
|
followers: HeroDrawItem[] = [];
|
||||||
|
hero!: HeroDrawItem;
|
||||||
|
|
||||||
|
/** 移动状态 */
|
||||||
|
moving: number = 0;
|
||||||
|
/** 移动过程中的偏移 */
|
||||||
|
offset: number = 0;
|
||||||
|
/** 勇士绘制时的alpha通道 */
|
||||||
|
alpha: number = 1;
|
||||||
|
|
||||||
|
ticker: Ticker = new Ticker();
|
||||||
|
|
||||||
|
/** 是否是后退状态 */
|
||||||
|
private back: boolean = false;
|
||||||
|
/** 是否正在移动 */
|
||||||
|
private isMoving: boolean = false;
|
||||||
|
/** 上一次换腿(?的时间 */
|
||||||
|
private lastMoving: number = 0;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
Mota.require('var', 'loading').once('coreInit', () => {
|
||||||
|
this.ticker.add(time => {
|
||||||
|
if (core.status.heroMoving < 0 || !this.isMoving) return;
|
||||||
|
if (time - this.lastMoving > core.values.moveSpeed) {
|
||||||
|
this.lastMoving = time;
|
||||||
|
this.moving++;
|
||||||
|
this.moving %= 4;
|
||||||
|
}
|
||||||
|
this.draw();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置勇士绘制信息
|
||||||
|
*/
|
||||||
|
setHero() {
|
||||||
|
const image = core.material.images.hero;
|
||||||
|
const canvas = new MotaCanvas2D();
|
||||||
|
canvas.setHD(false);
|
||||||
|
canvas.size(image.width, image.height);
|
||||||
|
canvas.ctx.drawImage(image, 0, 0);
|
||||||
|
this.hero = {
|
||||||
|
id: 'hero',
|
||||||
|
image: canvas.canvas
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行绘制
|
||||||
|
*/
|
||||||
|
draw() {
|
||||||
|
if (!core.isPlaying()) return;
|
||||||
|
const { ctx, canvas: can } = canvas;
|
||||||
|
const { x, y, direction: dir } = core.status.hero.loc;
|
||||||
|
ctx.clearRect(0, 0, can.width, can.height);
|
||||||
|
ctx.globalAlpha = this.alpha;
|
||||||
|
|
||||||
|
this.emit('beforeDraw');
|
||||||
|
|
||||||
|
const data: HeroDrawing[] = [];
|
||||||
|
data.push({ ...this.hero, x, y, dir });
|
||||||
|
core.status.hero.followers.forEach((v, i) => {
|
||||||
|
const { id, image } = this.followers[i];
|
||||||
|
data.push({ x: v.x, y: v.y, dir: v.direction, id, image });
|
||||||
|
});
|
||||||
|
|
||||||
|
const { offsetX: ox, offsetY: oy } = core.bigmap;
|
||||||
|
const sgn = this.back ? -1 : 1;
|
||||||
|
const offset = this.offset * sgn;
|
||||||
|
|
||||||
|
const frame = this.isMoving ? this.moving % 4 : 0;
|
||||||
|
|
||||||
|
data.forEach(v => {
|
||||||
|
// hero offset x
|
||||||
|
const hox = offset * core.utils.scan[v.dir].x;
|
||||||
|
const hoy = offset * core.utils.scan[v.dir].y;
|
||||||
|
const cx = v.x * 32 + 16 - ox + hox;
|
||||||
|
const cy = v.y * 32 + 16 - oy + hoy;
|
||||||
|
const { width, height } = v.image;
|
||||||
|
const pw = width / 4;
|
||||||
|
const ph = height / 4;
|
||||||
|
const line = DIR_INDEX[v.dir];
|
||||||
|
|
||||||
|
const px = cx - pw / 2;
|
||||||
|
const py = cy - ph + 16;
|
||||||
|
|
||||||
|
const sx = frame * pw;
|
||||||
|
const sy = line * ph;
|
||||||
|
|
||||||
|
ctx.drawImage(v.image, sx, sy, pw, ph, px, py, pw, ph);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.emit('afterDraw');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置绘制状态为正在移动还是静止
|
||||||
|
*/
|
||||||
|
move(moving: boolean) {
|
||||||
|
this.isMoving = moving;
|
||||||
|
if (!moving) {
|
||||||
|
resetMoving(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前是否为后退状态
|
||||||
|
*/
|
||||||
|
backward(back: boolean) {
|
||||||
|
this.back = back;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置绘制时的alpha
|
||||||
|
*/
|
||||||
|
setAlpha(alpha: number) {
|
||||||
|
this.alpha = alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const render = new HeroRenderer();
|
||||||
|
|
||||||
|
export { render as heroRender };
|
200
src/core/render/item.ts
Normal file
200
src/core/render/item.ts
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
import { isNil } from 'lodash-es';
|
||||||
|
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
|
||||||
|
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
||||||
|
import { Camera } from './camera';
|
||||||
|
|
||||||
|
export type RenderFunction = (
|
||||||
|
canvas: MotaOffscreenCanvas2D,
|
||||||
|
camera: Camera
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
export type RenderItemPosition = 'absolute' | 'static';
|
||||||
|
|
||||||
|
interface IRenderCache {
|
||||||
|
/** 缓存列表 */
|
||||||
|
cacheList: Map<string, MotaOffscreenCanvas2D>;
|
||||||
|
/** 当前正在使用的缓存 */
|
||||||
|
using?: string;
|
||||||
|
/** 下次绘制需要写入的缓存 */
|
||||||
|
writing?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在之后的绘制中使用缓存,如果缓存不存在,那么就不使用缓存,并在下一次绘制结束后写入
|
||||||
|
* @param index 缓存的索引,不填时表示不使用缓存
|
||||||
|
*/
|
||||||
|
useCache(index?: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将下次绘制写入缓存并使用
|
||||||
|
* @param index 缓存的索引,不填时表示不进行缓存
|
||||||
|
*/
|
||||||
|
cache(index?: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除指定或所有缓存
|
||||||
|
* @param index 要清除的缓存,不填代表清除所有
|
||||||
|
*/
|
||||||
|
clearCache(index?: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRenderUpdater {
|
||||||
|
/**
|
||||||
|
* 更新这个渲染元素
|
||||||
|
* @param item 触发更新事件的元素,可以是自身触发。如果不填表示手动触发,而非渲染内容发生变化而引起的触发
|
||||||
|
*/
|
||||||
|
update(item?: RenderItem): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICanvasCachedRenderItem {
|
||||||
|
/** 离屏画布,首先渲染到它上面,然后由Renderer渲染到最终画布上 */
|
||||||
|
canvas: MotaOffscreenCanvas2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRenderAnchor {
|
||||||
|
anchorX: number;
|
||||||
|
anchorY: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置渲染元素的位置锚点
|
||||||
|
* @param x 锚点的横坐标,小数,0表示最左边,1表示最右边
|
||||||
|
* @param y 锚点的纵坐标,小数,0表示最上边,1表示最下边
|
||||||
|
*/
|
||||||
|
setAnchor(x: number, y: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RenderItemEvent extends EmitableEvent {
|
||||||
|
beforeUpdate: (item?: RenderItem) => void;
|
||||||
|
afterUpdate: (item?: RenderItem) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class RenderItem
|
||||||
|
extends EventEmitter<RenderItemEvent>
|
||||||
|
implements IRenderCache, IRenderUpdater, IRenderAnchor
|
||||||
|
{
|
||||||
|
zIndex: number = 0;
|
||||||
|
|
||||||
|
x: number = 0;
|
||||||
|
y: number = 0;
|
||||||
|
width: number = 200;
|
||||||
|
height: number = 200;
|
||||||
|
|
||||||
|
cacheList: Map<string, MotaOffscreenCanvas2D> = new Map();
|
||||||
|
|
||||||
|
using?: string;
|
||||||
|
writing?: string;
|
||||||
|
|
||||||
|
anchorX: number = 0;
|
||||||
|
anchorY: number = 0;
|
||||||
|
|
||||||
|
/** 渲染模式,absolute表示绝对位置,static表示跟随摄像机移动,只对顶层元素有效 */
|
||||||
|
type: 'absolute' | 'static' = 'static';
|
||||||
|
|
||||||
|
parent?: RenderItem;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.using = '@default';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渲染这个对象
|
||||||
|
* @param canvas 渲染至的画布
|
||||||
|
* @param ctx 渲染至的画布的渲染上下文
|
||||||
|
* @param camera 渲染时使用的摄像机
|
||||||
|
*/
|
||||||
|
abstract render(
|
||||||
|
canvas: HTMLCanvasElement,
|
||||||
|
ctx: CanvasRenderingContext2D,
|
||||||
|
camera: Camera
|
||||||
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改这个对象的大小
|
||||||
|
*/
|
||||||
|
abstract size(width: number, height: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改这个对象的位置
|
||||||
|
*/
|
||||||
|
abstract pos(x: number, y: number): void;
|
||||||
|
|
||||||
|
useCache(index?: string): void {
|
||||||
|
if (isNil(index)) {
|
||||||
|
this.using = void 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.cacheList.has(index)) {
|
||||||
|
this.writing = index;
|
||||||
|
}
|
||||||
|
this.using = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache(index?: string): void {
|
||||||
|
this.writing = index;
|
||||||
|
this.using = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCache(index?: string): void {
|
||||||
|
if (isNil(index)) {
|
||||||
|
this.writing = void 0;
|
||||||
|
this.using = void 0;
|
||||||
|
this.cacheList.clear();
|
||||||
|
} else {
|
||||||
|
this.cacheList.delete(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAnchor(x: number, y: number): void {
|
||||||
|
this.anchorX = x;
|
||||||
|
this.anchorY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(item?: RenderItem): void {
|
||||||
|
this.writing = this.using;
|
||||||
|
this.using = void 0;
|
||||||
|
this.parent?.update(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withCacheRender(
|
||||||
|
item: RenderItem & ICanvasCachedRenderItem,
|
||||||
|
canvas: HTMLCanvasElement,
|
||||||
|
ctx: CanvasRenderingContext2D,
|
||||||
|
camera: Camera,
|
||||||
|
fn: RenderFunction
|
||||||
|
) {
|
||||||
|
const { width, height } = item;
|
||||||
|
const ax = width * item.anchorX;
|
||||||
|
const ay = height * item.anchorY;
|
||||||
|
let write = item.writing;
|
||||||
|
if (!isNil(item.using)) {
|
||||||
|
const cache = item.cacheList.get(item.using);
|
||||||
|
if (cache) {
|
||||||
|
ctx.drawImage(
|
||||||
|
cache.canvas,
|
||||||
|
item.x - ax,
|
||||||
|
item.y - ay,
|
||||||
|
item.width,
|
||||||
|
item.height
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write = item.using;
|
||||||
|
}
|
||||||
|
const { canvas: c, ctx: ct } = item.canvas;
|
||||||
|
ct.clearRect(0, 0, c.width, c.height);
|
||||||
|
fn(item.canvas, camera);
|
||||||
|
if (!isNil(write)) {
|
||||||
|
const cache = item.cacheList.get(write);
|
||||||
|
if (cache) {
|
||||||
|
const { canvas, ctx } = cache;
|
||||||
|
ctx.drawImage(c, 0, 0);
|
||||||
|
} else {
|
||||||
|
item.cacheList.set(write, MotaOffscreenCanvas2D.clone(item.canvas));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.drawImage(c, item.x - ax, item.y - ay, item.width, item.height);
|
||||||
|
item.using = write;
|
||||||
|
}
|
123
src/core/render/preset/misc.ts
Normal file
123
src/core/render/preset/misc.ts
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import { Sprite } from '../sprite';
|
||||||
|
|
||||||
|
type CanvasStyle = string | CanvasGradient | CanvasPattern;
|
||||||
|
|
||||||
|
export class Text extends Sprite {
|
||||||
|
text: string;
|
||||||
|
|
||||||
|
fillStyle?: CanvasStyle = '#fff';
|
||||||
|
strokeStyle?: CanvasStyle;
|
||||||
|
font?: string = '';
|
||||||
|
|
||||||
|
private length: number = 0;
|
||||||
|
private descent: number = 0;
|
||||||
|
|
||||||
|
constructor(text: string = '') {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.text = text;
|
||||||
|
if (text.length > 0) this.calBox();
|
||||||
|
|
||||||
|
this.renderFn = ({ canvas, ctx }) => {
|
||||||
|
ctx.save();
|
||||||
|
ctx.textBaseline = 'bottom';
|
||||||
|
ctx.fillStyle = this.fillStyle ?? 'transparent';
|
||||||
|
ctx.strokeStyle = this.strokeStyle ?? 'transparent';
|
||||||
|
ctx.font = this.font ?? '';
|
||||||
|
|
||||||
|
if (this.fillStyle) {
|
||||||
|
ctx.fillText(this.text, 0, this.descent);
|
||||||
|
}
|
||||||
|
if (this.strokeStyle) {
|
||||||
|
ctx.strokeText(this.text, 0, this.descent);
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文字的长度
|
||||||
|
*/
|
||||||
|
measure() {
|
||||||
|
this.canvas.ctx.save();
|
||||||
|
this.canvas.ctx.textBaseline = 'bottom';
|
||||||
|
this.canvas.ctx.font = this.font ?? '';
|
||||||
|
const res = this.canvas.ctx.measureText(this.text);
|
||||||
|
this.canvas.ctx.restore();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置显示文字
|
||||||
|
* @param text 显示的文字
|
||||||
|
*/
|
||||||
|
setText(text: string) {
|
||||||
|
this.text = text;
|
||||||
|
this.writing = this.using;
|
||||||
|
this.using = void 0;
|
||||||
|
this.calBox();
|
||||||
|
if (this.parent) this.update(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置使用的字体
|
||||||
|
* @param font 字体
|
||||||
|
*/
|
||||||
|
setFont(font: string) {
|
||||||
|
this.font = font;
|
||||||
|
this.calBox();
|
||||||
|
if (this.parent) this.update(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置字体样式
|
||||||
|
* @param fill 填充样式
|
||||||
|
* @param stroke 描边样式
|
||||||
|
*/
|
||||||
|
setStyle(fill?: CanvasStyle, stroke?: CanvasStyle) {
|
||||||
|
this.fillStyle = fill;
|
||||||
|
this.strokeStyle = stroke;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算字体所占空间,从而确定这个元素的大小
|
||||||
|
*/
|
||||||
|
calBox() {
|
||||||
|
const { width, fontBoundingBoxAscent } = this.measure();
|
||||||
|
this.length = width;
|
||||||
|
this.descent = fontBoundingBoxAscent;
|
||||||
|
this.size(width, fontBoundingBoxAscent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SizedCanvasImageSource = Exclude<
|
||||||
|
CanvasImageSource,
|
||||||
|
VideoFrame | SVGElement
|
||||||
|
>;
|
||||||
|
|
||||||
|
export class Image extends Sprite {
|
||||||
|
image: SizedCanvasImageSource;
|
||||||
|
|
||||||
|
constructor(image: SizedCanvasImageSource) {
|
||||||
|
super();
|
||||||
|
this.image = image;
|
||||||
|
this.canvas.withGameScale(false);
|
||||||
|
this.size(image.width, image.height);
|
||||||
|
|
||||||
|
this.renderFn = ({ canvas, ctx }) => {
|
||||||
|
ctx.drawImage(this.image, 0, 0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置图片资源
|
||||||
|
* @param image 图片资源
|
||||||
|
*/
|
||||||
|
setImage(image: SizedCanvasImageSource) {
|
||||||
|
this.image = image;
|
||||||
|
this.size(image.width, image.height);
|
||||||
|
this.writing = this.using;
|
||||||
|
this.using = void 0;
|
||||||
|
this.update(this);
|
||||||
|
}
|
||||||
|
}
|
142
src/core/render/render.ts
Normal file
142
src/core/render/render.ts
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
import { isNil } from 'lodash-es';
|
||||||
|
import { MotaCanvas2D, MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
||||||
|
import { Camera } from './camera';
|
||||||
|
import { Container } from './container';
|
||||||
|
import { RenderItem, withCacheRender } from './item';
|
||||||
|
import { Image, Text } from './preset/misc';
|
||||||
|
|
||||||
|
export class MotaRenderer extends Container {
|
||||||
|
canvas: MotaOffscreenCanvas2D;
|
||||||
|
camera: Camera;
|
||||||
|
|
||||||
|
/** 摄像机缓存,如果是需要快速切换摄像机的场景,使用缓存可以大幅提升性能表现 */
|
||||||
|
cameraCache: Map<Camera, MotaOffscreenCanvas2D> = new Map();
|
||||||
|
target: MotaCanvas2D;
|
||||||
|
|
||||||
|
private needUpdate: boolean = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.canvas = new MotaOffscreenCanvas2D();
|
||||||
|
this.camera = new Camera();
|
||||||
|
this.target = new MotaCanvas2D(`render-main`);
|
||||||
|
this.width = 480;
|
||||||
|
this.height = 480;
|
||||||
|
this.target.withGameScale(true);
|
||||||
|
this.target.size(480, 480);
|
||||||
|
this.canvas.withGameScale(true);
|
||||||
|
this.canvas.size(480, 480);
|
||||||
|
this.target.css(`z-index: 100`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用某个摄像机
|
||||||
|
* @param camera 要使用的摄像机
|
||||||
|
* @param noCache 是否不使用缓存,当切换至的目标摄像机相比切走时发生了例如位置的变化时,一般需要设置为true,
|
||||||
|
* 否则会使用上一次被切换走时的缓存
|
||||||
|
*/
|
||||||
|
useCamera(camera: Camera, noCache: boolean = false) {
|
||||||
|
const cache = MotaOffscreenCanvas2D.clone(this.canvas);
|
||||||
|
this.cameraCache.set(this.camera, cache);
|
||||||
|
this.camera = camera;
|
||||||
|
const nowCache = this.cameraCache.get(camera);
|
||||||
|
if (!nowCache || !noCache) this.render();
|
||||||
|
else this.renderCache(nowCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除某个摄像机的画面缓存
|
||||||
|
* @param camera 要删除的缓存对应的摄像机
|
||||||
|
*/
|
||||||
|
freeCameraCache(camera: Camera) {
|
||||||
|
this.cameraCache.delete(camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渲染游戏画面
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const { canvas, ctx } = this.target;
|
||||||
|
const camera = this.camera;
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
withCacheRender(this, canvas, ctx, camera, canvas => {
|
||||||
|
const { canvas: ca, ctx: ct, scale } = canvas;
|
||||||
|
const mat = camera.mat;
|
||||||
|
const a = mat[0] * scale;
|
||||||
|
const b = mat[1];
|
||||||
|
const c = mat[3];
|
||||||
|
const d = mat[4] * scale;
|
||||||
|
const e = mat[6];
|
||||||
|
const f = mat[7];
|
||||||
|
this.sortedChildren.forEach(v => {
|
||||||
|
if (v.type === 'absolute') {
|
||||||
|
ct.setTransform(scale, 0, 0, scale, 0, 0);
|
||||||
|
} else {
|
||||||
|
ct.setTransform(a, b, c, d, e, f);
|
||||||
|
}
|
||||||
|
v.render(ca, ct, camera);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新渲染,在下一个tick更新
|
||||||
|
*/
|
||||||
|
update(item?: RenderItem) {
|
||||||
|
if (this.needUpdate) return;
|
||||||
|
this.needUpdate = true;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.writing = this.using;
|
||||||
|
this.using = void 0;
|
||||||
|
this.needUpdate = false;
|
||||||
|
this.emit('beforeUpdate', item);
|
||||||
|
this.render();
|
||||||
|
this.emit('afterUpdate', item);
|
||||||
|
this.using = this.writing;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将缓存内容渲染至画面
|
||||||
|
* @param cache 渲染缓存,是一个离屏Canvas2D对象
|
||||||
|
*/
|
||||||
|
renderCache(cache: MotaOffscreenCanvas2D) {
|
||||||
|
const { canvas, ctx } = this.canvas;
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.width);
|
||||||
|
ctx.drawImage(cache.canvas, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加至游戏画面
|
||||||
|
*/
|
||||||
|
mount() {
|
||||||
|
this.target.mount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mota.require('var', 'hook').once('reset', () => {
|
||||||
|
const render = new MotaRenderer();
|
||||||
|
const con = new Container('static');
|
||||||
|
const camera = render.camera;
|
||||||
|
render.mount();
|
||||||
|
|
||||||
|
const testText = new Text();
|
||||||
|
testText.setText('测试测试');
|
||||||
|
testText.pos(100, 100);
|
||||||
|
testText.setFont('32px normal');
|
||||||
|
testText.setStyle('#fff');
|
||||||
|
con.size(480, 480);
|
||||||
|
const testImage = new Image(core.material.images.images['arrow.png']);
|
||||||
|
testImage.pos(200, 200);
|
||||||
|
|
||||||
|
con.appendChild([testText, testImage]);
|
||||||
|
|
||||||
|
render.appendChild([con]);
|
||||||
|
|
||||||
|
render.update(render);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
testText.setFont('18px normal');
|
||||||
|
}, 2000);
|
||||||
|
});
|
41
src/core/render/sprite.ts
Normal file
41
src/core/render/sprite.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { Camera } from './camera';
|
||||||
|
import { RenderFunction, RenderItem, withCacheRender } from './item';
|
||||||
|
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
||||||
|
|
||||||
|
export class Sprite extends RenderItem {
|
||||||
|
renderFn: RenderFunction;
|
||||||
|
|
||||||
|
canvas: MotaOffscreenCanvas2D;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.renderFn = () => {};
|
||||||
|
this.canvas = new MotaOffscreenCanvas2D();
|
||||||
|
this.canvas.withGameScale(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(
|
||||||
|
canvas: HTMLCanvasElement,
|
||||||
|
ctx: CanvasRenderingContext2D,
|
||||||
|
camera: Camera
|
||||||
|
): void {
|
||||||
|
this.emit('beforeUpdate', this);
|
||||||
|
withCacheRender(this, canvas, ctx, camera, canvas => {
|
||||||
|
this.renderFn(canvas, camera);
|
||||||
|
});
|
||||||
|
this.emit('afterUpdate', this);
|
||||||
|
}
|
||||||
|
|
||||||
|
size(width: number, height: number) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.canvas.size(width, height);
|
||||||
|
this.writing = this.using;
|
||||||
|
this.update(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos(x: number, y: number) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { EmitableEvent, EventEmitter } from '../core/common/eventEmitter';
|
import { EmitableEvent, EventEmitter } from '../core/common/eventEmitter';
|
||||||
import { DamageEnemy } from './enemy/damage';
|
import type { DamageEnemy } from './enemy/damage';
|
||||||
|
|
||||||
// ----- 加载事件
|
// ----- 加载事件
|
||||||
interface GameLoadEvent extends EmitableEvent {
|
interface GameLoadEvent extends EmitableEvent {
|
||||||
@ -75,25 +75,36 @@ class GameLoading extends EventEmitter<GameLoadEvent> {
|
|||||||
export const loading = new GameLoading();
|
export const loading = new GameLoading();
|
||||||
|
|
||||||
export interface GameEvent extends EmitableEvent {
|
export interface GameEvent extends EmitableEvent {
|
||||||
/** Emitted in events.prototype.resetGame. */
|
/** Emitted in libs/events.js resetGame. */
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
/** Emitted in src/App.vue setup. */
|
/** Emitted in src/App.vue setup. */
|
||||||
mounted: () => void;
|
mounted: () => void;
|
||||||
/** Emitted in plugin/ui.js */
|
/** Emitted in plugin/game/ui.ts updateStatusBar_update */
|
||||||
statusBarUpdate: () => void;
|
statusBarUpdate: () => void;
|
||||||
/** Emitted in core/index.ts */
|
/** Emitted in core/index.ts */
|
||||||
renderLoaded: () => void;
|
renderLoaded: () => void;
|
||||||
// /** Emitted in libs/events.js */
|
/** Emitted in libs/events.js getItem */
|
||||||
afterGetItem: (
|
afterGetItem: (
|
||||||
itemId: AllIdsOf<'items'>,
|
itemId: AllIdsOf<'items'>,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
isGentleClick: boolean
|
isGentleClick: boolean
|
||||||
) => void;
|
) => void;
|
||||||
|
/** Emitted in libs/events.js _openDoor_animate */
|
||||||
afterOpenDoor: (doorId: AllIdsOf<'animates'>, x: number, y: number) => void;
|
afterOpenDoor: (doorId: AllIdsOf<'animates'>, x: number, y: number) => void;
|
||||||
|
/** Emitted in project/functions.js afterChangeFloor */
|
||||||
afterChangeFloor: (floorId: FloorIds) => void;
|
afterChangeFloor: (floorId: FloorIds) => void;
|
||||||
|
/** Emitted in project/functions.js moveOneStep */
|
||||||
moveOneStep: (x: number, y: number, floorId: FloorIds) => void;
|
moveOneStep: (x: number, y: number, floorId: FloorIds) => void;
|
||||||
|
/** Emitted in src/game/enemy/battle.ts afterBattle */
|
||||||
afterBattle: (enemy: DamageEnemy, x?: number, y?: number) => void;
|
afterBattle: (enemy: DamageEnemy, x?: number, y?: number) => void;
|
||||||
|
/** Emitted in libs/events.js changingFloor */
|
||||||
|
changingFloor: (floorId: FloorIds, heroLoc: Loc) => void;
|
||||||
|
drawHero: (
|
||||||
|
status?: Exclude<keyof MaterialIcon['hero']['down'], 'loc'>,
|
||||||
|
offset?: number,
|
||||||
|
frame?: number
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hook = new EventEmitter<GameEvent>();
|
export const hook = new EventEmitter<GameEvent>();
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { has } from '@/plugin/game/utils';
|
import { has } from '@/plugin/game/utils';
|
||||||
|
import { loading } from '../game';
|
||||||
|
|
||||||
export namespace BluePalace {
|
export namespace BluePalace {
|
||||||
type DoorConvertInfo = [id: AllIds, x: number, y: number];
|
type DoorConvertInfo = [id: AllIds, x: number, y: number];
|
||||||
|
|
||||||
|
// ---------- 黄蓝门转换
|
||||||
|
|
||||||
function drawDoors(
|
function drawDoors(
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
convert: DoorConvertInfo[],
|
convert: DoorConvertInfo[],
|
||||||
@ -75,4 +78,30 @@ export namespace BluePalace {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- 传送门部分
|
||||||
|
|
||||||
|
interface Portal {
|
||||||
|
fx: number;
|
||||||
|
fy: number;
|
||||||
|
dir: Dir;
|
||||||
|
tx: number;
|
||||||
|
ty: number;
|
||||||
|
toDir: Dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const portals: Partial<Record<FloorIds, Portal[]>> = {
|
||||||
|
MT75: [
|
||||||
|
{ fx: 7, fy: 7, dir: 'left', tx: 9, ty: 9, toDir: 'down' },
|
||||||
|
{ fx: 5, fy: 11, dir: 'right', tx: 7, ty: 9, toDir: 'up' },
|
||||||
|
{ fx: 4, fy: 6, dir: 'right', tx: 9, ty: 4, toDir: 'up' },
|
||||||
|
{ fx: 5, fy: 9, dir: 'right', tx: 3, ty: 7, toDir: 'up' },
|
||||||
|
{ fx: 7, fy: 5, dir: 'right', tx: 4, ty: 9, toDir: 'up' }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
loading.once('coreInit', initPortals);
|
||||||
|
|
||||||
|
function initPortals() {
|
||||||
|
// 主要是复写勇士绘制以及传送判定,还有自动寻路
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,16 @@ import type * as damage from './enemy/damage';
|
|||||||
import type { Logger } from '@/core/common/logger';
|
import type { Logger } from '@/core/common/logger';
|
||||||
import type { Danmaku } from '@/core/main/custom/danmaku';
|
import type { Danmaku } from '@/core/main/custom/danmaku';
|
||||||
import type * as misc from './mechanism/misc';
|
import type * as misc from './mechanism/misc';
|
||||||
|
import type { MotaCanvas2D } from '@/core/fx/canvas2d';
|
||||||
|
import type * as portal from '@/core/fx/portal';
|
||||||
|
import type { HeroRenderer } from '@/core/render/hero';
|
||||||
|
|
||||||
interface ClassInterface {
|
interface ClassInterface {
|
||||||
// 渲染进程与游戏进程通用
|
// 渲染进程与游戏进程通用
|
||||||
EventEmitter: typeof EventEmitter;
|
EventEmitter: typeof EventEmitter;
|
||||||
IndexedEventEmitter: typeof IndexedEventEmitter;
|
IndexedEventEmitter: typeof IndexedEventEmitter;
|
||||||
Disposable: typeof Disposable;
|
Disposable: typeof Disposable;
|
||||||
// 定义于渲染进程,录像中会进行polyfill,但是不执行任何内容
|
// 定义于渲染进程
|
||||||
GameStorage: typeof GameStorage;
|
GameStorage: typeof GameStorage;
|
||||||
MotaSetting: typeof MotaSetting;
|
MotaSetting: typeof MotaSetting;
|
||||||
SettingDisplayer: typeof SettingDisplayer;
|
SettingDisplayer: typeof SettingDisplayer;
|
||||||
@ -45,12 +48,13 @@ interface ClassInterface {
|
|||||||
SoundEffect: typeof SoundEffect;
|
SoundEffect: typeof SoundEffect;
|
||||||
SoundController: typeof SoundController;
|
SoundController: typeof SoundController;
|
||||||
BgmController: typeof BgmController;
|
BgmController: typeof BgmController;
|
||||||
|
MotaCanvas2D: typeof MotaCanvas2D;
|
||||||
|
Danmaku: typeof Danmaku;
|
||||||
// todo: 放到插件 ShaderEffect: typeof ShaderEffect;
|
// todo: 放到插件 ShaderEffect: typeof ShaderEffect;
|
||||||
// 定义于游戏进程,渲染进程依然可用
|
// 定义于游戏进程,渲染进程依然可用
|
||||||
Range: typeof Range;
|
Range: typeof Range;
|
||||||
EnemyCollection: typeof EnemyCollection;
|
EnemyCollection: typeof EnemyCollection;
|
||||||
DamageEnemy: typeof DamageEnemy;
|
DamageEnemy: typeof DamageEnemy;
|
||||||
Danmaku: typeof Danmaku;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type _IBattle = typeof battle;
|
type _IBattle = typeof battle;
|
||||||
@ -90,6 +94,12 @@ interface ModuleInterface {
|
|||||||
Mechanism: {
|
Mechanism: {
|
||||||
BluePalace: typeof misc.BluePalace;
|
BluePalace: typeof misc.BluePalace;
|
||||||
};
|
};
|
||||||
|
Effect: {
|
||||||
|
Portal: typeof portal;
|
||||||
|
};
|
||||||
|
Render: {
|
||||||
|
heroRender: HeroRenderer;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SystemInterfaceMap {
|
interface SystemInterfaceMap {
|
||||||
|
@ -6,7 +6,7 @@ let pop: any[] = [];
|
|||||||
let time = 0;
|
let time = 0;
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
core.registerAnimationFrame('pop', true, popValue);
|
// core.registerAnimationFrame('pop', true, popValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { sleep } from 'mutate-animate';
|
||||||
import { tip } from './utils';
|
import { tip } from './utils';
|
||||||
|
|
||||||
export default function init() {
|
export default function init() {
|
||||||
@ -29,6 +30,12 @@ window.addEventListener('resize', () => {
|
|||||||
});
|
});
|
||||||
checkMobile();
|
checkMobile();
|
||||||
|
|
||||||
|
sleep(2000).then(() => {
|
||||||
|
if (!isMobile) {
|
||||||
|
tip('info', `注意,不推荐使用浏览器的缩放功能,使用游戏内的缩放即可`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function checkMobile() {
|
function checkMobile() {
|
||||||
if (isMobile && !alerted) {
|
if (isMobile && !alerted) {
|
||||||
tip(
|
tip(
|
||||||
|
@ -242,9 +242,6 @@ export function tip(
|
|||||||
class: 'antdv-message'
|
class: 'antdv-message'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
sleep(2000).then(() => {
|
|
||||||
tip('info', `注意,不推荐使用浏览器的缩放功能,使用游戏内的缩放即可`);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置文字分段换行等
|
* 设置文字分段换行等
|
||||||
|
10
src/types/control.d.ts
vendored
10
src/types/control.d.ts
vendored
@ -368,7 +368,7 @@ interface Control {
|
|||||||
*/
|
*/
|
||||||
drawHero(
|
drawHero(
|
||||||
status?: Exclude<keyof MaterialIcon['hero']['down'], 'loc'>,
|
status?: Exclude<keyof MaterialIcon['hero']['down'], 'loc'>,
|
||||||
offset?: number,
|
offset?: number | (Loc & { offset: number }),
|
||||||
frame?: number
|
frame?: number
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
@ -1071,6 +1071,14 @@ interface Control {
|
|||||||
|
|
||||||
_drawHero_updateViewport(x: number, y: number, offset: Loc): void;
|
_drawHero_updateViewport(x: number, y: number, offset: Loc): void;
|
||||||
_moveAction_moving(callback: () => void): void;
|
_moveAction_moving(callback: () => void): void;
|
||||||
|
_drawHero_draw(
|
||||||
|
direction: Dir,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
status: Exclude<keyof MaterialIcon['hero']['down'], 'loc'>,
|
||||||
|
offset: Loc & { offset: number },
|
||||||
|
frame?: number
|
||||||
|
): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const control: new () => Control;
|
declare const control: new () => Control;
|
||||||
|
2
src/types/core.d.ts
vendored
2
src/types/core.d.ts
vendored
@ -240,6 +240,7 @@ interface AnimateFrame {
|
|||||||
readonly animateTime: number;
|
readonly animateTime: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* 勇士移动的时候上一次的换腿时间
|
* 勇士移动的时候上一次的换腿时间
|
||||||
*/
|
*/
|
||||||
moveTime: number;
|
moveTime: number;
|
||||||
@ -251,6 +252,7 @@ interface AnimateFrame {
|
|||||||
lastLegTime: number;
|
lastLegTime: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated
|
||||||
* 当前是否在左腿上,使用了四帧插件时无效
|
* 当前是否在左腿上,使用了四帧插件时无效
|
||||||
*/
|
*/
|
||||||
leftLeg: boolean;
|
leftLeg: boolean;
|
||||||
|
6
src/types/status.d.ts
vendored
6
src/types/status.d.ts
vendored
@ -628,6 +628,7 @@ interface InitGameStatus {
|
|||||||
lockControl: boolean;
|
lockControl: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated 迟早给你删喽\
|
||||||
* 勇士移动状态,每个数字干啥的自己去libs翻,这东西太复杂了,不过应该不会有人用这个东西吧(
|
* 勇士移动状态,每个数字干啥的自己去libs翻,这东西太复杂了,不过应该不会有人用这个东西吧(
|
||||||
*/
|
*/
|
||||||
heroMoving: number;
|
heroMoving: number;
|
||||||
@ -792,6 +793,11 @@ interface Follower {
|
|||||||
* 跟随者的图片id
|
* 跟随者的图片id
|
||||||
*/
|
*/
|
||||||
name: ImageIds;
|
name: ImageIds;
|
||||||
|
|
||||||
|
direction: Dir;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
stop: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HeroStatistics {
|
interface HeroStatistics {
|
||||||
|
@ -290,10 +290,10 @@ gameKey
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.realize('@shop_add', () => {
|
.realize('@shop_add', () => {
|
||||||
count.value--;
|
count.value++;
|
||||||
})
|
})
|
||||||
.realize('@shop_min', () => {
|
.realize('@shop_min', () => {
|
||||||
count.value++;
|
count.value--;
|
||||||
})
|
})
|
||||||
.realize('exit', () => {
|
.realize('exit', () => {
|
||||||
exit();
|
exit();
|
||||||
@ -311,10 +311,12 @@ function exit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
core.lockControl();
|
||||||
core.status.route.push(`openShop:${id}`);
|
core.status.route.push(`openShop:${id}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
core.unlockControl();
|
||||||
gameKey.dispose(props.ui.symbol);
|
gameKey.dispose(props.ui.symbol);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user