add audio effects
This commit is contained in:
parent
9c722afe9d
commit
32c01bf868
BIN
src/assets/game/share_mask.png
Normal file
BIN
src/assets/game/share_mask.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
19
src/assets/sounds/index.ts
Normal file
19
src/assets/sounds/index.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { EasyAudio } from "./utils";
|
||||||
|
|
||||||
|
import 按钮音效 from "./按钮音效.mp3"
|
||||||
|
import 弹簧蓄力结束弹射 from "./弹簧蓄力结束弹射有效.mp3"
|
||||||
|
import 弹簧蓄力下拉音效 from "./弹簧蓄力下拉音效.mp3"
|
||||||
|
import 风声 from "./风声.mp3"
|
||||||
|
import 标题出现 from "./首页标题、尾标出现音效.mp3"
|
||||||
|
import 结算 from "./最终结算音效.mp3"
|
||||||
|
|
||||||
|
const ea = new EasyAudio([
|
||||||
|
{name: "按钮音效", audioUrl: 按钮音效, volume: 0.5},
|
||||||
|
{name: "弹簧蓄力结束弹射", audioUrl: 弹簧蓄力结束弹射, volume: 0.5},
|
||||||
|
{name: "弹簧蓄力下拉音效", audioUrl: 弹簧蓄力下拉音效, volume: 0.5},
|
||||||
|
{name: "风声", audioUrl: 风声, volume: 0.5},
|
||||||
|
{name: "标题出现", audioUrl: 标题出现, volume: 0.5},
|
||||||
|
{name: "结算", audioUrl: 结算, volume: 0.5},
|
||||||
|
]);
|
||||||
|
|
||||||
|
export default ea;
|
||||||
114
src/assets/sounds/utils.ts
Normal file
114
src/assets/sounds/utils.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
export class EasyAudio {
|
||||||
|
private static audioCtx: AudioContext | null = null;
|
||||||
|
private buffers: Map<string, AudioBuffer> = new Map();
|
||||||
|
private sources: Map<string, AudioBufferSourceNode> = new Map();
|
||||||
|
private audioOptions: Map<
|
||||||
|
string,
|
||||||
|
{ audioUrl: string; loop?: boolean; volume?: number }
|
||||||
|
> = new Map();
|
||||||
|
|
||||||
|
private get audioCtx(): AudioContext {
|
||||||
|
if (!EasyAudio.audioCtx) {
|
||||||
|
EasyAudio.audioCtx = new AudioContext();
|
||||||
|
}
|
||||||
|
return EasyAudio.audioCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
audios?:
|
||||||
|
| { name: string; audioUrl: string | URL; loop?: boolean; volume?: number }
|
||||||
|
| { name: string; audioUrl: string | URL; loop?: boolean; volume?: number }[]
|
||||||
|
) {
|
||||||
|
if (audios) {
|
||||||
|
this.add(audios);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createAudioBuffer(audioUrl: string): Promise<AudioBuffer> {
|
||||||
|
const response = await fetch(audioUrl);
|
||||||
|
const arrayBuffer = await response.arrayBuffer();
|
||||||
|
return await this.audioCtx.decodeAudioData(arrayBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadAudio(name: string) {
|
||||||
|
const options = this.audioOptions.get(name);
|
||||||
|
if (!options) {
|
||||||
|
throw new Error(`音频 ${name} 未找到`);
|
||||||
|
}
|
||||||
|
const buffer = await this.createAudioBuffer(options.audioUrl);
|
||||||
|
this.buffers.set(name, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
async load(): Promise<void> {
|
||||||
|
const promises = Array.from(this.audioOptions.keys()).map(name =>
|
||||||
|
this.loadAudio(name)
|
||||||
|
);
|
||||||
|
await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(
|
||||||
|
audios:
|
||||||
|
| { name: string; audioUrl: string | URL; loop?: boolean; volume?: number }
|
||||||
|
| { name: string; audioUrl: string | URL; loop?: boolean; volume?: number }[]
|
||||||
|
): void {
|
||||||
|
if (Array.isArray(audios)) {
|
||||||
|
audios.forEach(audio => {
|
||||||
|
this.audioOptions.set(audio.name, {
|
||||||
|
audioUrl: typeof (audio.audioUrl) === "string" ? audio.audioUrl : audio.audioUrl.href,
|
||||||
|
loop: audio.loop,
|
||||||
|
volume: audio.volume,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.audioOptions.set(audios.name, {
|
||||||
|
audioUrl: typeof (audios.audioUrl) === "string" ? audios.audioUrl : audios.audioUrl.href,
|
||||||
|
loop: audios.loop,
|
||||||
|
volume: audios.volume,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async play(name: string) {
|
||||||
|
if (!this.buffers.has(name)) {
|
||||||
|
await this.loadAudio(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = this.buffers.get(name);
|
||||||
|
const options = this.audioOptions.get(name);
|
||||||
|
if (!buffer || !options) {
|
||||||
|
throw new Error(`音频 ${name} 未找到`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = this.audioCtx.createBufferSource();
|
||||||
|
source.buffer = buffer;
|
||||||
|
source.loop = options.loop || false;
|
||||||
|
|
||||||
|
let gainNode: GainNode | null = null;
|
||||||
|
if (options.volume !== undefined) {
|
||||||
|
gainNode = this.audioCtx.createGain();
|
||||||
|
gainNode.gain.value = options.volume;
|
||||||
|
source.connect(gainNode);
|
||||||
|
gainNode.connect(this.audioCtx.destination);
|
||||||
|
} else {
|
||||||
|
source.connect(this.audioCtx.destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
source.start();
|
||||||
|
this.sources.set(name, source);
|
||||||
|
console.log(`音频 ${name} 播放`);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
stop(name: string) {
|
||||||
|
const source = this.sources.get(name);
|
||||||
|
if (source) {
|
||||||
|
source.stop();
|
||||||
|
this.sources.delete(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stopAll() {
|
||||||
|
this.sources.forEach(source => source.stop());
|
||||||
|
this.sources.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/assets/sounds/弹簧蓄力下拉音效.mp3
Normal file
BIN
src/assets/sounds/弹簧蓄力下拉音效.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/弹簧蓄力结束弹射有效.mp3
Normal file
BIN
src/assets/sounds/弹簧蓄力结束弹射有效.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/按钮音效.mp3
Normal file
BIN
src/assets/sounds/按钮音效.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/最终结算音效.mp3
Normal file
BIN
src/assets/sounds/最终结算音效.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/风声.mp3
Normal file
BIN
src/assets/sounds/风声.mp3
Normal file
Binary file not shown.
BIN
src/assets/sounds/首页标题、尾标出现音效.mp3
Normal file
BIN
src/assets/sounds/首页标题、尾标出现音效.mp3
Normal file
Binary file not shown.
@ -11,6 +11,7 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
import AudioEffects from '../assets/sounds'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
userdata: {
|
userdata: {
|
||||||
@ -32,6 +33,7 @@ const hasP2AnimationPlayed = ref(false);
|
|||||||
|
|
||||||
async function shoot() {
|
async function shoot() {
|
||||||
//sunEle.value?.jumpTo('天上飞')
|
//sunEle.value?.jumpTo('天上飞')
|
||||||
|
AudioEffects.play("弹簧蓄力下拉音效")
|
||||||
sunEle.value?.jumpTo('蓄力飞')
|
sunEle.value?.jumpTo('蓄力飞')
|
||||||
|
|
||||||
await document.querySelector('.sun-ani-wrapper')?.animate([
|
await document.querySelector('.sun-ani-wrapper')?.animate([
|
||||||
@ -54,6 +56,7 @@ async function shoot() {
|
|||||||
document.querySelector('.arrow')?.remove();
|
document.querySelector('.arrow')?.remove();
|
||||||
});
|
});
|
||||||
emit('cloudUp');
|
emit('cloudUp');
|
||||||
|
AudioEffects.play("弹簧蓄力结束弹射")
|
||||||
document.querySelector('.bed')?.animate([
|
document.querySelector('.bed')?.animate([
|
||||||
{ transform: 'translateY(0)' },
|
{ transform: 'translateY(0)' },
|
||||||
{ transform: 'translateY(170%)' },
|
{ transform: 'translateY(170%)' },
|
||||||
@ -300,6 +303,7 @@ function gToggle(pos: 'left' | 'center' | 'right') {
|
|||||||
if (windEl) {
|
if (windEl) {
|
||||||
windEl.style.rotate = `${windAni[0]}deg`;
|
windEl.style.rotate = `${windAni[0]}deg`;
|
||||||
}
|
}
|
||||||
|
AudioEffects.play("风声")
|
||||||
|
|
||||||
windEl?.animate([
|
windEl?.animate([
|
||||||
{ left: windAni[1][0] + 'vw', top: windAni[1][1] + 'vw', opacity: 0 },
|
{ left: windAni[1][0] + 'vw', top: windAni[1][1] + 'vw', opacity: 0 },
|
||||||
@ -558,6 +562,7 @@ async function gameEnd() {
|
|||||||
easing: 'cubic-bezier(0.4, 0, 1, 0.5)',
|
easing: 'cubic-bezier(0.4, 0, 1, 0.5)',
|
||||||
fill: 'forwards',
|
fill: 'forwards',
|
||||||
});
|
});
|
||||||
|
AudioEffects.play("结算")
|
||||||
sunEle.value?.jumpTo('落下');
|
sunEle.value?.jumpTo('落下');
|
||||||
|
|
||||||
|
|
||||||
@ -716,6 +721,7 @@ async function finishCollect() {
|
|||||||
document.querySelector('.bar-container').style.display = 'none';
|
document.querySelector('.bar-container').style.display = 'none';
|
||||||
|
|
||||||
showLastPage.value = true;
|
showLastPage.value = true;
|
||||||
|
AudioEffects.play("标题出现")
|
||||||
|
|
||||||
// 在最后一页显示后设置 Intersection Observer 监听 p2 元素
|
// 在最后一页显示后设置 Intersection Observer 监听 p2 元素
|
||||||
await wait(100); // 等待 DOM 更新
|
await wait(100); // 等待 DOM 更新
|
||||||
@ -726,7 +732,7 @@ async function finishCollect() {
|
|||||||
hasP2AnimationPlayed.value = true;
|
hasP2AnimationPlayed.value = true;
|
||||||
posterP2Ele.value?.jumpTo('p2');
|
posterP2Ele.value?.jumpTo('p2');
|
||||||
console.log('Poster P2 animation triggered');
|
console.log('Poster P2 animation triggered');
|
||||||
|
|
||||||
// 停止观察,因为只需要触发一次
|
// 停止观察,因为只需要触发一次
|
||||||
observer.unobserve(entry.target);
|
observer.unobserve(entry.target);
|
||||||
}
|
}
|
||||||
@ -785,6 +791,7 @@ function posterSwap(e: PointerEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} */
|
} */
|
||||||
|
const showShareMask = ref(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -792,14 +799,11 @@ function posterSwap(e: PointerEvent) {
|
|||||||
|
|
||||||
<div class="public">
|
<div class="public">
|
||||||
|
|
||||||
<img src="../assets/game/床.webp" alt="" class="abs bed"
|
<img src="../assets/game/床.webp" alt="" class="abs bed" style="width: 66vw;bottom: 12%;left: 17%;">
|
||||||
style="width: 66vw;bottom: 12%;left: 17%;">
|
|
||||||
|
|
||||||
<AniEle :url="assets.ani.下拉蓄力提示" ref="shoot-notice" :height="334"
|
<AniEle :url="assets.ani.下拉蓄力提示" ref="shoot-notice" :height="334" :width="337" :rules="[
|
||||||
:width="337" :rules="[
|
{ name: '蓄力', frame: 241, loop: 2 },
|
||||||
{ name: '蓄力', frame: 241, loop: 2 },
|
]" class="abs arrow" style="bottom: 7%;width: 30vw;left: 35%;" @pointerdown.once="shoot" />
|
||||||
]" class="abs arrow" style="bottom: 7%;width: 30vw;left: 35%;"
|
|
||||||
@pointerdown.once="shoot" />
|
|
||||||
|
|
||||||
<div class="sun-ani-wrapper abs" v-if="!showEndAni" :style="{
|
<div class="sun-ani-wrapper abs" v-if="!showEndAni" :style="{
|
||||||
width: '60vw',
|
width: '60vw',
|
||||||
@ -812,13 +816,12 @@ function posterSwap(e: PointerEvent) {
|
|||||||
}">
|
}">
|
||||||
|
|
||||||
<!-- AniEle 组件现在只关心自己的内容,不再有复杂的外部样式 -->
|
<!-- AniEle 组件现在只关心自己的内容,不再有复杂的外部样式 -->
|
||||||
<AniEle :url="assets.ani.小太阳总" ref="sun-ani" class="sun-ani"
|
<AniEle :url="assets.ani.小太阳总" ref="sun-ani" class="sun-ani" :height="1800" :width="1600" :rules="[
|
||||||
:height="1800" :width="1600" :rules="[
|
{ name: '起飞前', frame: 90, loop: 0, pauseAfter: true, duration: 33 },
|
||||||
{ name: '起飞前', frame: 90, loop: 0, pauseAfter: true, duration: 33 },
|
{ name: '蓄力飞', frame: 181, loop: 1, pauseAfter: false, duration: 33 },
|
||||||
{ name: '蓄力飞', frame: 181, loop: 1, pauseAfter: false, duration: 33 },
|
{ name: '天上飞', frame: 90, loop: 0, pauseAfter: true, duration: 33 },
|
||||||
{ name: '天上飞', frame: 90, loop: 0, pauseAfter: true, duration: 33 },
|
{ name: '落下', frame: 382, loop: 0, pauseAfter: false, duration: 33 },
|
||||||
{ name: '落下', frame: 382, loop: 0, pauseAfter: false, duration: 33 },
|
]" style="width: 100%; height: auto;" />
|
||||||
]" style="width: 100%; height: auto;" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -827,59 +830,50 @@ function posterSwap(e: PointerEvent) {
|
|||||||
style="bottom: -40%; width: 66vw; left: 17%; transform-origin: 50% 63%; transition: all 0.2s;"
|
style="bottom: -40%; width: 66vw; left: 17%; transform-origin: 50% 63%; transition: all 0.2s;"
|
||||||
:style="{ transform: `rotate(${gDeg}deg)` }" />
|
:style="{ transform: `rotate(${gDeg}deg)` }" />
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<img draggable="false" :style="{ animationDelay: '0.1s' }"
|
<img draggable="false" :style="{ animationDelay: '0.1s' }" src="../assets/game/左.webp" alt=""
|
||||||
src="../assets/game/左.webp" alt="" @click="gToggle('left')">
|
@click="gToggle('left')">
|
||||||
<img draggable="false" :style="{ animationDelay: '0.2s' }"
|
<img draggable="false" :style="{ animationDelay: '0.2s' }" src="../assets/game/中.webp" alt=""
|
||||||
src="../assets/game/中.webp" alt=""
|
|
||||||
@click="gToggle('center')">
|
@click="gToggle('center')">
|
||||||
<img draggable="false" :style="{ animationDelay: '0.0s' }"
|
<img draggable="false" :style="{ animationDelay: '0.0s' }" src="../assets/game/右.webp" alt=""
|
||||||
src="../assets/game/右.webp" alt=""
|
|
||||||
@click="gToggle('right')">
|
@click="gToggle('right')">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img class="abs gift-item" v-for="(gift, index) in giftList"
|
<img class="abs gift-item" v-for="(gift, index) in giftList" :src="gift[0]" style="width: 20vw;"
|
||||||
:src="gift[0]" style="width: 20vw;" v-if="!isGameEnd" :style="{
|
v-if="!isGameEnd" :style="{
|
||||||
display: giftProgress == index ? 'block' : 'none',
|
display: giftProgress == index ? 'block' : 'none',
|
||||||
bottom: `calc(45% + ${giftPos[1] ?? 0}vw)`, left: `calc(39.5% + ${giftPos[0] ?? 0}vw)`, transition: transitionOn ? `all 0.1s ease` : undefined
|
bottom: `calc(45% + ${giftPos[1] ?? 0}vw)`, left: `calc(39.5% + ${giftPos[0] ?? 0}vw)`, transition: transitionOn ? `all 0.1s ease` : undefined
|
||||||
}" alt=""
|
}" alt="" :class="{ show: giftProgress == index, hide: giftProgress != index }">
|
||||||
:class="{ show: giftProgress == index, hide: giftProgress != index }">
|
|
||||||
|
|
||||||
<img src="../assets//game/操作提示.webp" class="abs prompt" alt=""
|
<img src="../assets//game/操作提示.webp" class="abs prompt" alt="" style="width: 31%; bottom: 18%; left: 34%; ">
|
||||||
style="width: 31%; bottom: 18%; left: 34%; ">
|
|
||||||
<img src="../assets/game/风.webp" alt="" class="abs wind">
|
<img src="../assets/game/风.webp" alt="" class="abs wind">
|
||||||
<img src="../assets/game/wecare.webp" alt="" class="abs wecare"
|
<img src="../assets/game/wecare.webp" alt="" class="abs wecare" style="width: 24vw;
|
||||||
style="width: 24vw;
|
|
||||||
left: 50%; top: 6%; transform: translateX(-50%);">
|
left: 50%; top: 6%; transform: translateX(-50%);">
|
||||||
<div class="dot" v-if="!isGameEnd">
|
<div class="dot" v-if="!isGameEnd">
|
||||||
<div v-for="(_, index) in giftList" :key="index"
|
<div v-for="(_, index) in giftList" :key="index" class="dot-item"
|
||||||
class="dot-item" :class="{ finished: index < giftProgress }"
|
:class="{ finished: index < giftProgress }" @click="giftProgress = index">
|
||||||
@click="giftProgress = index">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="game-end abs" v-if="isGameEnd"
|
<div class="game-end abs" v-if="isGameEnd"
|
||||||
style="z-index: 2; inset: 0; height: 100%; width: 100%;pointer-events: none;">
|
style="z-index: 2; inset: 0; height: 100%; width: 100%;pointer-events: none;">
|
||||||
<div class="icon-cloud"
|
<div class="icon-cloud" style="position: absolute; left: 50%; top: 20%;">
|
||||||
style="position: absolute; left: 50%; top: 20%;">
|
|
||||||
<img v-for="icon in floatIcons" :src="icon.src" alt="" :style="{
|
<img v-for="icon in floatIcons" :src="icon.src" alt="" :style="{
|
||||||
top: `${icon.top}vw`,
|
top: `${icon.top}vw`,
|
||||||
left: `${icon.left}vw`,
|
left: `${icon.left}vw`,
|
||||||
animationDelay: `${icon.delay}ms`,
|
animationDelay: `${icon.delay}ms`,
|
||||||
}">
|
}">
|
||||||
</div>
|
</div>
|
||||||
<img src="../assets/game/wecare.webp" alt="" class="abs wecare"
|
<img src="../assets/game/wecare.webp" alt="" class="abs wecare" style="width: 24vw;
|
||||||
style="width: 24vw;
|
|
||||||
left: 50%; top: 6%; transform: translateX(-50%);">
|
left: 50%; top: 6%; transform: translateX(-50%);">
|
||||||
|
|
||||||
<img src="../assets/game/wecare标题.webp" alt=""
|
<img src="../assets/game/wecare标题.webp" alt="" class="abs wecare-title"
|
||||||
class="abs wecare-title" style="width: 72%;left: 14%;top: 12%;">
|
style="width: 72%;left: 14%;top: 12%;">
|
||||||
|
|
||||||
|
|
||||||
<div class="scoreboard" v-if="showScore">
|
<div class="scoreboard" v-if="showScore">
|
||||||
<div class="bar-container">
|
<div class="bar-container">
|
||||||
<div class="bar"
|
<div class="bar" v-for="(item, index) in [leaderBoard[1], leaderBoard[0], leaderBoard[2]]"
|
||||||
v-for="(item, index) in [leaderBoard[1], leaderBoard[0], leaderBoard[2]]"
|
|
||||||
:key="index" :class="{
|
:key="index" :class="{
|
||||||
'first': index === 1, 'second': index === 0, 'third': index === 2
|
'first': index === 1, 'second': index === 0, 'third': index === 2
|
||||||
}">
|
}">
|
||||||
@ -890,9 +884,7 @@ function posterSwap(e: PointerEvent) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="lines">
|
<div class="lines">
|
||||||
<div class="line"
|
<div class="line" v-for="(item, index) in leaderBoard.slice(3, 7)" :key="index"
|
||||||
v-for="(item, index) in leaderBoard.slice(3, 7)"
|
|
||||||
:key="index"
|
|
||||||
:style="{ animationDelay: index * 100 + 400 + 'ms' }">
|
:style="{ animationDelay: index * 100 + 400 + 'ms' }">
|
||||||
<div class="rank">{{ index + 4 }}</div>
|
<div class="rank">{{ index + 4 }}</div>
|
||||||
<div class="name">{{ item.name }}</div>
|
<div class="name">{{ item.name }}</div>
|
||||||
@ -902,19 +894,16 @@ function posterSwap(e: PointerEvent) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sun-ani-end-wrapper abs"
|
<div class="sun-ani-end-wrapper abs" style="pointer-events: none; inset: 0; width: 100%;z-index: 2;"
|
||||||
style="pointer-events: none; inset: 0; width: 100%;z-index: 2;"
|
|
||||||
:style="{ display: showEndAni ? 'block' : 'none' }">
|
:style="{ display: showEndAni ? 'block' : 'none' }">
|
||||||
|
|
||||||
<!-- AniEle 组件现在只关心自己的内容,不再有复杂的外部样式 -->
|
<!-- AniEle 组件现在只关心自己的内容,不再有复杂的外部样式 -->
|
||||||
<AniEle :url="assets.ani.后端效果" ref="sun-ani-end"
|
<AniEle :url="assets.ani.后端效果" ref="sun-ani-end" class="sun-ani-end" :height="2462" :width="1179"
|
||||||
class="sun-ani-end" :height="2462" :width="1179"
|
:rules="sunAniEndRules" style="width: 100%; height: auto;" />
|
||||||
:rules="sunAniEndRules"
|
|
||||||
style="width: 100%; height: auto;" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img src="../assets/game/完成收集.webp" alt="" v-if="showScore"
|
<img src="../assets/game/完成收集.webp" alt="" v-if="showScore" class="finish-collect abs"
|
||||||
class="finish-collect abs" @click.once="finishCollect"
|
@click.once="AudioEffects.play('按钮音效');finishCollect()"
|
||||||
style="bottom: 8%;left: 33%;width: 34vw;animation: scale-in 0.3s ease-out;pointer-events: all;">
|
style="bottom: 8%;left: 33%;width: 34vw;animation: scale-in 0.3s ease-out;pointer-events: all;">
|
||||||
|
|
||||||
|
|
||||||
@ -924,12 +913,11 @@ function posterSwap(e: PointerEvent) {
|
|||||||
style="z-index: 0;position: absolute; inset: 0;height: 100%; width: 100%; pointer-events: none;">
|
style="z-index: 0;position: absolute; inset: 0;height: 100%; width: 100%; pointer-events: none;">
|
||||||
<AniEle :url="assets.ani.结尾主标" :width="925" :height="340"
|
<AniEle :url="assets.ani.结尾主标" :width="925" :height="340"
|
||||||
:rules="[{ name: 'main', frame: 41, loop: 1, pauseAfter: true, duration: 33, reverse: false }]"
|
:rules="[{ name: 'main', frame: 41, loop: 1, pauseAfter: true, duration: 33, reverse: false }]"
|
||||||
style="position: absolute;top: 13%;width: 80%;left: 11%; pointer-events:none;"
|
style="position: absolute;top: 13%;width: 80%;left: 11%; pointer-events:none;" ref="main-logo" />
|
||||||
ref="main-logo" />
|
|
||||||
<div class="poster-container"
|
<div class="poster-container"
|
||||||
style="position: absolute;top: 29.3%;left: 37.2%;width: 57.3%; height: 38%; overflow-x: auto; overflow-y: hidden; pointer-events: all; scroll-snap-type: x mandatory;">
|
style="position: absolute;top: 29.3%;left: 37.2%;width: 57.3%; height: 38%; overflow-x: auto; overflow-y: hidden; pointer-events: all; scroll-snap-type: x mandatory;">
|
||||||
<div class="poster-wrapper"
|
<div class="poster-wrapper" style="display: flex; width: 200%; height: 100%; flex-direction: row;"
|
||||||
style="display: flex; width: 200%; height: 100%; flex-direction: row;" dir="ltr" >
|
dir="ltr">
|
||||||
<AniEle :url="assets.ani.海报p1" ref="gui-ani-end-post-p1 "
|
<AniEle :url="assets.ani.海报p1" ref="gui-ani-end-post-p1 "
|
||||||
style="width: 50%; flex-shrink: 0; scroll-snap-align: start;" class="gui-ani-end-post"
|
style="width: 50%; flex-shrink: 0; scroll-snap-align: start;" class="gui-ani-end-post"
|
||||||
:height="940" :width="671" :rules="[
|
:height="940" :width="671" :rules="[
|
||||||
@ -943,18 +931,14 @@ function posterSwap(e: PointerEvent) {
|
|||||||
]" />
|
]" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AniEle :url="assets.ani.线" ref="gui-ani-end" class="gui-ani-end"
|
<AniEle :url="assets.ani.线" ref="gui-ani-end" class="gui-ani-end" :height="2462" :width="1179" :rules="[
|
||||||
:height="2462" :width="1179" :rules="[
|
{ name: 'all', frame: 54, loop: 1, pauseAfter: false, duration: 16 },
|
||||||
{ name: 'all', frame: 54, loop: 1, pauseAfter: false, duration: 16 },
|
]" style="width: 100%; height: auto;position: absolute;inset: 0;pointer-events: none;" />
|
||||||
]"
|
<img src="../assets/game/床.webp" alt="" class="abs last-bed" style="width: 66vw;bottom: -19%;left: 17%;">
|
||||||
style="width: 100%; height: auto;position: absolute;inset: 0;pointer-events: none;" />
|
|
||||||
<img src="../assets/game/床.webp" alt="" class="abs last-bed"
|
|
||||||
style="width: 66vw;bottom: -19%;left: 17%;">
|
|
||||||
|
|
||||||
<img src="../assets/game/分享海报.webp" alt="" class="abs"
|
<img src="../assets/game/分享海报.webp" alt="" class="abs" @click="AudioEffects.play('按钮音效');showShareMask = true"
|
||||||
style="width: 34vw;bottom: -19%;left: 15%;animation: last-btn-in 0.3s ease-out forwards; cursor: pointer; pointer-events: all;">
|
style="width: 34vw;bottom: -19%;left: 15%;animation: last-btn-in 0.3s ease-out forwards; cursor: pointer; pointer-events: all;">
|
||||||
<img src="../assets/game/再玩一次.webp" alt="" class="abs"
|
<img src="../assets/game/再玩一次.webp" alt="" class="abs" @click="AudioEffects.play('按钮音效');resetGame()"
|
||||||
@click="resetGame"
|
|
||||||
style="width: 34vw;bottom: -19%;left: 51%;animation: last-btn-in 0.3s ease-out forwards; cursor: pointer; animation-delay: 200ms; pointer-events: all;">
|
style="width: 34vw;bottom: -19%;left: 51%;animation: last-btn-in 0.3s ease-out forwards; cursor: pointer; animation-delay: 200ms; pointer-events: all;">
|
||||||
|
|
||||||
<div class="time-spent abs" style="left: 10%; top:44%;width: 24%;height: 23%; display: flex;
|
<div class="time-spent abs" style="left: 10%; top:44%;width: 24%;height: 23%; display: flex;
|
||||||
@ -976,8 +960,7 @@ function posterSwap(e: PointerEvent) {
|
|||||||
style="width: 100%;bottom:7%;position: absolute;animation: line-in 0.5s ease-out 1s forwards;transform: translateX(-210%);">
|
style="width: 100%;bottom:7%;position: absolute;animation: line-in 0.5s ease-out 1s forwards;transform: translateX(-210%);">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="region-area abs"
|
<div class="region-area abs" style="left: 10%; top:30%;width: 24%;height: 10%;gap:2vw; display: flex;animation: line-in 0.5s ease-out 0.4s forwards;transform: translateX(-210%);
|
||||||
style="left: 10%; top:30%;width: 24%;height: 10%;gap:2vw; display: flex;animation: line-in 0.5s ease-out 0.4s forwards;transform: translateX(-210%);
|
|
||||||
align-items: center; flex-direction: column;justify-content: center;">
|
align-items: center; flex-direction: column;justify-content: center;">
|
||||||
<div class="region"
|
<div class="region"
|
||||||
style="width: 20vw; background-color: white;font-size: 3vw;text-align: center;height: 5.2vw;line-height: 5.2vw; border-radius: 4.5vw;">
|
style="width: 20vw; background-color: white;font-size: 3vw;text-align: center;height: 5.2vw;line-height: 5.2vw; border-radius: 4.5vw;">
|
||||||
@ -991,18 +974,35 @@ function posterSwap(e: PointerEvent) {
|
|||||||
|
|
||||||
|
|
||||||
<div v-if="giftShow" class="gift-popup">
|
<div v-if="giftShow" class="gift-popup">
|
||||||
<img :src="giftList[giftProgress][1]" alt="" class="abs"
|
<img :src="giftList[giftProgress][1]" alt="" class="abs" style="width: 82%; left: 9%; top: 11%;">
|
||||||
style="width: 82%; left: 9%; top: 11%;">
|
<img src="../assets/game/收下福利.webp" alt="" class="abs" style="width: 14%; left: 43%; top: 54%;"
|
||||||
<img src="../assets/game/收下福利.webp" alt="" class="abs"
|
@click="AudioEffects.play('按钮音效');gameLoop()">
|
||||||
style="width: 14%; left: 43%; top: 54%;" @click="gameLoop()">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Transition name="fade">
|
||||||
|
<div v-if="showShareMask" class="share-mask" @click="showShareMask = false">
|
||||||
|
<img src="../assets/game/share_mask.png" alt="">
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
.share-mask {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.gui-ani-end-post {
|
.gui-ani-end-post {
|
||||||
/* 确保每个海报都能正确对齐 */
|
/* 确保每个海报都能正确对齐 */
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
@ -1349,11 +1349,14 @@ function posterSwap(e: PointerEvent) {
|
|||||||
|
|
||||||
.poster-container {
|
.poster-container {
|
||||||
/* 隐藏滚动条但保持滚动功能 */
|
/* 隐藏滚动条但保持滚动功能 */
|
||||||
scrollbar-width: none; /* Firefox */
|
scrollbar-width: none;
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
/* Firefox */
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
/* IE and Edge */
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
display: none; /* Chrome, Safari, Opera */
|
display: none;
|
||||||
|
/* Chrome, Safari, Opera */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import assets from '../assets';
|
|||||||
import { regions, type RegionData, type Store } from '../data';
|
import { regions, type RegionData, type Store } from '../data';
|
||||||
import AniEle from '../components/AniEle.vue';
|
import AniEle from '../components/AniEle.vue';
|
||||||
|
|
||||||
|
import AudioEffects from '../assets/sounds'
|
||||||
|
|
||||||
const regionsPos = [
|
const regionsPos = [
|
||||||
{ w: 68.8, h: 68.8, l: -1, t: 0, src: assets.p1.大北区, tt: '大北区', trt: -13, ad: 6, key: '大北区' },
|
{ w: 68.8, h: 68.8, l: -1, t: 0, src: assets.p1.大北区, tt: '大北区', trt: -13, ad: 6, key: '大北区' },
|
||||||
{ w: 73.3, h: 73.3, l: 44, t: 20, src: assets.p1.大东区, tt: '大东区', ad: 3, key: '大东区' },
|
{ w: 73.3, h: 73.3, l: 44, t: 20, src: assets.p1.大东区, tt: '大东区', ad: 3, key: '大东区' },
|
||||||
@ -101,6 +103,7 @@ const emit = defineEmits<{
|
|||||||
const noticeToInputName = ref(false);
|
const noticeToInputName = ref(false);
|
||||||
async function startExploration() {
|
async function startExploration() {
|
||||||
console.log('开始探索:', selectedStores.value[selectedStoreIndex.value]);
|
console.log('开始探索:', selectedStores.value[selectedStoreIndex.value]);
|
||||||
|
AudioEffects.play("按钮音效");
|
||||||
if (!selectedRegion.value || selectedStores.value.length === 0) {
|
if (!selectedRegion.value || selectedStores.value.length === 0) {
|
||||||
alert('请选择一个区域和店铺!');
|
alert('请选择一个区域和店铺!');
|
||||||
return;
|
return;
|
||||||
@ -192,6 +195,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
// --- 绑定事件 ---
|
// --- 绑定事件 ---
|
||||||
const pDown = () => {
|
const pDown = () => {
|
||||||
|
AudioEffects.play("按钮音效");
|
||||||
if (selectionInProgress.value) return;
|
if (selectionInProgress.value) return;
|
||||||
bubble.style.filter = 'brightness(0.9)';
|
bubble.style.filter = 'brightness(0.9)';
|
||||||
bubble.style.transform = 'translate3d(-50%,-50%, 0) scale(0.92)';
|
bubble.style.transform = 'translate3d(-50%,-50%, 0) scale(0.92)';
|
||||||
@ -257,10 +261,12 @@ onMounted(() => {
|
|||||||
|
|
||||||
|
|
||||||
function goBackToRegionSelection() {
|
function goBackToRegionSelection() {
|
||||||
|
AudioEffects.play("按钮音效");
|
||||||
if (!selectedBubbleEl.value) return;
|
if (!selectedBubbleEl.value) return;
|
||||||
selectionInProgress.value = true; // 加锁防止重复操作
|
selectionInProgress.value = true; // 加锁防止重复操作
|
||||||
|
|
||||||
mainLogoRules.value[0].reverse = false;
|
mainLogoRules.value[0].reverse = false;
|
||||||
|
AudioEffects.play("标题出现")
|
||||||
selectInfoRules.value[0].reverse = false;
|
selectInfoRules.value[0].reverse = false;
|
||||||
|
|
||||||
// 1. 隐藏店铺选择器
|
// 1. 隐藏店铺选择器
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user