2022-12-29 19:57:31 +08:00
|
|
|
<template>
|
|
|
|
<div id="chapter">
|
|
|
|
<canvas id="chapter-back"></canvas>
|
|
|
|
<span id="chapter-text">{{ chapter }}</span>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
2023-11-13 12:53:22 +08:00
|
|
|
import { Animation, hyper, sleep } from 'mutate-animate';
|
|
|
|
import { onMounted } from 'vue';
|
2022-12-29 19:57:31 +08:00
|
|
|
import { has } from '../plugin/utils';
|
2023-11-13 12:53:22 +08:00
|
|
|
import { GameUi } from '@/core/main/custom/ui';
|
2024-01-24 21:32:49 +08:00
|
|
|
import { fixedUi } from '@/core/main/init/ui';
|
2022-12-29 19:57:31 +08:00
|
|
|
|
|
|
|
const props = defineProps<{
|
2023-11-13 12:53:22 +08:00
|
|
|
num: number;
|
|
|
|
ui: GameUi;
|
2022-12-29 19:57:31 +08:00
|
|
|
chapter: string;
|
|
|
|
}>();
|
|
|
|
|
2022-12-30 14:14:28 +08:00
|
|
|
let can: HTMLCanvasElement;
|
2022-12-29 19:57:31 +08:00
|
|
|
let ctx: CanvasRenderingContext2D;
|
|
|
|
let text: HTMLSpanElement;
|
|
|
|
|
|
|
|
onMounted(async () => {
|
2022-12-30 14:14:28 +08:00
|
|
|
can = document.getElementById('chapter-back') as HTMLCanvasElement;
|
|
|
|
ctx = can.getContext('2d')!;
|
2022-12-29 19:57:31 +08:00
|
|
|
text = document.getElementById('chapter-text') as HTMLSpanElement;
|
|
|
|
|
|
|
|
const ani = new Animation();
|
|
|
|
const w = window.innerWidth * devicePixelRatio;
|
|
|
|
const h = window.innerHeight * devicePixelRatio;
|
2023-11-13 12:53:22 +08:00
|
|
|
ctx.font = '5vh normal';
|
2022-12-29 19:57:31 +08:00
|
|
|
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);
|
|
|
|
|
2022-12-30 14:14:28 +08:00
|
|
|
can.width = w;
|
|
|
|
can.height = h;
|
|
|
|
can.style.width = `${window.innerWidth}px`;
|
|
|
|
can.style.height = `${window.innerHeight}px`;
|
2022-12-29 19:57:31 +08:00
|
|
|
text.style.left = `${w + 10}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;
|
|
|
|
}
|
|
|
|
|
2022-12-31 00:52:10 +08:00
|
|
|
if (time >= 4050) {
|
2024-01-24 21:32:49 +08:00
|
|
|
fixedUi.close(props.num);
|
2022-12-30 14:14:28 +08:00
|
|
|
ani.ticker.destroy();
|
|
|
|
}
|
2022-12-29 19:57:31 +08:00
|
|
|
|
|
|
|
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)
|
2023-01-05 22:21:40 +08:00
|
|
|
.mode(hyper('sin', 'out'))
|
2022-12-29 19:57:31 +08:00
|
|
|
.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);
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
#chapter {
|
|
|
|
width: 100vw;
|
|
|
|
height: 100vh;
|
|
|
|
position: fixed;
|
|
|
|
left: 0;
|
|
|
|
top: 0;
|
|
|
|
user-select: none;
|
2023-04-22 10:17:04 +08:00
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
2022-12-29 19:57:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#chapter-back {
|
2023-04-22 10:17:04 +08:00
|
|
|
position: fixed;
|
2022-12-29 19:57:31 +08:00
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
#chapter-text {
|
2023-04-22 10:17:04 +08:00
|
|
|
position: relative;
|
|
|
|
font-family: 'normal';
|
2022-12-29 19:57:31 +08:00
|
|
|
font-size: 5vh;
|
|
|
|
text-shadow: 0px 0px 5px #fff;
|
|
|
|
}
|
|
|
|
</style>
|