From 2616dc21f137b3a73534555f9c5d54d1dd12e800 Mon Sep 17 00:00:00 2001 From: chicrobot Date: Wed, 4 Feb 2026 18:46:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(SS)=20=E6=B7=BB=E5=8A=A0=E6=B8=B8=E6=88=8F?= =?UTF-8?q?=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.js | 9 +- scenes/storeScenes/PrimordialDevide.js | 2 +- scenes/storeScenes/WorldLand.js | 134 ++++++++++++++++++++ scenes/storeScenes/WorldTime.js | 161 +++++++++++++++++++++++++ systems/GameTimeManager.js | 124 +++++++++++++++++++ 5 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 scenes/storeScenes/WorldLand.js create mode 100644 scenes/storeScenes/WorldTime.js create mode 100644 systems/GameTimeManager.js diff --git a/main.js b/main.js index 2e4f273..becdaa8 100644 --- a/main.js +++ b/main.js @@ -50,9 +50,12 @@ import CharacterClassTestScene from './scenes/testScenes/CharacterClassTestScene import WeaponTestScene from './scenes/testScenes/WeaponTestScene.js'; // 故事场景 -// 导入开天辟地 +// 开天辟地 import PrimordialDevide from './scenes/storeScenes/PrimordialDevide.js'; -// 导入女娲造人 +// 日月山川 +import WorldTime from './scenes/storeScenes/WorldTime.js'; +import WorldLand from './scenes/storeScenes/WorldLand.js'; +// 女娲造人 import BreatheLife from './scenes/storeScenes/BreatheLife.js'; // 创建游戏的最终配置对象 @@ -63,6 +66,8 @@ const config = { // 指定游戏使用的场景列表,包括主场景和所有测试场景 scene: [ PrimordialDevide, + WorldTime, + WorldLand, BreatheLife, // 测试场景 diff --git a/scenes/storeScenes/PrimordialDevide.js b/scenes/storeScenes/PrimordialDevide.js index 30fa358..6040eda 100644 --- a/scenes/storeScenes/PrimordialDevide.js +++ b/scenes/storeScenes/PrimordialDevide.js @@ -11,7 +11,7 @@ export default class PrimordialDevide extends Phaser.Scene { */ constructor() { super('PrimordialDevide') - this.nextScene = 'BreatheLife' + this.nextScene = 'WorldTime' } /** diff --git a/scenes/storeScenes/WorldLand.js b/scenes/storeScenes/WorldLand.js new file mode 100644 index 0000000..eb625c0 --- /dev/null +++ b/scenes/storeScenes/WorldLand.js @@ -0,0 +1,134 @@ +/** + * WorldLand 场景类 + * + * 初始引导场景,显示空白背景并在用户交互或自动延迟后 + * 执行过渡动画切换到下一个场景 + */ +import GameTimeManager from '../../systems/GameTimeManager.js' + +export default class WorldLand extends Phaser.Scene { + /** + * 构造函数 + * 初始化场景并设置场景键名为 'WorldLand' + */ + constructor() { + super('WorldLand') + this.nextScene = 'BreatheLife' + + this.timeManager = new GameTimeManager() // 创建游戏时间管理器实例 + + this.UIDepth = 100 // UI层级深度,确保在其他元素之上 + this.maskDepth = 99 // 黑夜遮罩层级,低于UI层级 + + } + create() { + // 设置场景背景颜色为深灰色 + this.cameras.main.setBackgroundColor('#999999') + + // 监听鼠标点击事件,点击后执行场景过渡动画 + this.input.on('pointerdown', () => { + this.scene.start(this.nextScene); + }) + + // 监听键盘按键事件,按键后执行场景过渡动画 + this.input.keyboard.on('keydown', () => { + this.scene.start(this.nextScene); + }) + + this.initDayNight(this.toGameTime('1999-12-30 23:57:00')) // 初始化时间,白天黑夜状态 + this.initFrameRateText() // 初始化帧率显示文本 + } + /** + * 更新游戏时间 + * 每帧调用,刷新游戏时间 + */ + update() { + this.showFrameRate() // 显示当前帧率 + this.updateGameTime() // 更新游戏时间 + this.displayTime() // 显示当前游戏时间 + this.updateDayNight() // 更新昼夜状态 + } + + + initFrameRateText() { + // 创建帧率显示文本 + this.frameRateText = this.add.text( + 20, 60, '', { + fontSize: '20px', + fill: '#ffffff', + fontFamily: 'Arial' + } + ).setScrollFactor(0).setDepth(this.UIDepth) // 固定文本,不随相机移动,UI层级 + } + showFrameRate() { + // 获取当前帧率 + const frameRate = this.game.loop.actualFps + // 更新帧率显示文本 + this.frameRateText.setText(`Frame Rate: ${frameRate.toFixed(2)}`) + } + /** + * 初始化昼夜状态 + * 设置初始为白天,添加事件监听切换状态 + */ + initDayNight(gameTime) { + this.timeManager.init(gameTime) // 初始化时间管理器 + // 创建时间显示文本 + this.timeText = this.add.text( + 20, 20, '', { + fontSize: '20px', + fill: '#ffffff', + fontFamily: 'Arial' + } + ).setScrollFactor(0).setDepth(this.UIDepth) // 固定文本,不随相机移动,UI层级 + // 添加黑夜遮罩 + this.nightMask = this.add.rectangle( + 0, 0, + this.cameras.main.width, + this.cameras.main.height, + 0x000000 + ).setOrigin(0, 0).setScrollFactor(0).setDepth(this.maskDepth) // 固定遮罩,不随相机移动,遮罩层级 + this.nightMask.alpha = 0 // 初始设置为透明 + } + /** + * 更新游戏时间 + * 每帧调用,基于现实时间流逝更新游戏时间 + */ + updateGameTime() { + this.timeManager.updateGameTime() // 使用时间管理器更新游戏时间 + } + /** + * 获取游戏中的日期 + * 根据游戏时间戳计算游戏年月日时分秒,格式为YYYY-MM-DD HH:mm:ss + */ + getGameDate() { + return this.timeManager.getGameDate() // 使用时间管理器获取游戏日期 + } + /** + * 转换游戏时间字符串为游戏时间戳 + * 接收时间字符串,格式为YYYY-MM-DD HH:mm:ss,返回游戏时间戳(单位:秒) + */ + toGameTime(gameTimeString) { + return this.timeManager.toGameTime(gameTimeString) // 使用时间管理器转换游戏时间 + } + /** + * 显示当前时间 + * 每帧调用,更新显示时间 + */ + displayTime() { + const timeString = this.getGameDate().dateString + const day = this.timeManager.getDayNightState() ? '白天' : '黑夜' + // 更新显示时间 + this.timeText.setText(`${day} ${timeString}`) + } + /** + * 更新昼夜状态 + * 每帧调用,根据游戏时间切换白天黑夜状态 + */ + updateDayNight() { + const isDay = this.timeManager.updateDayNight() + // 根据昼夜状态更新遮罩 + if (this.nightMask) { + this.nightMask.alpha = isDay ? 0 : 0.5 + } + } +} diff --git a/scenes/storeScenes/WorldTime.js b/scenes/storeScenes/WorldTime.js new file mode 100644 index 0000000..7b53eaf --- /dev/null +++ b/scenes/storeScenes/WorldTime.js @@ -0,0 +1,161 @@ +/** + * WorldLand 场景类 + * + * 初始引导场景,显示空白背景并在用户交互或自动延迟后 + * 执行过渡动画切换到下一个场景 + */ +export default class WorldTime extends Phaser.Scene { + /** + * 构造函数 + * 初始化场景并设置场景键名为 'WorldTime' + */ + constructor() { + super('WorldTime') + this.nextScene = 'WorldLand' + + this.gameTime = 0 // 游戏中的时间戳(单位:秒) + // 固定为60秒/分钟,60分钟/小时,24小时/天,30天/月,12月/年 + this.minuteSec = 60 + this.hourSec = 60 * this.minuteSec + this.daySec = 24 * this.hourSec + this.monthSec = 30 * this.daySec + this.yearSec = 12 * this.monthSec + + this.lastRealTime = 0 // 上一次更新的现实时间戳(毫秒) + this.gameTimeUpdateInterval = 1000/60 // 游戏中的每秒时间更新间隔(毫秒) + + this.isDay = true // 昼夜状态 + + this.UIDepth = 100 // UI层级深度,确保在其他元素之上 + this.maskDepth = 99 // 黑夜遮罩层级,低于UI层级 + + } + create() { + // 设置场景背景颜色为深灰色 + this.cameras.main.setBackgroundColor('#999999') + + // 监听鼠标点击事件,点击后执行场景过渡动画 + this.input.on('pointerdown', () => { + this.scene.start(this.nextScene); + }) + + // 监听键盘按键事件,按键后执行场景过渡动画 + this.input.keyboard.on('keydown', () => { + this.scene.start(this.nextScene); + }) + + this.initDayNight(this.toGameTime('2000-01-01 17:57:00')) // 初始化时间,白天黑夜状态 + } + /** + * 更新游戏时间 + * 每帧调用,刷新游戏时间 + */ + update() { + this.updateGameTime() // 更新游戏时间 + this.displayTime() // 显示当前游戏时间 + this.updateDayNight() // 更新昼夜状态 + } + /** + * 初始化昼夜状态 + * 设置初始为白天,添加事件监听切换状态 + */ + initDayNight(gameTime) { + // 初始更新时间戳为当前现实时间,注意不要使用this.time.now,它是Phaser的时间戳,不是现实时间 + this.lastRealTime = Date.now() + this.isDay = true // 设置初始为白天 + this.gameTime = gameTime // 设置游戏初始时间 + // 创建时间显示文本 + this.timeText = this.add.text( + 20, 20, '', { + fontSize: '20px', + fill: '#ffffff', + fontFamily: 'Arial' + } + ).setScrollFactor(0).setDepth(this.UIDepth) // 固定文本,不随相机移动,UI层级 + // 添加黑夜遮罩 + this.nightMask = this.add.rectangle( + 0, 0, + this.cameras.main.width, + this.cameras.main.height, + 0x000000 + ).setOrigin(0, 0).setScrollFactor(0).setDepth(this.maskDepth) // 固定遮罩,不随相机移动,遮罩层级 + this.nightMask.alpha = 0 // 初始设置为透明 + } + /** + * 更新游戏时间 + * 每帧调用,基于现实时间流逝更新游戏时间 + */ + updateGameTime() { + // 获取当前现实时间戳 + const currentRealTime = Date.now() + // 计算与上次更新的时间差(毫秒) + const deltaRealTime = currentRealTime - this.lastRealTime + if (deltaRealTime <= this.gameTimeUpdateInterval) { // 小于更新间隔,不更新时间 + return + }else { + let addSec = deltaRealTime / this.gameTimeUpdateInterval // 计算增加的秒数 + this.gameTime += addSec // 更新游戏时间 + this.lastRealTime = currentRealTime // 刷新更新时间戳 + } + } + /** + * 获取游戏中的日期 + * 根据游戏时间戳计算游戏年月日时分秒,格式为YYYY-MM-DD HH:mm:ss + */ + getGameDate() { + // 计算当前时间的年、月、日、时、分、秒 + const year = Math.floor(this.gameTime / this.yearSec) + const month = Math.floor((this.gameTime % this.yearSec) / this.monthSec)+1 + const day = Math.floor((this.gameTime % this.monthSec) / this.daySec)+1 + const hour = Math.floor((this.gameTime % this.daySec) / this.hourSec) + const minute = Math.floor((this.gameTime % this.hourSec) / this.minuteSec) + const second = Math.floor(this.gameTime % this.minuteSec) + // 格式化日期字符串 + const dateString = `${year}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day} ${hour < 10 ? '0' : ''}${hour}:${minute < 10 ? '0' : ''}${minute}:${second < 10 ? '0' : ''}${second}` + const formatDate = { + year, month, day, hour, minute, second , + dateString, + } + return formatDate + } + /** + * 转换游戏时间字符串为游戏时间戳 + * 接收时间字符串,格式为YYYY-MM-DD HH:mm:ss,返回游戏时间戳(单位:秒) + */ + toGameTime(gameTimeString) { + // 解析时间字符串为秒数 + const [year, month, day, hour, minute, second] = gameTimeString.split(/[- :]/).map(Number) + // 计算游戏时间戳 + return year * this.yearSec + (month - 1) * this.monthSec + (day - 1) * this.daySec + hour * this.hourSec + minute * this.minuteSec + second + } + /** + * 显示当前时间 + * 每帧调用,更新显示时间 + */ + displayTime() { + const timeString = this.getGameDate().dateString + const day = this.isDay ? '白天' : '黑夜' + // 更新显示时间 + this.timeText.setText(`${day} ${timeString}`) + } + /** + * 更新昼夜状态 + * 每帧调用,根据游戏时间切换白天黑夜状态 + */ + updateDayNight() { + const hour = this.getGameDate().hour + if (hour >= 6 && hour < 18) { + this.isDay = true + // 白天:隐藏黑夜遮罩 + if (this.nightMask) { + this.nightMask.alpha = 0 + } + }else { + this.isDay = false + // 黑夜:显示黑夜遮罩 + if (this.nightMask) { + this.nightMask.alpha = 0.5 + } + } + } +} diff --git a/systems/GameTimeManager.js b/systems/GameTimeManager.js new file mode 100644 index 0000000..993611c --- /dev/null +++ b/systems/GameTimeManager.js @@ -0,0 +1,124 @@ +/** + * GameTimeManager 游戏时间管理类 + * + * 负责管理游戏中的时间系统,包括: + * 1. 游戏时间的更新和计算 + * 2. 游戏时间与现实时间的转换 + * 3. 游戏日期的获取 + * 4. 昼夜状态的管理 + */ +export default class GameTimeManager { + /** + * 构造函数 + * 初始化时间管理系统 + */ + constructor() { + this.gameTime = 0 // 游戏中的时间戳(单位:秒) + // 固定为60秒/分钟,60分钟/小时,24小时/天,30天/月,12月/年 + this.minuteSec = 60 + this.hourSec = 60 * this.minuteSec + this.daySec = 24 * this.hourSec + this.monthSec = 30 * this.daySec + this.yearSec = 12 * this.monthSec + + this.lastRealTime = 0 // 上一次更新的现实时间戳(毫秒) + this.gameTimeUpdateInterval = 1000/60 // 游戏中的每秒时间更新间隔(毫秒) + + this.isDay = true // 昼夜状态 + } + + /** + * 初始化时间系统 + * @param {number} initialGameTime - 初始游戏时间戳 + */ + init(initialGameTime) { + this.lastRealTime = Date.now() // 初始更新时间戳为当前现实时间 + this.isDay = true // 设置初始为白天 + this.gameTime = initialGameTime // 设置游戏初始时间 + } + + /** + * 更新游戏时间 + * 每帧调用,刷新游戏时间 + */ + updateGameTime() { + // 获取当前现实时间戳 + const currentRealTime = Date.now() + // 计算与上次更新的时间差(毫秒) + const deltaRealTime = currentRealTime - this.lastRealTime + if (deltaRealTime <= this.gameTimeUpdateInterval) { // 小于更新间隔,不更新时间 + return + } else { + let addSec = deltaRealTime / this.gameTimeUpdateInterval // 计算增加的秒数 + this.gameTime += addSec // 更新游戏时间 + this.lastRealTime = currentRealTime // 刷新更新时间戳 + } + } + + /** + * 获取游戏中的日期 + * 根据游戏时间戳计算游戏年月日时分秒,格式为YYYY-MM-DD HH:mm:ss + */ + getGameDate() { + // 计算当前时间的年、月、日、时、分、秒 + const year = Math.floor(this.gameTime / this.yearSec) + const month = Math.floor((this.gameTime % this.yearSec) / this.monthSec)+1 + const day = Math.floor((this.gameTime % this.monthSec) / this.daySec)+1 + const hour = Math.floor((this.gameTime % this.daySec) / this.hourSec) + const minute = Math.floor((this.gameTime % this.hourSec) / this.minuteSec) + const second = Math.floor(this.gameTime % this.minuteSec) + // 格式化日期字符串 + const dateString = `${year}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day} ${hour < 10 ? '0' : ''}${hour}:${minute < 10 ? '0' : ''}${minute}:${second < 10 ? '0' : ''}${second}` + const formatDate = { + year, month, day, hour, minute, second , + dateString, + } + return formatDate + } + + /** + * 转换游戏时间字符串为游戏时间戳 + * 接收时间字符串,格式为YYYY-MM-DD HH:mm:ss,返回游戏时间戳(单位:秒) + */ + toGameTime(gameTimeString) { + // 解析时间字符串为秒数 + const [year, month, day, hour, minute, second] = gameTimeString.split(/[- :]/).map(Number) + // 计算游戏时间戳 + return year * this.yearSec + (month - 1) * this.monthSec + (day - 1) * this.daySec + hour * this.hourSec + minute * this.minuteSec + second + } + + /** + * 更新昼夜状态 + * 每帧调用,根据游戏时间切换白天黑夜状态 + */ + updateDayNight() { + const hour = this.getGameDate().hour + if (hour >= 6 && hour < 18) { + this.isDay = true + } else { + this.isDay = false + } + return this.isDay + } + + /** + * 获取当前昼夜状态 + */ + getDayNightState() { + return this.isDay + } + + /** + * 获取当前游戏时间 + */ + getGameTime() { + return this.gameTime + } + + /** + * 设置游戏时间 + */ + setGameTime(gameTime) { + this.gameTime = gameTime + } +} \ No newline at end of file