mirror of
http://junepve.top:3000/chicrobot/CINC.git
synced 2026-10-30 04:31:29 +08:00
feat(menu) 完善菜单场景的功能与效果
This commit is contained in:
1 parent
6dbce8bdd5
commit
cb5c7ac51b
5 files changed
+467
-13
No files matched your search
@@ -0,0 +1,51 @@
|
||||
// lang/LanguageManager.js
|
||||
class LanguageManager {
|
||||
constructor() {
|
||||
this.translations = {};
|
||||
this.currentLanguage = '#^'; // 默认语言
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载翻译文件
|
||||
* @param {Object} translations - 翻译对象
|
||||
*/
|
||||
loadTranslations(translations) {
|
||||
this.translations = translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前语言
|
||||
* @param {string} lang - 语言代码,如 'en', 'zh'
|
||||
*/
|
||||
setLanguage(lang) {
|
||||
if (this.translations[lang]) {
|
||||
this.currentLanguage = lang;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取翻译文本
|
||||
* @param {string} key - 文本键值
|
||||
* @param {string} lang - 可选,指定语言,默认使用当前语言
|
||||
* @returns {string} 翻译后的文本
|
||||
*/
|
||||
t(key, lang = this.currentLanguage) {
|
||||
if (this.translations[lang] && this.translations[lang][key]) {
|
||||
return this.translations[lang][key];
|
||||
}
|
||||
return key; // 如果没有找到翻译,返回原键值
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用语言列表
|
||||
* @returns {string[]} 语言代码数组
|
||||
*/
|
||||
getAvailableLanguages() {
|
||||
return Object.keys(this.translations);
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例
|
||||
export default new LanguageManager();
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
export default {
|
||||
"#^": {
|
||||
"title": "#*^#",
|
||||
'start': "@%!$%",
|
||||
"exit": "#@*%"
|
||||
},
|
||||
"en": {
|
||||
"title": "CINC",
|
||||
"start": "start",
|
||||
"exit": "exit"
|
||||
},
|
||||
"中文": {
|
||||
"title": "游戏",
|
||||
"start": "开始",
|
||||
"exit": "退出"
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,8 @@ const config = {
|
||||
...gameConfig,
|
||||
// 指定游戏使用的场景列表,包括主场景和所有测试场景
|
||||
scene: [
|
||||
BootScene,
|
||||
MenuScene,
|
||||
BootScene,
|
||||
GameScene,
|
||||
KeyboardMovementTestScene,
|
||||
TargetMovementTestScene,
|
||||
|
||||
@@ -27,6 +27,8 @@ export default class GameScene extends Phaser.Scene {
|
||||
|
||||
// create方法:当场景创建时自动调用,用于初始化游戏元素
|
||||
create() {
|
||||
// 设置背景颜色
|
||||
this.cameras.main.setBackgroundColor('#333333')
|
||||
// === 0. 添加窗口大小变化监听 ===
|
||||
// 监听浏览器窗口大小变化事件,当窗口大小改变时调用resizeGame方法
|
||||
window.addEventListener('resize', this.resizeGame.bind(this));
|
||||
@@ -102,6 +104,63 @@ export default class GameScene extends Phaser.Scene {
|
||||
x: this.sys.game.config.width - 200 - 10, // 小地图在屏幕上的x坐标
|
||||
y: 10 // 小地图在屏幕上的y坐标
|
||||
});
|
||||
|
||||
// === 7. 添加菜单按钮 ===
|
||||
// 添加返回菜单按钮
|
||||
const menuButton = this.add.text(
|
||||
20, // x坐标
|
||||
20, // y坐标
|
||||
'返回菜单', // 文本内容
|
||||
{ fontSize: '16px', color: '#ffffff' } // 样式
|
||||
).setOrigin(0, 0);
|
||||
|
||||
// 为返回菜单按钮添加点击区域
|
||||
const menuClickArea = this.add.rectangle(
|
||||
menuButton.x + menuButton.width / 2,
|
||||
menuButton.y + menuButton.height / 2,
|
||||
menuButton.width + 20,
|
||||
menuButton.height + 10,
|
||||
0x000000,
|
||||
0 // 透明
|
||||
).setOrigin(0.5, 0.5);
|
||||
|
||||
// 设置返回菜单按钮可交互
|
||||
menuClickArea.setInteractive({ useHandCursor: true });
|
||||
|
||||
// 添加返回菜单按钮点击事件
|
||||
menuClickArea.on('pointerdown', () => {
|
||||
console.log('Return to menu clicked');
|
||||
// 直接切换到菜单场景
|
||||
this.scene.start('MenuScene');
|
||||
});
|
||||
|
||||
// 添加进入boot菜单按钮
|
||||
const bootButton = this.add.text(
|
||||
20, // x坐标
|
||||
60, // y坐标
|
||||
'进入Boot菜单', // 文本内容
|
||||
{ fontSize: '16px', color: '#ffffff' } // 样式
|
||||
).setOrigin(0, 0);
|
||||
|
||||
// 为进入boot菜单按钮添加点击区域
|
||||
const bootClickArea = this.add.rectangle(
|
||||
bootButton.x + bootButton.width / 2,
|
||||
bootButton.y + bootButton.height / 2,
|
||||
bootButton.width + 20,
|
||||
bootButton.height + 10,
|
||||
0x000000,
|
||||
0 // 透明
|
||||
).setOrigin(0.5, 0.5);
|
||||
|
||||
// 设置进入boot菜单按钮可交互
|
||||
bootClickArea.setInteractive({ useHandCursor: true });
|
||||
|
||||
// 添加进入boot菜单按钮点击事件
|
||||
bootClickArea.on('pointerdown', () => {
|
||||
console.log('Enter boot menu clicked');
|
||||
// 直接切换到boot场景
|
||||
this.scene.start('BootScene');
|
||||
});
|
||||
}
|
||||
|
||||
// update方法:每帧自动调用(约60次/秒),用于更新游戏状态
|
||||
|
||||
+338
-12
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user