feat(menu) 完善菜单场景的功能与效果

This commit is contained in:
wvellichor committed 2026-01-20 01:58:58 +08:00
1 parent 6dbce8bdd5
commit cb5c7ac51b
5 files changed
+467 -13

No files matched your search

+338 -12
View File
@@ -1,3 +1,6 @@
import LanguageManager from '../lang/LanguageManager.js';
import translations from '../lang/translations.js';
export default class MenuScene extends Phaser.Scene {
constructor() {
super('MenuScene')
@@ -9,20 +12,343 @@ export default class MenuScene extends Phaser.Scene {
// 获取主相机对象
const cam = this.cameras.main;
// 添加菜单文本
this.add.text(
cam.centerX/5, // 文本在x轴上的位置,相机中心的1/5
cam.centerY/5, // 文本在y轴上的位置,相机中心的1/5
'CINC',
{ fontSize: '64px', color: '#ffffff' }
// 添加落雨落效果
this.createRainEffect();
// 初始化语言管理器 - 支持多语言
LanguageManager.loadTranslations(translations);
// 添加菜单文本 - 使用多语言
this.titleText = this.add.text(
cam.centerX, // 文本在x轴上的位置,相机中心
cam.centerY - 80, // 文本在y轴上的位置,相机中心上方
LanguageManager.t('title'),
{ fontSize: '24px', color: '#ffffff' }
).setOrigin(0.5, 0.5);
this.add.rectangle(
cam.centerX/5, // 矩形在x轴上的位置,相机中心的1/5
cam.centerY, // 矩形在y轴上的位置,相机中心的1/5
10, // 矩形的宽度
10, // 矩形的高度
0xffffff // 矩形的颜色,这里是白色
// 添加菜单文本 - 使用多语言
this.startText = this.add.text(
cam.centerX, // 文本在x轴上的位置,相机中心
cam.centerY, // 文本在y轴上的位置,相机中心
LanguageManager.t('start'),
{ fontSize: '32px', color: '#ffffff' }
).setOrigin(0.5, 0.5);
// 添加退出按钮文本 - 使用多语言
this.exitText = this.add.text(
cam.centerX, // 文本在x轴上的位置,相机中心
cam.centerY + 50, // 文本在y轴上的位置,开始按钮下方
LanguageManager.t('exit'),
{ fontSize: '24px', color: '#ffffff' }
).setOrigin(0.5, 0.5);
// 为开始和退出按钮添加点击功能
this.addButtonClickHandlers();
// 添加语言切换按钮(仅用于测试)
this.createLanguageToggle();
}
/**
* 创建语言切换按钮(使用文本倒影效果)
*/
createLanguageToggle() {
const cam = this.cameras.main;
const languages = LanguageManager.getAvailableLanguages();
let currentLangIndex = languages.indexOf(LanguageManager.currentLanguage);
// 按钮基础位置(在退出按钮下方)
const baseY = cam.centerY + 110;
// 创建主按钮文本
const toggleText = this.add.text(
cam.centerX,
baseY,
`${LanguageManager.currentLanguage}`,
{ fontSize: '16px', color: '#ffffff' }
).setOrigin(0.5, 0.5);
// 创建倒影文本
const reflectionText = this.add.text(
cam.centerX,
baseY + 20, // 倒影位置在主文本下方
`${LanguageManager.currentLanguage}`,
{ fontSize: '16px', color: '#ffffff' }
).setOrigin(0.5, 0.5);
// 设置倒影效果
reflectionText.setScale(1, -1); // 垂直翻转
reflectionText.setAlpha(0.3); // 半透明效果
// 添加动态波纹效果
this.createRippleEffect(reflectionText);
// 创建透明的点击区域(与文本大小匹配)
const clickArea = this.add.rectangle(
cam.centerX,
baseY,
toggleText.width,
toggleText.height,
0x000000,
0 // 完全透明
).setOrigin(0.5, 0.5);
// 设置点击区域可交互
clickArea.setInteractive({ useHandCursor: true });
// 添加点击事件
clickArea.on('pointerdown', () => {
currentLangIndex = (currentLangIndex + 1) % languages.length;
const newLang = languages[currentLangIndex];
LanguageManager.setLanguage(newLang);
// 更新文本
const newText = `${newLang}`;
toggleText.setText(newText);
reflectionText.setText(newText);
// 重新计算点击区域大小
clickArea.width = toggleText.width + 20;
clickArea.height = toggleText.height + 40;
// 直接更新菜单文本以显示新语言
this.titleText.setText(LanguageManager.t('title'));
this.startText.setText(LanguageManager.t('start'));
this.exitText.setText(LanguageManager.t('exit'));
});
}
/**
* 为开始和退出按钮添加点击功能
*/
addButtonClickHandlers() {
// 为开始文本添加点击区域
const startClickArea = this.add.rectangle(
this.startText.x,
this.startText.y,
this.startText.width + 40, // 增加点击区域宽度
this.startText.height + 20, // 增加点击区域高度
0x000000,
0 // 透明
).setOrigin(0.5, 0.5);
// 设置开始按钮可交互
startClickArea.setInteractive({ useHandCursor: true });
// 添加开始按钮鼠标悬停事件
startClickArea.on('pointerover', () => {
this.tweens.add({
targets: this.startText,
y: this.startText.y - 5, // 字体上移
duration: 100,
ease: 'Sine.easeOut'
});
});
// 添加开始按钮鼠标离开事件
startClickArea.on('pointerout', () => {
this.tweens.add({
targets: this.startText,
y: this.startText.y + 5, // 字体恢复原位
duration: 100,
ease: 'Sine.easeOut'
});
});
// 添加开始按钮点击事件
startClickArea.on('pointerdown', () => {
console.log('Start game clicked');
// 添加进入场景前的过渡动画
this.cameras.main.fadeOut(500, 0, 0, 0);
this.cameras.main.once('camerafadeoutcomplete', () => {
// 切换到游戏场景
this.scene.start('GameScene');
});
});
// 为退出文本添加点击区域
const exitClickArea = this.add.rectangle(
this.exitText.x,
this.exitText.y,
this.exitText.width + 40, // 增加点击区域宽度
this.exitText.height + 20, // 增加点击区域高度
0x000000,
0 // 透明
).setOrigin(0.5, 0.5);
// 设置退出按钮可交互
exitClickArea.setInteractive({ useHandCursor: true });
// 添加退出按钮鼠标悬停事件
exitClickArea.on('pointerover', () => {
this.tweens.add({
targets: this.exitText,
y: this.exitText.y - 5, // 字体上移
duration: 100,
ease: 'Sine.easeOut'
});
});
// 添加退出按钮鼠标离开事件
exitClickArea.on('pointerout', () => {
this.tweens.add({
targets: this.exitText,
y: this.exitText.y + 5, // 字体恢复原位
duration: 100,
ease: 'Sine.easeOut'
});
});
// 添加退出按钮点击事件
exitClickArea.on('pointerdown', () => {
console.log('Exit game clicked');
// 关闭游戏(在浏览器中关闭窗口)
window.close();
});
}
/**
* 为文本添加波纹效果,模拟水下倒影
* @param {Phaser.GameObjects.Text} text - 要添加波纹效果的文本
*/
createRippleEffect(text) {
// 保存原始位置
const originalX = text.x;
const originalY = text.y;
// 创建波纹动画
this.tweens.add({
targets: text,
y: originalY + 5, // 上下波动
duration: 1500,
ease: 'Sine.easeInOut',
yoyo: true,
repeat: -1 // 无限重复
});
// 添加轻微的缩放动画
this.tweens.add({
targets: text,
scaleY: -1.05, // 垂直方向轻微缩放(保持负值,继续翻转)
duration: 2000,
ease: 'Sine.easeInOut',
yoyo: true,
repeat: -1 // 无限重复
});
// 添加透明度变化
this.tweens.add({
targets: text,
alpha: 0.2, // 透明度变化
duration: 2500,
ease: 'Sine.easeInOut',
yoyo: true,
repeat: -1 // 无限重复
});
}
/**
* 创建雨落下效果
*/
createRainEffect() {
// 创建雨滴精灵组
this.rainGroup = this.add.group();
// 雨的参数
const rainCount = 50; // 雨滴数量
const screenWidth = this.sys.game.config.width;
const screenHeight = this.sys.game.config.height;
// 创建雨滴
for (let i = 0; i < rainCount; i++) {
// 创建雨滴精灵(使用简单的白色矩形)
const raindrop = this.add.rectangle(
Phaser.Math.Between(0, screenWidth), // 随机x位置
Phaser.Math.Between(-screenHeight, 0), // 初始y位置在屏幕上方
2, // 雨滴宽度
10, // 雨滴高度
0xffffff, // 白色
0.3 // 半透明
);
// 添加到组
this.rainGroup.add(raindrop);
// 设置雨滴动画
this.tweens.add({
targets: raindrop,
y: screenHeight + 20, // 下落到底部
duration: Phaser.Math.Between(1000, 2000), // 随机下落速度
ease: 'Linear',
repeat: -1, // 无限重复
delay: Phaser.Math.Between(0, 2000), // 随机延迟,使雨滴分布更均匀
onRepeat: (tween, targets) => {
// 检查目标是否存在,防止场景重启时的错误
if (targets[0] && targets[0].active) {
// 重置雨滴位置
targets[0].x = Phaser.Math.Between(0, screenWidth);
targets[0].y = -20;
}
}
});
}
// 添加雨滴涟漪效果
this.createRainRipples(screenWidth, screenHeight);
}
/**
* 创建雨滴落下的涟漪效果
* @param {number} screenWidth - 屏幕宽度
* @param {number} screenHeight - 屏幕高度
*/
createRainRipples(screenWidth, screenHeight) {
// 涟漪数量
const rippleCount = 15;
for (let i = 0; i < rippleCount; i++) {
// 随机延迟开始
setTimeout(() => {
this.createSingleRipple(screenWidth, screenHeight);
}, Phaser.Math.Between(0, 2000));
}
}
/**
* 创建单个雨滴涟漪
* @param {number} screenWidth - 屏幕宽度
* @param {number} screenHeight - 屏幕高度
*/
createSingleRipple(screenWidth, screenHeight) {
// 随机位置
const x = Phaser.Math.Between(0, screenWidth);
const y = Phaser.Math.Between(0, screenHeight); // 整个屏幕高度
// 创建涟漪圆圈(只保留边框)
const ripple = this.add.circle(
x,
y,
0, // 初始半径
0xffffff, // 白色
0 // 透明填充
).setStrokeStyle(1, 0xffffff, 0.2); // 1像素白色边框,半透明
// 创建扩散动画
this.tweens.add({
targets: ripple,
radius: 20, // 最大半径
alpha: 0, // 逐渐消失
duration: 1000, // 动画持续时间
ease: 'Sine.easeOut',
onComplete: (tween, targets) => {
// 动画完成后销毁涟漪
if (targets[0] && targets[0].active) {
targets[0].destroy();
}
// 递归创建新的涟漪
this.createSingleRipple(screenWidth, screenHeight);
}
});
}
}