mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-19 04:19:30 +08:00
章节显示
This commit is contained in:
parent
e165bc9f74
commit
a1a6539583
@ -18,7 +18,7 @@
|
||||
"chart.js": "^4.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"lz-string": "^1.4.4",
|
||||
"mutate-animate": "^0.1.0",
|
||||
"mutate-animate": "^1.0.0",
|
||||
"vue": "^3.2.41"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -20,7 +20,7 @@ specifiers:
|
||||
less: ^4.1.3
|
||||
lodash: ^4.17.21
|
||||
lz-string: ^1.4.4
|
||||
mutate-animate: ^0.1.0
|
||||
mutate-animate: ^1.0.0
|
||||
terser: ^5.15.1
|
||||
ts-node: ^10.9.1
|
||||
typescript: ^4.6.4
|
||||
@ -36,7 +36,7 @@ dependencies:
|
||||
chart.js: 4.0.1
|
||||
lodash: 4.17.21
|
||||
lz-string: 1.4.4
|
||||
mutate-animate: 0.1.0
|
||||
mutate-animate: 1.0.0
|
||||
vue: 3.2.45
|
||||
|
||||
devDependencies:
|
||||
@ -2468,8 +2468,8 @@ packages:
|
||||
resolution: {integrity: sha512-Tr1knR3d2mKvvWthlk7202rywKbiOm4rVFLsfAaSIhJ6dt9o47W4S+JMtWhd/PW9Wrdew2/S2fSvhz3E2gkfEg==}
|
||||
dev: true
|
||||
|
||||
/mutate-animate/0.1.0:
|
||||
resolution: {integrity: sha512-XOdyX/PDFYZDpUpaqPeLOfdeDYXQcThWsuLUQpp3z6FbReDV23jIN0Vzv5QLUy+6CDMHEBZHfsumODrlKJva+g==}
|
||||
/mutate-animate/1.0.0:
|
||||
resolution: {integrity: sha512-Vt6zDunYjunQAJQ8mXTnamjbubWOM/hM0W+umvJKOvFP6klRAJPHO5R1XUKqEe2/mM9QM+aUfKb2q8Z0Ybwj/A==}
|
||||
dev: false
|
||||
|
||||
/nan/2.17.0:
|
||||
|
@ -37,7 +37,7 @@ main.floors.MT0=
|
||||
"请耐心等待字体加载完成,否则很多地方显示会很奇怪,大概需要十秒,过一段时间打开任意界面再关闭即可",
|
||||
{
|
||||
"type": "function",
|
||||
"function": "function(){\ncore.displayChapter(0);\n}"
|
||||
"function": "function(){\ncore.showChapter('序章 起源');\n}"
|
||||
}
|
||||
],
|
||||
"parallelDo": "",
|
||||
|
@ -3547,236 +3547,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
}
|
||||
}
|
||||
},
|
||||
chapter: function () {
|
||||
// 章节显示
|
||||
var chapter = '',
|
||||
description = '';
|
||||
// 显示章节
|
||||
this.displayChapter = function (index) {
|
||||
if (core.isReplaying()) return;
|
||||
var number = core.replaceNumberWithChinese(index);
|
||||
// 获取第几章
|
||||
chapter = '第' + number + '章';
|
||||
if (index == 0) chapter = '序章';
|
||||
// 获取描述
|
||||
switch (index) {
|
||||
case 0:
|
||||
description = '起源';
|
||||
break;
|
||||
case 1:
|
||||
description = '勇气';
|
||||
break;
|
||||
case 2:
|
||||
description = '智慧';
|
||||
break;
|
||||
}
|
||||
core.coreChapterAnimate(chapter, description);
|
||||
};
|
||||
// 替换数字大小写
|
||||
this.replaceNumberWithChinese = function (number) {
|
||||
if (number == 0) return '零';
|
||||
if (number == 1) return '一';
|
||||
if (number == 2) return '二';
|
||||
if (number == 3) return '三';
|
||||
if (number == 4) return '四';
|
||||
if (number == 5) return '五';
|
||||
if (number == 6) return '六';
|
||||
if (number == 7) return '七';
|
||||
if (number == 8) return '八';
|
||||
if (number == 9) return '九';
|
||||
if (number == 10) return '十';
|
||||
};
|
||||
// 核心动画运算
|
||||
this.coreChapterAnimate = function (chapter, description) {
|
||||
// 先建画布
|
||||
if (core.isReplaying()) return;
|
||||
core.createCanvas('chapter', 0, 0, 480, 480, 100);
|
||||
var frame = 0,
|
||||
speed = 0,
|
||||
left = -480,
|
||||
down = 240;
|
||||
// 一秒50帧
|
||||
core.lockControl();
|
||||
var interval = setInterval(() => {
|
||||
core.clearMap('chapter');
|
||||
speed = core.hyperbolicCosine((frame - 84) * 0.05);
|
||||
left += speed / 2;
|
||||
// 背景
|
||||
if (frame <= 110) {
|
||||
core.fillRect(
|
||||
'chapter',
|
||||
0,
|
||||
-240 - left,
|
||||
480,
|
||||
left + 480,
|
||||
'#000000'
|
||||
);
|
||||
core.fillRect(
|
||||
'chapter',
|
||||
0,
|
||||
240,
|
||||
480,
|
||||
left + 480,
|
||||
'#000000'
|
||||
);
|
||||
} else {
|
||||
core.fillRect('chapter', 0, 0, 480, down, '#000000');
|
||||
core.fillRect(
|
||||
'chapter',
|
||||
0,
|
||||
480 - down,
|
||||
480,
|
||||
down,
|
||||
'#000000'
|
||||
);
|
||||
down -= speed / 2;
|
||||
}
|
||||
// 中间矩形
|
||||
if (frame <= 100) {
|
||||
core.fillRect(
|
||||
'chapter',
|
||||
0,
|
||||
240 - frame / 5,
|
||||
480,
|
||||
frame / 2.5,
|
||||
[255, 255, 255, 0.5 + frame / 200]
|
||||
);
|
||||
} else {
|
||||
core.fillRect(
|
||||
'chapter',
|
||||
0,
|
||||
240 - 2100 / (205 - frame),
|
||||
480,
|
||||
4200 / (205 - frame),
|
||||
[255, 255, 255, (175 - frame) / 75]
|
||||
);
|
||||
}
|
||||
// 上下方线
|
||||
core.fillRect('chapter', left, 210, 300, 10, '#FF4D00');
|
||||
core.fillRect('chapter', 180 - left, 260, 300, 10, '#2DFFFC');
|
||||
core.fillRect('chapter', left + 310, 210, 10, 10, '#FF4D00');
|
||||
core.fillRect('chapter', 160 - left, 260, 10, 10, '#2DFFFC');
|
||||
core.fillPolygon(
|
||||
'chapter',
|
||||
[
|
||||
[left + 330, 210],
|
||||
[left + 330, 220],
|
||||
[left + 340, 220]
|
||||
],
|
||||
'#FF4D00'
|
||||
);
|
||||
core.fillPolygon(
|
||||
'chapter',
|
||||
[
|
||||
[150 - left, 260],
|
||||
[140 - left, 260],
|
||||
[150 - left, 270]
|
||||
],
|
||||
'#2DFFFC'
|
||||
);
|
||||
// 闪光条
|
||||
for (var i = 5; i > 0; i--) {
|
||||
if (frame <= 150) {
|
||||
core.drawLine(
|
||||
'chapter',
|
||||
0,
|
||||
220,
|
||||
left + 320,
|
||||
220,
|
||||
[255, 255, 255, 0.4],
|
||||
i
|
||||
);
|
||||
core.drawLine(
|
||||
'chapter',
|
||||
480,
|
||||
260,
|
||||
160 - left,
|
||||
260,
|
||||
[255, 255, 255, 0.4],
|
||||
i
|
||||
);
|
||||
} else {
|
||||
core.drawLine(
|
||||
'chapter',
|
||||
0,
|
||||
220,
|
||||
left + 320,
|
||||
220,
|
||||
[255, 255, 255, 0.4 - (frame - 150) / 125],
|
||||
i
|
||||
);
|
||||
core.drawLine(
|
||||
'chapter',
|
||||
480,
|
||||
260,
|
||||
160 - left,
|
||||
260,
|
||||
[255, 255, 255, 0.4 - (frame - 150) / 125],
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
core.fillEllipse(
|
||||
'chapter',
|
||||
left + 320,
|
||||
220,
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
[255, 255, 255, 0.8]
|
||||
);
|
||||
core.fillEllipse(
|
||||
'chapter',
|
||||
left + 320,
|
||||
220,
|
||||
2,
|
||||
10,
|
||||
0,
|
||||
[255, 255, 255, 0.8]
|
||||
);
|
||||
core.fillEllipse(
|
||||
'chapter',
|
||||
160 - left,
|
||||
260,
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
[255, 255, 255, 0.8]
|
||||
);
|
||||
core.fillEllipse(
|
||||
'chapter',
|
||||
160 - left,
|
||||
260,
|
||||
2,
|
||||
10,
|
||||
0,
|
||||
[255, 255, 255, 0.8]
|
||||
);
|
||||
// 字
|
||||
core.setTextAlign('chapter', 'center');
|
||||
core.fillBoldText(
|
||||
'chapter',
|
||||
chapter + ' ' + description,
|
||||
left + 360,
|
||||
250,
|
||||
'#ffffff',
|
||||
'#000000',
|
||||
'28px scroll'
|
||||
);
|
||||
if (frame >= 200) {
|
||||
clearInterval(interval);
|
||||
core.deleteCanvas('chapter');
|
||||
core.unlockControl();
|
||||
}
|
||||
if (frame == 80) core.playSound('chapter.mp3');
|
||||
frame++;
|
||||
}, 20);
|
||||
};
|
||||
// 返回双曲余弦值
|
||||
this.hyperbolicCosine = function (number) {
|
||||
return 0.5 * (Math.pow(Math.E, number) + Math.pow(Math.E, -number));
|
||||
};
|
||||
},
|
||||
intelligenceTree: function () {
|
||||
// 智慧加点
|
||||
var list;
|
||||
@ -9046,6 +8816,8 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
if (core.isReplaying()) showToolbox = true;
|
||||
core.plugin.showStatusBar.value = false;
|
||||
|
||||
var statusItems = core.dom.status,
|
||||
toolItems = core.dom.tools;
|
||||
core.setFlag('hideStatusBar', true);
|
||||
core.setFlag('showToolbox', showToolbox || null);
|
||||
if (
|
||||
@ -9059,5 +8831,10 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = {
|
||||
core.dom.toolBar.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
this.showChapter = function (chapter) {
|
||||
core.plugin.chapterContent.value = chapter;
|
||||
core.plugin.chapterShowed.value = true;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -408,25 +408,25 @@ p#name {
|
||||
|
||||
@-webkit-keyframes selector {
|
||||
0% {
|
||||
opacity: 0.95;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.55;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.25;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.95;
|
||||
opacity: 0.55;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes selector {
|
||||
0% {
|
||||
opacity: 0.95;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.55;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.25;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.95;
|
||||
opacity: 0.55;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
<div id="non-ui">
|
||||
<StatusBar v-if="showStatusBar"></StatusBar>
|
||||
<MarkedEnemy></MarkedEnemy>
|
||||
<Chapter v-if="chapterShowed" :chapter="chapterContent"></Chapter>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -10,6 +11,8 @@ import { ref } from 'vue';
|
||||
import StatusBar from './ui/statusBar.vue';
|
||||
import { showStatusBar } from './plugin/uiController';
|
||||
import MarkedEnemy from './ui/markedEnemy.vue';
|
||||
import Chapter from './ui/chapter.vue';
|
||||
import { chapterContent, chapterShowed } from './plugin/ui/chapter';
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -10,8 +10,8 @@
|
||||
<span class="name">{{ enemy.name }}</span>
|
||||
<BoxAnimate
|
||||
:id="enemy.id"
|
||||
:width="isMobile ? 32 : 50"
|
||||
:height="isMobile ? 32 : 50"
|
||||
:width="isMobile ? 32 : w"
|
||||
:height="isMobile ? 32 : w"
|
||||
style="margin: 5%"
|
||||
></BoxAnimate>
|
||||
<div
|
||||
@ -136,6 +136,8 @@ const emits = defineEmits<{
|
||||
|
||||
const core = window.core;
|
||||
|
||||
const w = window.innerWidth * 0.032;
|
||||
|
||||
/**
|
||||
* 选择这个怪物时
|
||||
*/
|
||||
|
@ -5,7 +5,8 @@
|
||||
"在本塔中,状态栏与游戏画面是分开的。你可以自由拖动状态栏,也可以修改其大小。",
|
||||
"具体方法如下:点击一下状态栏之后,左上角的拖拽图标会放大,此时你可以按住它拖动状态栏。",
|
||||
"你可以直接将鼠标放到状态栏的边框上,然后直接拖动以改变状态栏的大小。手机端可以先点击一下状态栏使边框",
|
||||
"变宽,然后拖动。电脑端点击状态栏也可以使边框变宽。",
|
||||
"变宽,然后拖动。电脑端点击状态栏也可以使边框变宽。如果你想折叠状态栏,完全可以拖动状态栏的下边框,",
|
||||
"然后直接拖动至上方,这时状态栏便会变成一条线,相当于折叠了状态栏",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"状态栏可以纵向滚动,如果你发现状态栏显示不全,可以尝试拉大状态栏,或者纵向拖动状态栏,就像网页上下滚动一样。",
|
||||
@ -30,8 +31,10 @@
|
||||
"<br>",
|
||||
"3. 当勇士恰好踩到怪物的临界时,会进行提示",
|
||||
"<br>",
|
||||
"4. 被标记的怪物会出现类似于状态栏的盒子,可以随意拖动和改变大小。你也可以选择关闭这个盒子,",
|
||||
"被关闭后可以通过重新标记来打开。这个盒子会显示标记的怪物的临界与伤害信息等,依然可以纵向滚动。",
|
||||
"4. 当怪物零伤时,会进行提示",
|
||||
"<br>",
|
||||
"5. 被标记的怪物会出现类似于状态栏的盒子,可以随意拖动和改变大小。你也可以选择关闭这个盒子,",
|
||||
"被关闭后可以通过重新标记来打开。这个盒子会显示标记的怪物的临界与伤害信息等,与状态栏一样,可以纵向滚动。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"这个功能可以用于标记boss或者较强的挡路怪,当这些怪能够攻击时你可以直接收到信息,不需要再时刻费心注意怪物的伤害。"
|
||||
@ -40,7 +43,54 @@
|
||||
"book": {
|
||||
"text": "怪物手册",
|
||||
"desc": [
|
||||
""
|
||||
"本塔的怪物手册功能很多,下面一一介绍。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"怪物手册打开的时候有一个0.6秒的动画,如果不想要可以在开头捡的系统设置里面关闭。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"打开怪物手册后,怪物手册的布局与样板自带的类似。与样板不同的是,这里的怪物手册不再是翻页式结构。",
|
||||
"这里的怪物手册是滚动式结构,你可以像浏览网页一样,用手指或鼠标上下滚动或者拖动右边的滚动条,电脑端还可以使用滚轮。",
|
||||
"对于电脑端,还可以使用键盘操作。上和下可以上下选择怪物,左和右可以向上或向下移动5个怪物。这些操作与样板都类似。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"点击一个怪物或者按下回车空格后,将进入怪物详细信息界面。这个界面分为多个栏,分别是特殊属性栏,详细临界栏,更多信息栏。",
|
||||
"进入怪物详细信息后默认在特殊属性栏,该栏可以查看怪物的特殊属性。注意特殊属性依然可以纵向滚动。在特殊属性下方,",
|
||||
"是怪物的临界表,可以粗略地查看怪物的临界信息。在下方,你可以点击详细临界信息进入详细临界栏。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"在详细临界栏中,怪物的伤害会以可视化折线图的方式显示出来,从而你可以更为清晰地看出怪物减伤趋势。",
|
||||
"除了查看怪物伤害曲线,你还可以规划宝石。每个折线图下方都有一个滑动条,你可以拖动来模拟吃宝石。",
|
||||
"注意,拖动时,滑动条左边会显示当前的加攻或加防次数,这个数值指的是在勇士所在地图中需要吃的宝石数量。",
|
||||
"例如,当前勇士所在地图中一个宝石最低加2点攻击,加攻数值为3,那么勇士的攻击增加量就为6。",
|
||||
"勇士增加的攻击数值也会在下方显示。当加攻次数和加防次数改变时,折线图也会变化。",
|
||||
"当前状态下怪物的伤害以及减伤总量也会在下方显示。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"在特殊属性栏,点击下方的怪物更多信息可以进入更多信息栏。此栏中,你可以查看怪物描述。但这不是这一栏的核心功能。",
|
||||
"这一栏的核心功能是标记怪物。被标记的怪物会有一些非常方便的行为,这些行为可以在“标记怪物”说明中查看。"
|
||||
]
|
||||
},
|
||||
"tools": {
|
||||
"text": "道具栏与装备栏",
|
||||
"desc": [
|
||||
"道具栏与装备栏打开时会有一个0.6秒的动画,如果不想要可以在开头捡的系统设置里面关闭。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"本塔的道具栏没有特别之处,这里不需要说明。主要是装备栏。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"本塔的装备栏手机和电脑端不同,电脑端比手机端多了一个勇士属性的显示。在装备栏的装备列表栏,",
|
||||
"上方有两个选择框与一个排序方式的选项。这三个可以筛选你拥有的装备并进行排序,从而让你能够更清楚地知道哪个装备更强。",
|
||||
"第一个选择框可以筛选装备增加的属性,如果装备不增加选择的属性,那么会不显示。第二个选择框可以筛选增加的属性的方式,",
|
||||
"有数值增加和百分比增加两种。在这个选择框右边有一个图标,这个图标可以改变武器的排序方式,有升序和降序两种,默认为升序。",
|
||||
"例如,你拥有两个装备,分别增加10攻击和20攻击,三者你分别选择了攻击,数值,升序,那么增加10攻击的装备会排在上面,",
|
||||
"而增加20攻击的装备会排在下面。",
|
||||
"<br>",
|
||||
"<br>",
|
||||
"对于电脑端,如果你想装装备,可以直接拖动装备至装备孔,也可以选中装备后再次点击。手机端暂时无法拖动装备。当选中一个装备后,",
|
||||
"电脑端和手机端均会显示装备增加或减少的属性,注意有的装备可能不增加属性但是有特殊功能。对于电脑端,",
|
||||
"还会直接在勇士属性栏显示增加或减少的属性。"
|
||||
]
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import utils from './plugin/utils';
|
||||
import status from './plugin/ui/statusBar';
|
||||
import mark from './plugin/mark';
|
||||
import setting from './plugin/settings';
|
||||
import chapter from './plugin/ui/chapter';
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
// 每个引入的插件都要在这里执行,否则不会被转发
|
||||
@ -18,7 +19,8 @@ window.addEventListener('load', () => {
|
||||
utils(),
|
||||
status(),
|
||||
mark(),
|
||||
setting()
|
||||
setting(),
|
||||
chapter()
|
||||
];
|
||||
|
||||
// 初始化所有插件,并转发到core上
|
||||
|
8
src/plugin/ui/chapter.ts
Normal file
8
src/plugin/ui/chapter.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
export const chapterShowed = ref(false);
|
||||
export const chapterContent = ref('');
|
||||
|
||||
export default function init() {
|
||||
return { chapterShowed, chapterContent };
|
||||
}
|
154
src/types/plugin.d.ts
vendored
154
src/types/plugin.d.ts
vendored
@ -14,7 +14,7 @@ type CanParseCss = keyof {
|
||||
: never]: CSSStyleDeclaration[P];
|
||||
};
|
||||
|
||||
interface PluginDeclaration extends PluginUtils {
|
||||
interface PluginDeclaration extends PluginUtils, PluginUis, PluginUse {
|
||||
/**
|
||||
* 添加函数 例:添加弹出文字,像这个就可以使用core.addPop或core.plugin.addPop调用
|
||||
* @param px 弹出的横坐标
|
||||
@ -26,80 +26,12 @@ interface PluginDeclaration extends PluginUtils {
|
||||
/** 添加变量 例:所有的正在弹出的文字,像这个就可以使用core.plugin.pop获取 */
|
||||
pop: any[];
|
||||
|
||||
/** 怪物手册的怪物详细信息的初始位置 */
|
||||
bookDetailPos: number;
|
||||
|
||||
/** 怪物手册详细信息展示的怪物 */
|
||||
bookDetailEnemy: DetailedEnemy;
|
||||
|
||||
/** ui是否使用渐变 */
|
||||
readonly transition: Ref<boolean>;
|
||||
|
||||
/** 手册是否打开 */
|
||||
readonly bookOpened: Ref<boolean>;
|
||||
|
||||
/** 道具栏是否打开 */
|
||||
readonly toolOpened: Ref<boolean>;
|
||||
|
||||
/** 装备栏是否打开 */
|
||||
readonly equipOpened: Ref<boolean>;
|
||||
|
||||
/** 是否显示状态栏 */
|
||||
readonly showStatusBar: Ref<boolean>;
|
||||
|
||||
/** 设置界面是否打开 */
|
||||
readonly settingsOpened: Ref<boolean>;
|
||||
|
||||
/** ui栈 */
|
||||
readonly uiStack: Ref<Component[]>;
|
||||
|
||||
/** 是否是移动设备 */
|
||||
readonly isMobile: boolean;
|
||||
|
||||
/** 状态栏信息,取反后刷新状态栏 */
|
||||
readonly statusBarStatus: Ref<boolean>;
|
||||
|
||||
/** 检查标记的怪物,取反后更新显示信息 */
|
||||
readonly checkMarkedStatus: Ref<boolean>;
|
||||
|
||||
/**
|
||||
* 向一个元素添加拖拽事件
|
||||
* @param ele 目标元素
|
||||
* @param fn 推拽时触发的函数,传入x y和鼠标事件或点击事件
|
||||
* @param ondown 鼠标按下时执行的函数
|
||||
* @param global 是否全局拖拽,即拖拽后鼠标或手指离开元素后是否依然视为正在拖拽
|
||||
*/
|
||||
useDrag(
|
||||
ele: HTMLElement,
|
||||
fn: DragFn,
|
||||
ondown?: DragFn,
|
||||
onUp?: (e: MouseEvent | TouchEvent) => void,
|
||||
global: boolean = false
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 去除一个全局拖拽函数
|
||||
* @param fn 要去除的函数
|
||||
*/
|
||||
cancelGlobalDrag(fn: DragFn): void;
|
||||
|
||||
/**
|
||||
* 当触发滚轮时执行函数
|
||||
* @param ele 目标元素
|
||||
* @param fn 当滚轮触发时执行的函数
|
||||
*/
|
||||
useWheel(
|
||||
ele: HTMLElement,
|
||||
fn: (x: number, y: number, z: number, e: WheelEvent) => void
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 当鼠标或手指松开时执行函数
|
||||
* @param ele 目标元素
|
||||
* @param fn 当鼠标或手指松开时执行的函数
|
||||
*/
|
||||
useUp(ele: HTMLElement, fn: DragFn): void;
|
||||
|
||||
/**
|
||||
* 添加一个动画
|
||||
* @param fn 要添加的函数
|
||||
@ -143,6 +75,90 @@ interface PluginUtils {
|
||||
parseCss(css: string): Partial<Record<CanParseCss, string>>;
|
||||
}
|
||||
|
||||
interface PluginUis {
|
||||
/** 怪物手册的怪物详细信息的初始位置 */
|
||||
bookDetailPos: number;
|
||||
|
||||
/** 怪物手册详细信息展示的怪物 */
|
||||
bookDetailEnemy: DetailedEnemy;
|
||||
|
||||
/** ui是否使用渐变 */
|
||||
readonly transition: Ref<boolean>;
|
||||
|
||||
/** 手册是否打开 */
|
||||
readonly bookOpened: Ref<boolean>;
|
||||
|
||||
/** 道具栏是否打开 */
|
||||
readonly toolOpened: Ref<boolean>;
|
||||
|
||||
/** 装备栏是否打开 */
|
||||
readonly equipOpened: Ref<boolean>;
|
||||
|
||||
/** 是否显示状态栏 */
|
||||
readonly showStatusBar: Ref<boolean>;
|
||||
|
||||
/** 设置界面是否打开 */
|
||||
readonly settingsOpened: Ref<boolean>;
|
||||
|
||||
/** 是否正在进行章节显示 */
|
||||
readonly chapterShowed: Ref<boolean>;
|
||||
|
||||
/** 章节显示的内容 */
|
||||
readonly chapterContent: Ref<boolean>;
|
||||
|
||||
/** ui栈 */
|
||||
readonly uiStack: Ref<Component[]>;
|
||||
|
||||
/**
|
||||
* 显示章节
|
||||
* @param chapter 显示的文字
|
||||
*/
|
||||
showChapter(chapter: string): void;
|
||||
}
|
||||
|
||||
interface PluginUse {
|
||||
/** 是否是移动设备 */
|
||||
readonly isMobile: boolean;
|
||||
|
||||
/**
|
||||
* 向一个元素添加拖拽事件
|
||||
* @param ele 目标元素
|
||||
* @param fn 推拽时触发的函数,传入x y和鼠标事件或点击事件
|
||||
* @param ondown 鼠标按下时执行的函数
|
||||
* @param global 是否全局拖拽,即拖拽后鼠标或手指离开元素后是否依然视为正在拖拽
|
||||
*/
|
||||
useDrag(
|
||||
ele: HTMLElement,
|
||||
fn: DragFn,
|
||||
ondown?: DragFn,
|
||||
onUp?: (e: MouseEvent | TouchEvent) => void,
|
||||
global: boolean = false
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 去除一个全局拖拽函数
|
||||
* @param fn 要去除的函数
|
||||
*/
|
||||
cancelGlobalDrag(fn: DragFn): void;
|
||||
|
||||
/**
|
||||
* 当触发滚轮时执行函数
|
||||
* @param ele 目标元素
|
||||
* @param fn 当滚轮触发时执行的函数
|
||||
*/
|
||||
useWheel(
|
||||
ele: HTMLElement,
|
||||
fn: (x: number, y: number, z: number, e: WheelEvent) => void
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 当鼠标或手指松开时执行函数
|
||||
* @param ele 目标元素
|
||||
* @param fn 当鼠标或手指松开时执行的函数
|
||||
*/
|
||||
useUp(ele: HTMLElement, fn: DragFn): void;
|
||||
}
|
||||
|
||||
type Forward<T> = {
|
||||
[K in keyof T as T[K] extends Function
|
||||
? K extends `_${string}`
|
||||
|
@ -227,12 +227,9 @@ onUnmounted(async () => {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#back {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
#tools {
|
||||
height: 6%;
|
||||
font-size: 3.2vh;
|
||||
}
|
||||
|
||||
.tools {
|
||||
|
144
src/ui/chapter.vue
Normal file
144
src/ui/chapter.vue
Normal file
@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div id="chapter">
|
||||
<canvas id="chapter-back"></canvas>
|
||||
<span id="chapter-text">{{ chapter }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Animation, hyper, power, sleep } from 'mutate-animate';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { has } from '../plugin/utils';
|
||||
import { chapterShowed } from '../plugin/ui/chapter';
|
||||
|
||||
const props = defineProps<{
|
||||
chapter: string;
|
||||
}>();
|
||||
|
||||
let canvas: HTMLCanvasElement;
|
||||
let ctx: CanvasRenderingContext2D;
|
||||
let text: HTMLSpanElement;
|
||||
|
||||
onMounted(async () => {
|
||||
canvas = document.getElementById('chapter-back') as HTMLCanvasElement;
|
||||
ctx = canvas.getContext('2d')!;
|
||||
text = document.getElementById('chapter-text') as HTMLSpanElement;
|
||||
|
||||
const ani = new Animation();
|
||||
const w = window.innerWidth * devicePixelRatio;
|
||||
const h = window.innerHeight * devicePixelRatio;
|
||||
ctx.font = '5vh scroll';
|
||||
const textWidth = ctx.measureText(props.chapter).width;
|
||||
const line = h * 0.05;
|
||||
ani.register('rect', 0);
|
||||
ani.register('line', -10);
|
||||
ani.register('lineOpacity', 1);
|
||||
ani.register('rect2', h / 2);
|
||||
ani.register('text', window.innerWidth + 10 + textWidth);
|
||||
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
canvas.style.width = `${window.innerWidth}px`;
|
||||
canvas.style.height = `${window.innerHeight}px`;
|
||||
text.style.left = `${w + 10}px`;
|
||||
text.style.top = `${window.innerHeight / 2 - h * 0.025}px`;
|
||||
text.style.height = `${h * 0.05}px`;
|
||||
text.style.width = `${textWidth}px`;
|
||||
|
||||
let soundPlayed = false;
|
||||
let started = false;
|
||||
|
||||
ani.ticker.add(time => {
|
||||
if (!has(time) || isNaN(time)) return;
|
||||
if (!started) {
|
||||
started = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time >= 4000) chapterShowed.value = false;
|
||||
|
||||
if (!soundPlayed && time >= 1500) {
|
||||
soundPlayed = true;
|
||||
core.playSound('chapter.mp3');
|
||||
}
|
||||
ctx.restore();
|
||||
ctx.save();
|
||||
text.style.left = `${ani.value.text}px`;
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
if (time <= 2000) {
|
||||
ctx.fillRect(0, h / 2, w, -ani.value.rect);
|
||||
ctx.fillRect(0, h / 2, w, ani.value.rect);
|
||||
} else if (time >= 2000 && time <= 3050) {
|
||||
ctx.fillRect(0, 0, w, ani.value.rect2);
|
||||
ctx.fillRect(0, h, w, -ani.value.rect2);
|
||||
}
|
||||
ctx.shadowColor = '#fff';
|
||||
ctx.shadowBlur = 3;
|
||||
ctx.shadowOffsetX = 0;
|
||||
ctx.shadowOffsetY = 0;
|
||||
ctx.lineWidth = 3;
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.globalAlpha = ani.value.lineOpacity;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, h / 2 - line);
|
||||
ctx.lineTo(ani.value.line, h / 2 - line);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(w, h / 2 + line);
|
||||
ctx.lineTo(w - ani.value.line, h / 2 + line);
|
||||
ctx.stroke();
|
||||
ctx.shadowBlur = 0;
|
||||
ctx.filter = 'blur(5px)';
|
||||
ctx.beginPath();
|
||||
ctx.arc(ani.value.line, h / 2 - line, 10, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.beginPath();
|
||||
ctx.arc(w - ani.value.line, h / 2 + line, 10, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
});
|
||||
|
||||
ani.mode(hyper('tan', 'center'))
|
||||
.time(3000)
|
||||
.absolute()
|
||||
.apply('line', w + 10)
|
||||
.mode(hyper('sin', 'in'))
|
||||
.time(1000)
|
||||
.apply('rect', h / 2)
|
||||
.mode(hyper('tan', 'center'))
|
||||
.time(3000)
|
||||
.apply('text', -textWidth * 2 - 10);
|
||||
|
||||
await sleep(2000);
|
||||
ani.mode(hyper('sin', 'in')).time(1000).apply('rect2', 0);
|
||||
await sleep(1000);
|
||||
ani.mode(hyper('sin', 'out')).time(1000).apply('lineOpacity', 0);
|
||||
|
||||
await sleep(1000);
|
||||
ani.ticker.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#chapter {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#chapter-back {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#chapter-text {
|
||||
position: fixed;
|
||||
font-family: 'scroll';
|
||||
font-size: 5vh;
|
||||
text-shadow: 0px 0px 5px #fff;
|
||||
}
|
||||
</style>
|
@ -461,7 +461,7 @@ onUnmounted(() => {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: 2em;
|
||||
font-size: 3.2vh;
|
||||
height: 5vh;
|
||||
justify-content: space-between;
|
||||
font-family: 'normal';
|
||||
|
@ -275,7 +275,7 @@ onUnmounted(() => {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-family: 'normal';
|
||||
font-size: 2em;
|
||||
font-size: 3.2vh;
|
||||
height: 5vh;
|
||||
justify-content: space-between;
|
||||
|
||||
@ -403,12 +403,11 @@ onUnmounted(() => {
|
||||
#toolbox-main {
|
||||
flex-direction: column-reverse;
|
||||
height: 100%;
|
||||
border-top: 1px solid #ddd4;
|
||||
}
|
||||
|
||||
.item-list {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: 40vh;
|
||||
}
|
||||
|
||||
.divider {
|
||||
|
Loading…
Reference in New Issue
Block a user