From 80896b4ddce0ad6bd62e85841233601195f34004 Mon Sep 17 00:00:00 2001 From: chicrobot Date: Tue, 27 Jan 2026 21:38:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(TOS)=20=E6=B7=BB=E5=8A=A0=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E6=B5=8B=E8=AF=95=E5=9C=BA=E6=99=AF=EF=BC=8C=E6=8B=86?= =?UTF-8?q?=E5=88=86=E8=AF=AD=E8=A8=80=E9=97=AE=E4=BB=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lang/default.js | 9 + lang/en.js | 9 + lang/translations.js | 32 +- lang/zh.js | 9 + main.js | 5 +- scenes/BootScene.js | 1 + scenes/TmpScene.js | 784 +++++++++++++++++--------- scenes/testScenes/TestObjectsScene.js | 757 +++++++++++++++++++++++++ 8 files changed, 1312 insertions(+), 294 deletions(-) create mode 100644 lang/default.js create mode 100644 lang/en.js create mode 100644 lang/zh.js create mode 100644 scenes/testScenes/TestObjectsScene.js diff --git a/lang/default.js b/lang/default.js new file mode 100644 index 0000000..6f58057 --- /dev/null +++ b/lang/default.js @@ -0,0 +1,9 @@ +// 默认语言翻译模块 +export default { + "title": "#*^#", + "start": "@%!$%", + "exit": "#@*%", + "rain": "$!*^", + "on": "(^", + "off": "($$" +}; \ No newline at end of file diff --git a/lang/en.js b/lang/en.js new file mode 100644 index 0000000..ae2e8e2 --- /dev/null +++ b/lang/en.js @@ -0,0 +1,9 @@ +// 英文翻译模块 +export default { + "title": "CINC", + "start": "start", + "exit": "exit", + "rain": "rain", + "on": "on", + "off": "off" +}; \ No newline at end of file diff --git a/lang/translations.js b/lang/translations.js index 8da45b1..0ba6299 100644 --- a/lang/translations.js +++ b/lang/translations.js @@ -1,27 +1,11 @@ +// 导入各个语言的翻译文件 +import defaultTranslations from './default.js'; +import enTranslations from './en.js'; +import zhTranslations from './zh.js'; + export default { - "#^": { - "title": "#*^#", - 'start': "@%!$%", - "exit": "#@*%", - "rain": "$!*^", - "on": "(^", - "off": "($$" - }, - "en": { - "title": "CINC", - "start": "start", - "exit": "exit", - "rain": "rain", - "on": "on", - "off": "off" - }, - "中文": { - "title": "游戏", - "start": "开始", - "exit": "退出", - "rain": "雨天", - "on": "开启", - "off": "关闭" - } + "#^": defaultTranslations, + "en": enTranslations, + "中文": zhTranslations } diff --git a/lang/zh.js b/lang/zh.js new file mode 100644 index 0000000..c31b60e --- /dev/null +++ b/lang/zh.js @@ -0,0 +1,9 @@ +// 中文翻译模块 +export default { + "title": "游戏", + "start": "开始", + "exit": "退出", + "rain": "雨天", + "on": "开启", + "off": "关闭" +}; \ No newline at end of file diff --git a/main.js b/main.js index 784c763..ac9f7a8 100644 --- a/main.js +++ b/main.js @@ -38,6 +38,8 @@ import FogOfWarTestScene from './scenes/testScenes/FogOfWarTestScene.js'; import MenuScene from './scenes/MenuScene.js'; // 导入临时场景 import TmpScene from './scenes/TmpScene.js'; +// 导入测试对象场景 +import TestObjectsScene from './scenes/testScenes/TestObjectsScene.js'; // 创建游戏的最终配置对象 const config = { // 使用扩展运算符(...)将gameConfig中的所有配置项复制到当前对象中 @@ -46,8 +48,9 @@ const config = { // 指定游戏使用的场景列表,包括主场景和所有测试场景 scene: [ MenuScene, - BootScene, TmpScene, + TestObjectsScene, + BootScene, GameScene, KeyboardMovementTestScene, TargetMovementTestScene, diff --git a/scenes/BootScene.js b/scenes/BootScene.js index b5fd800..c420217 100644 --- a/scenes/BootScene.js +++ b/scenes/BootScene.js @@ -17,6 +17,7 @@ export default class BootScene extends Phaser.Scene { // 测试场景列表 const testScenes = [ + { key: 'TestObjectsScene', name: '测试场景19:测试对象场景' }, { key: 'TmpScene', name: '测试场景18:临时场景' }, { key: 'FogOfWarTestScene', name: '测试场景17:迷雾系统测试' }, { key: 'AttackSkillTestScene', name: '测试场景16:攻击技能测试' }, diff --git a/scenes/TmpScene.js b/scenes/TmpScene.js index 52c0cf1..88d8c88 100644 --- a/scenes/TmpScene.js +++ b/scenes/TmpScene.js @@ -1,348 +1,464 @@ +/** + * TmpScene 类 - 示例场景,展示如何创建一个带有可展开信息栏的Phaser场景 + * 继承自Phaser.Scene,是Phaser游戏中场景的基本结构 + */ export default class TmpScene extends Phaser.Scene { + /** + * 构造函数 - 初始化场景 + * @constructor + */ constructor() { + // 调用父类构造函数,设置场景名称为'TmpScene' + // 场景名称用于在Phaser中切换场景时使用 super('TmpScene') + // 定义类成员变量 - this.infoBarVisible = false; // 信息栏是否可见 - this.infoBar = null; // 信息栏对象 - this.infoBarToggle = null; // 信息栏展开/收起按钮 - this.infoBarContainer = null; // 信息栏容器 - this.infoBarScrollContainer = null; // 滚动容器 - this.infoBarComponents = {}; // 组件管理对象 - this.infoBarConfig = { // 信息栏配置 - width: 0, - height: 0, - components: {}, // 组件配置 - autoCleanup: true, // 是否自动清理资源密集型组件 - scrollable: true // 是否支持滚动 + + // 信息栏可见性状态 - 初始为隐藏 + this.infoBarVisible = false; + + // 信息栏对象引用 - 用于存储信息栏的所有相关元素 + this.infoBar = null; + + // 信息栏展开/收起按钮引用 + this.infoBarToggle = null; + + // 信息栏主容器引用 - 包含整个信息栏的所有元素 + this.infoBarContainer = null; + + // 滚动容器引用 - 包含所有可滚动的组件 + this.infoBarScrollContainer = null; + + // 组件管理对象 - 存储所有添加到信息栏的组件实例 + this.infoBarComponents = {}; + + // 信息栏配置对象 - 控制信息栏的行为和外观 + this.infoBarConfig = { + width: 0, // 信息栏宽度,将在create方法中根据屏幕宽度计算 + height: 0, // 信息栏高度,将在create方法中根据屏幕高度计算 + components: {}, // 存储组件配置信息 + autoCleanup: true, // 是否自动清理资源密集型组件,优化性能 + scrollable: true // 是否支持滚动,当组件总高度超过屏幕高度时 }; + // 滚动相关变量 - this.scrollY = 0; - this.maxScrollY = 0; - this.isDragging = false; - this.lastDragY = 0; + this.scrollY = 0; // 当前滚动位置 + this.maxScrollY = 0; // 最大滚动距离 + this.isDragging = false; // 是否正在拖动滚动 + this.lastDragY = 0; // 上一次拖动的Y坐标 } + /** + * create方法 - 场景创建时调用的方法,用于初始化场景中的所有元素 + * 在Phaser中,场景启动后会自动调用此方法 + */ create() { - // 设置背景色 + // 设置场景背景色为深灰色 + // cameras.main 是场景的主相机,控制场景的渲染区域 this.cameras.main.setBackgroundColor('#333333'); - // 获取屏幕宽度和高度 + + // 获取屏幕宽度和高度,存储为实例变量供后续使用 + // this.scale.width 和 this.scale.height 是Phaser提供的获取当前游戏窗口大小的属性 this.screenWidth = this.scale.width; this.screenHeight = this.scale.height; - // 创建右侧信息栏 + + // 调用方法创建右侧信息栏 this.createRightInfoBar(); - // 示例:添加不同类型的组件,带固定高度和自定义顺序 + // 示例:添加不同类型的组件到信息栏,带固定高度和自定义顺序 + + // 添加角色状态组件 - 文本类型 this.addInfoBarComponent('playerStats', { - type: 'text', - title: '角色状态', - content: ['生命值: 100/100', '魔法值: 50/50', '等级: 1'], - enabled: true, - resourceIntensive: false, + type: 'text', // 组件类型:文本 + title: '角色状态', // 组件标题 + content: ['生命值: 100/100', '魔法值: 50/50', '等级: 1'], // 组件内容 + enabled: true, // 组件是否启用 + resourceIntensive: false, // 是否为资源密集型组件 height: 120, // 固定高度 - order: 1 // 自定义顺序 + order: 1 // 自定义顺序(越小越靠前) }); + // 添加小地图组件 - 占位符类型 this.addInfoBarComponent('miniMap', { - type: 'placeholder', // 占位符,实际项目中替换为真实小地图 - title: '小地图', - content: ['小地图区域'], - enabled: true, - resourceIntensive: true, + type: 'placeholder', // 占位符类型,实际项目中替换为真实小地图 + title: '小地图', // 组件标题 + content: ['小地图区域'], // 组件内容 + enabled: true, // 组件是否启用 + resourceIntensive: true, // 标记为资源密集型组件,会在信息栏收起时自动清理 height: 180, // 固定高度 order: 2 // 自定义顺序 }); + // 添加游戏日志组件 - 文本类型 this.addInfoBarComponent('gameLog', { - type: 'text', - title: '游戏日志', - content: ['系统: 欢迎来到游戏', '提示: 按H查看帮助', '新任务: 探索未知区域', '提示: 按I打开背包'], - enabled: true, - resourceIntensive: false, + type: 'text', // 组件类型:文本 + title: '游戏日志', // 组件标题 + content: ['系统: 欢迎来到游戏', '提示: 按H查看帮助', '新任务: 探索未知区域', '提示: 按I打开背包'], // 组件内容 + enabled: true, // 组件是否启用 + resourceIntensive: false, // 是否为资源密集型组件 height: 160, // 固定高度 order: 3 // 自定义顺序 }); // 初始化时,如果信息栏可见,创建所有启用的组件 + // 由于初始状态下infoBarVisible为false,这里不会执行 if (this.infoBarVisible) { this.createAllEnabledComponents(); } } - // 创建所有启用的组件 + /** + * 创建所有启用的组件 + * 按自定义顺序创建组件实例,并重新排列和更新滚动区域 + */ createAllEnabledComponents() { - // 按自定义顺序创建组件 + // 获取按自定义顺序排序的组件列表 const orderedComponents = this.getOrderedComponents(); + + // 遍历排序后的组件,创建启用的组件实例 orderedComponents.forEach(({id, config}) => { if (config.enabled) { this.createComponentInstance(id, config.config); } }); - // 重新排列组件 + + // 重新排列组件位置 this.rearrangeComponents(); - // 更新滚动区域 + + // 更新滚动区域大小 this.updateScrollArea(); } - // 获取按自定义顺序排序的组件 + /** + * 获取按自定义顺序排序的组件 + * @returns {Array} 排序后的组件数组,每个元素包含id和config + */ getOrderedComponents() { + // 将组件配置对象转换为数组 + // Object.entries() 将对象转换为[key, value]数组 return Object.entries(this.infoBarConfig.components) + // 映射为包含id和config的对象数组 .map(([id, config]) => ({id, config})) + // 按order属性排序,order值越小越靠前 .sort((a, b) => { + // 获取每个组件的order值,如果没有设置则默认为0 const orderA = a.config.config.order || 0; const orderB = b.config.config.order || 0; return orderA - orderB; }); } - // 创建右侧信息栏 + /** + * 创建右侧信息栏 + * 包括容器、背景、滚动容器和展开/收起按钮 + */ createRightInfoBar() { - // 定义信息栏宽度 + // 定义信息栏宽度为屏幕宽度的20% this.infoBarConfig.width = this.screenWidth * 0.2; + this.infoBarConfig.height = this.screenHeight * 0.8; - // 创建信息栏容器 + // 创建信息栏主容器 + // this.add.container() 创建一个新的容器,用于组织和管理多个游戏对象 this.infoBarContainer = this.add.container( - this.screenWidth, // 初始位置在屏幕右侧外 - 0 + this.screenWidth, // 初始位置在屏幕上侧外 + 0 - this.infoBarConfig.height // Y坐标 ); // 创建信息栏背景 + // this.add.rectangle() 创建一个矩形游戏对象 const infoBarBg = this.add.rectangle( - 0, // 相对于容器的位置 - 0, // 相对于容器的位置 - this.infoBarConfig.width, - this.screenHeight, - 0x222222, // 背景色 + 0, // 相对于容器的X位置 + 0, // 相对于容器的Y位置 + this.infoBarConfig.width, // 宽度 + this.screenHeight, // 高度 + 0x222222, // 背景色(深灰色) 0.9 // 透明度 - ).setOrigin(1, 0); // 锚点在右上角 + ).setOrigin(1, 0); // 设置锚点在右上角,便于定位 // 创建滚动容器,用于容纳所有组件 this.infoBarScrollContainer = this.add.container( - -this.infoBarConfig.width, // 相对于信息栏容器的位置 - 0 + -this.infoBarConfig.width, // 相对于信息栏容器的X位置 + 0 // Y坐标为0 ); // 将背景和滚动容器添加到信息栏容器 + // 容器的add方法可以添加多个游戏对象 this.infoBarContainer.add([infoBarBg, this.infoBarScrollContainer]); - // 添加滚动功能 + // 如果配置了滚动功能,设置滚动 if (this.infoBarConfig.scrollable) { this.setupScrolling(); } // 创建信息栏展开/收起按钮,固定在屏幕右上角 + // this.add.text() 创建文本游戏对象 this.infoBarToggle = this.add.text( - this.screenWidth - 40, // 按钮位置 - 20, + this.screenWidth, // 按钮X位置 + 0, // 按钮Y位置 '+', // 初始文本 - { fontSize: '24px', fill: '#ffffff', backgroundColor: '#444444', padding: { x: 10, y: 5 } } - ).setOrigin(0.5, 0.5).setInteractive(); + { fontSize: '16px', fill: '#ffffff', backgroundColor: '#444444', padding: { x: 10, y: 5 } } + ).setOrigin(1, 0) // 设置锚点在右上角 + .setInteractive(); // 设置为可交互,以便接收鼠标事件 - // 添加点击事件 + // 添加点击事件监听器 + // on('pointerdown', callback) 监听鼠标按下事件 this.infoBarToggle.on('pointerdown', () => { - this.toggleInfoBar(); + this.toggleInfoBar(); // 调用方法切换信息栏显示/隐藏 }); - // 保存信息栏对象,便于其他系统更新 + // 保存信息栏对象,便于其他系统更新和访问 this.infoBar = { - container: this.infoBarContainer, - scrollContainer: this.infoBarScrollContainer, - toggle: this.infoBarToggle, - bg: infoBarBg, - config: this.infoBarConfig, - components: this.infoBarComponents + container: this.infoBarContainer, // 信息栏主容器 + scrollContainer: this.infoBarScrollContainer, // 滚动容器 + toggle: this.infoBarToggle, // 展开/收起按钮 + bg: infoBarBg, // 背景 + config: this.infoBarConfig, // 配置 + components: this.infoBarComponents // 组件 }; } - // 设置滚动功能 + /** + * 设置滚动功能 + * 添加鼠标和触摸事件监听,实现信息栏的滚动效果 + */ setupScrolling() { // 移除遮罩,使用简单的滚动方式 // 添加鼠标事件监听 + // on('pointerdown', callback) 监听鼠标按下事件 this.input.on('pointerdown', (pointer) => { // 检查点击是否在信息栏区域内 const infoBarRect = new Phaser.Geom.Rectangle( - this.screenWidth - this.infoBarConfig.width, - 0, - this.infoBarConfig.width, - this.screenHeight + this.screenWidth - this.infoBarConfig.width, // 信息栏左边界 + 0, // 上边界 + this.infoBarConfig.width, // 宽度 + this.screenHeight // 高度 ); + // 检查点击位置是否在信息栏内且信息栏可见 if (Phaser.Geom.Rectangle.ContainsPoint(infoBarRect, pointer) && this.infoBarVisible) { - this.isDragging = true; - this.lastDragY = pointer.y; + this.isDragging = true; // 开始拖动 + this.lastDragY = pointer.y; // 记录初始拖动位置 } }); + // 监听鼠标移动事件 this.input.on('pointermove', (pointer) => { if (this.isDragging) { + // 计算拖动距离 const deltaY = pointer.y - this.lastDragY; + // 调用滚动方法 this.scroll(deltaY); + // 更新最后拖动位置 this.lastDragY = pointer.y; } }); + // 监听鼠标释放事件 this.input.on('pointerup', () => { - this.isDragging = false; + this.isDragging = false; // 结束拖动 }); - // 添加触摸事件支持 + // 添加触摸事件支持,使滚动在移动设备上也能工作 this.input.on('touchstart', (pointer) => { - this.input.emit('pointerdown', pointer); + this.input.emit('pointerdown', pointer); // 触发pointerdown事件 }); this.input.on('touchmove', (pointer) => { - this.input.emit('pointermove', pointer); + this.input.emit('pointermove', pointer); // 触发pointermove事件 }); this.input.on('touchend', () => { - this.input.emit('pointerup'); + this.input.emit('pointerup'); // 触发pointerup事件 }); } - // 滚动逻辑 + /** + * 滚动逻辑 + * 处理滚动位置计算和应用 + * @param {number} deltaY - 滚动距离 + */ scroll(deltaY) { + // 计算新的滚动位置 const newScrollY = this.scrollY + deltaY; - // 限制滚动范围 + // 限制滚动范围,使用Phaser.Math.Clamp确保值在指定范围内 this.scrollY = Phaser.Math.Clamp(newScrollY, 0, this.maxScrollY); - // 应用滚动 + // 应用滚动:通过设置滚动容器的Y位置实现 this.infoBarScrollContainer.setY(-this.scrollY); } - // 更新滚动区域 + /** + * 更新滚动区域 + * 计算所有组件的总高度,更新最大滚动距离 + */ updateScrollArea() { // 计算所有组件的总高度 let totalHeight = 20; // 顶部边距 const orderedComponents = this.getOrderedComponents(); + // 遍历所有组件,累加高度 orderedComponents.forEach(({id}) => { if (this.infoBarComponents[id]) { totalHeight += this.infoBarComponents[id].height + 10; // 组件高度 + 间距 } }); - // 更新最大滚动距离 + // 更新最大滚动距离:总高度减去屏幕高度,加上底部边距 this.maxScrollY = Math.max(0, totalHeight - this.screenHeight + 20); // +20为底部边距 } - // 切换信息栏显示/隐藏 + /** + * 切换信息栏显示/隐藏 + * 使用Phaser的tweens系统实现平滑的动画效果 + */ toggleInfoBar() { + // 切换信息栏可见性状态 this.infoBarVisible = !this.infoBarVisible; if (this.infoBarVisible) { // 展开信息栏 + // 使用tweens.add()创建动画 this.tweens.add({ - targets: this.infoBarContainer, - x: this.screenWidth - this.infoBarConfig.width, - duration: 300, - ease: 'Power1' + targets: this.infoBarContainer, // 动画目标:信息栏容器 + x: this.screenWidth, // 目标X位置:屏幕右侧减去信息栏宽度 + duration: 300, // 动画持续时间:300毫秒 + ease: 'Power1' // 缓动函数:Power1(线性) }); + + // 更新按钮文本为'-'(收起) this.infoBarToggle.setText('-'); + // 创建所有启用的组件 this.createAllEnabledComponents(); } else { // 收起信息栏 this.tweens.add({ - targets: this.infoBarContainer, - x: this.screenWidth, - duration: 300, - ease: 'Power1' + targets: this.infoBarContainer, // 动画目标:信息栏容器 + x: this.screenWidth + this.infoBarConfig.width, // 目标X位置:屏幕右侧外 + duration: 300, // 动画持续时间:300毫秒 + ease: 'Power1' // 缓动函数:Power1(线性) }); + + // 更新按钮文本为'+'(展开) this.infoBarToggle.setText('+'); - // 清理资源密集型组件 + + // 如果配置了自动清理,清理资源密集型组件 if (this.infoBarConfig.autoCleanup) { this.cleanupResourceIntensiveComponents(); } } } - // 添加信息栏组件 + /** + * 添加信息栏组件 + * @param {string} id - 组件唯一标识符 + * @param {Object} componentConfig - 组件配置对象 + * @returns {Object} 组件实例 + */ addInfoBarComponent(id, componentConfig) { - // 保存组件配置 + // 保存组件配置到信息栏配置对象 this.infoBarConfig.components[id] = { - enabled: componentConfig.enabled !== false, - resourceIntensive: componentConfig.resourceIntensive || false, - config: componentConfig + enabled: componentConfig.enabled !== false, // 默认为启用 + resourceIntensive: componentConfig.resourceIntensive || false, // 默认为非资源密集型 + config: componentConfig // 保存原始配置 }; - // 如果信息栏可见且组件启用,则创建组件 + // 如果信息栏可见且组件启用,则创建组件实例 if (this.infoBarVisible && this.infoBarConfig.components[id].enabled) { this.createComponentInstance(id, componentConfig); - // 重新排列组件 + // 重新排列组件位置 this.rearrangeComponents(); } + // 返回组件实例 return this.infoBarComponents[id]; } - // 创建组件实例 + /** + * 创建组件实例 + * 根据组件类型创建不同的实例 + * @param {string} id - 组件唯一标识符 + * @param {Object} componentConfig - 组件配置对象 + * @returns {Object} 组件实例 + */ createComponentInstance(id, componentConfig) { // 根据组件类型创建不同的实例 let componentInstance; switch (componentConfig.type) { case 'text': + // 创建文本组件 componentInstance = this.createTextComponent(id, componentConfig); break; case 'miniMap': + // 创建小地图组件 componentInstance = this.createMiniMapComponent(id, componentConfig); break; case 'placeholder': default: + // 创建占位符组件 componentInstance = this.createPlaceholderComponent(id, componentConfig); break; } - // 保存组件实例 + // 保存组件实例到组件管理对象 this.infoBarComponents[id] = componentInstance; return componentInstance; } - // 创建文本组件 + /** + * 创建文本组件 + * @param {string} id - 组件唯一标识符 + * @param {Object} config - 组件配置对象 + * @returns {Object} 文本组件实例 + */ createTextComponent(id, config) { + // 创建组件组容器 const componentGroup = this.add.container( - 10, // 相对于滚动容器的位置,左内边距10px - 0 + 10, // 相对于滚动容器的X位置,左内边距10px + 0 // 相对于滚动容器的Y位置 ); - // 创建组件容器,用于容纳标题栏和内容 + // 创建组件内容容器,用于容纳标题栏和内容 const componentContent = this.add.container(0, 0); // 创建标题栏背景 const titleBar = this.add.rectangle( - 0, - 0, - this.infoBarConfig.width - 20, - 30, - 0x444444, - 0.5 - ).setOrigin(0, 0); + 0, // X位置 + 0, // Y位置 + this.infoBarConfig.width - 20, // 宽度:信息栏宽度减去左右内边距 + 30, // 高度 + 0x444444, // 颜色 + 0.5 // 透明度 + ).setOrigin(0, 0); // 锚点在左上角 // 创建组件标题 const title = this.add.text( - 10, - 5, - config.title, - { fontSize: '14px', fill: '#ffffff', fontWeight: 'bold' } - ).setOrigin(0, 0); + 10, // X位置 + 5, // Y位置 + config.title, // 标题文本 + { fontSize: '14px', fill: '#ffffff', fontWeight: 'bold' } // 样式 + ).setOrigin(0, 0); // 锚点在左上角 // 创建展开/收起按钮 const toggleBtn = this.add.text( - this.infoBarConfig.width - 30, - 5, - '-', - { fontSize: '16px', fill: '#ffffff' } - ).setOrigin(0, 0).setInteractive(); + this.infoBarConfig.width - 30, // X位置 + 5, // Y位置 + '-', // 初始文本 + { fontSize: '16px', fill: '#ffffff' } // 样式 + ).setOrigin(0, 0) // 锚点在左上角 + .setInteractive(); // 设置为可交互 // 创建分隔线 const separator = this.add.line( - 0, - 30, - 0, 0, - this.infoBarConfig.width - 20, 0, - 0x555555 - ).setOrigin(0, 0); + 0, // X位置 + 30, // Y位置 + 0, 0, // 起始点 + this.infoBarConfig.width - 20, 0, // 结束点 + 0x555555 // 颜色 + ).setOrigin(0, 0); // 锚点在左上角 // 创建内容容器,用于动态管理内容 const contentContainer = this.add.container(0, 30); @@ -351,11 +467,11 @@ export default class TmpScene extends Phaser.Scene { const contentTexts = []; config.content.forEach((line, index) => { const text = this.add.text( - 10, - index * 25, - line, - { fontSize: '12px', fill: '#cccccc' } - ).setOrigin(0, 0); + 10, // X位置 + index * 25, // Y位置:每行25像素 + line, // 文本内容 + { fontSize: '12px', fill: '#cccccc' } // 样式 + ).setOrigin(0, 0); // 锚点在左上角 contentTexts.push(text); }); @@ -371,8 +487,8 @@ export default class TmpScene extends Phaser.Scene { // 保存组件状态 const componentState = { - expanded: true, - contentVisible: true + expanded: true, // 是否展开 + contentVisible: true // 内容是否可见 }; // 添加展开/收起点击事件 @@ -381,9 +497,10 @@ export default class TmpScene extends Phaser.Scene { }); // 计算高度 - const collapsedHeight = 40; - const expandedHeight = config.height || (30 + config.content.length * 25) + 10; + const collapsedHeight = 40; // 收起时的高度 + const expandedHeight = config.height || (30 + config.content.length * 25) + 10; // 展开时的高度 + // 返回组件实例对象 return { group: componentGroup, componentContent: componentContent, @@ -402,70 +519,78 @@ export default class TmpScene extends Phaser.Scene { }; } - // 创建小地图组件(示例) + /** + * 创建小地图组件(示例) + * @param {string} id - 组件唯一标识符 + * @param {Object} config - 组件配置对象 + * @returns {Object} 小地图组件实例 + */ createMiniMapComponent(id, config) { + // 创建组件组容器 const componentGroup = this.add.container( - 10, // 相对于滚动容器的位置,左内边距10px - 0 + 10, // 相对于滚动容器的X位置,左内边距10px + 0 // 相对于滚动容器的Y位置 ); - // 创建组件容器,用于容纳标题栏和内容 + // 创建组件内容容器,用于容纳标题栏和内容 const componentContent = this.add.container(0, 0); // 创建标题栏背景 const titleBar = this.add.rectangle( - 0, - 0, - this.infoBarConfig.width - 20, - 30, - 0x444444, - 0.5 - ).setOrigin(0, 0); + 0, // X位置 + 0, // Y位置 + this.infoBarConfig.width - 20, // 宽度:信息栏宽度减去左右内边距 + 30, // 高度 + 0x444444, // 颜色 + 0.5 // 透明度 + ).setOrigin(0, 0); // 锚点在左上角 // 创建组件标题 const title = this.add.text( - 10, - 5, - config.title, - { fontSize: '14px', fill: '#ffffff', fontWeight: 'bold' } - ).setOrigin(0, 0); + 10, // X位置 + 5, // Y位置 + config.title, // 标题文本 + { fontSize: '14px', fill: '#ffffff', fontWeight: 'bold' } // 样式 + ).setOrigin(0, 0); // 锚点在左上角 // 创建展开/收起按钮 const toggleBtn = this.add.text( - this.infoBarConfig.width - 30, - 5, - '-', - { fontSize: '16px', fill: '#ffffff' } - ).setOrigin(0, 0).setInteractive(); + this.infoBarConfig.width - 30, // X位置 + 5, // Y位置 + '-', // 初始文本 + { fontSize: '16px', fill: '#ffffff' } // 样式 + ).setOrigin(0, 0) // 锚点在左上角 + .setInteractive(); // 设置为可交互 // 创建分隔线 const separator = this.add.line( - 0, - 30, - 0, 0, - this.infoBarConfig.width - 20, 0, - 0x555555 - ).setOrigin(0, 0); + 0, // X位置 + 30, // Y位置 + 0, 0, // 起始点 + this.infoBarConfig.width - 20, 0, // 结束点 + 0x555555 // 颜色 + ).setOrigin(0, 0); // 锚点在左上角 // 创建内容容器,用于动态管理内容 const contentContainer = this.add.container(0, 30); // 创建小地图占位符(实际项目中替换为真实小地图) const miniMapBg = this.add.rectangle( - (this.infoBarConfig.width - 20) / 2, - (config.height - 40) / 2, // 垂直居中,减去标题栏高度 - this.infoBarConfig.width - 40, // 宽度固定为信息栏宽度减去内边距 - config.height - 50, // 高度固定,减去标题和分隔线高度 - 0x111111, - 1 - ).setOrigin(0.5, 0.5); + (this.infoBarConfig.width - 20) / 2, // X位置:水平居中 + (config.height - 40) / 2, // Y位置:垂直居中,减去标题栏高度 + this.infoBarConfig.width - 40, // 宽度:信息栏宽度减去内边距 + config.height - 50, // 高度:固定高度减去标题和分隔线高度 + 0x111111, // 颜色 + 1 // 透明度 + ).setOrigin(0.5, 0.5); // 锚点在中心 + // 创建小地图文本 const miniMapText = this.add.text( - (this.infoBarConfig.width - 20) / 2, - (config.height - 40) / 2, // 垂直居中 - '小地图', - { fontSize: '12px', fill: '#cccccc' } - ).setOrigin(0.5, 0.5); + (this.infoBarConfig.width - 20) / 2, // X位置:水平居中 + (config.height - 40) / 2, // Y位置:垂直居中 + '小地图', // 文本 + { fontSize: '12px', fill: '#cccccc' } // 样式 + ).setOrigin(0.5, 0.5); // 锚点在中心 // 将内容添加到内容容器 contentContainer.add([miniMapBg, miniMapText]); @@ -479,8 +604,8 @@ export default class TmpScene extends Phaser.Scene { // 保存组件状态 const componentState = { - expanded: true, - contentVisible: true, + expanded: true, // 是否展开 + contentVisible: true, // 内容是否可见 contentCreated: true // 标记内容已创建 }; @@ -490,9 +615,10 @@ export default class TmpScene extends Phaser.Scene { }); // 计算高度 - const collapsedHeight = 40; - const expandedHeight = config.height || 160; + const collapsedHeight = 40; // 收起时的高度 + const expandedHeight = config.height || 160; // 展开时的高度 + // 返回组件实例对象 return { group: componentGroup, componentContent: componentContent, @@ -512,61 +638,72 @@ export default class TmpScene extends Phaser.Scene { }; } - // 创建占位符组件 + /** + * 创建占位符组件 + * @param {string} id - 组件唯一标识符 + * @param {Object} config - 组件配置对象 + * @returns {Object} 占位符组件实例 + */ createPlaceholderComponent(id, config) { + // 创建组件组容器 const componentGroup = this.add.container( - 10, // 相对于滚动容器的位置,左内边距10px - 0 + 10, // 相对于滚动容器的X位置,左内边距10px + 0 // 相对于滚动容器的Y位置 ); - // 创建组件容器,用于容纳标题栏和内容 + // 创建组件内容容器,用于容纳标题栏和内容 const componentContent = this.add.container(0, 0); // 创建标题栏背景 const titleBar = this.add.rectangle( - 0, - 0, - this.infoBarConfig.width - 20, - 30, - 0x444444, - 0.5 - ).setOrigin(0, 0); + 0, // X位置 + 0, // Y位置 + this.infoBarConfig.width - 20, // 宽度:信息栏宽度减去左右内边距 + 30, // 高度 + 0x444444, // 颜色 + 0.5 // 透明度 + ).setOrigin(0, 0); // 锚点在左上角 // 创建组件标题 const title = this.add.text( - 10, - 5, - config.title, - { fontSize: '14px', fill: '#ffffff', fontWeight: 'bold' } - ).setOrigin(0, 0); + 10, // X位置 + 5, // Y位置 + config.title, // 标题文本 + { fontSize: '14px', fill: '#ffffff', fontWeight: 'bold' } // 样式 + ).setOrigin(0, 0); // 锚点在左上角 // 创建展开/收起按钮 const toggleBtn = this.add.text( - this.infoBarConfig.width - 30, - 5, - '-', - { fontSize: '16px', fill: '#ffffff' } - ).setOrigin(0, 0).setInteractive(); + this.infoBarConfig.width - 30, // X位置 + 5, // Y位置 + '-', // 初始文本 + { fontSize: '16px', fill: '#ffffff' } // 样式 + ).setOrigin(0, 0) // 锚点在左上角 + .setInteractive(); // 设置为可交互 // 创建分隔线 const separator = this.add.line( - 0, - 30, - 0, 0, - this.infoBarConfig.width - 20, 0, - 0x555555 - ).setOrigin(0, 0); + 0, // X位置 + 30, // Y位置 + 0, 0, // 起始点 + this.infoBarConfig.width - 20, 0, // 结束点 + 0x555555 // 颜色 + ).setOrigin(0, 0); // 锚点在左上角 // 创建内容容器,用于动态管理内容 const contentContainer = this.add.container(0, 30); // 创建内容 const contentText = this.add.text( - 10, - 0, - config.content.join('\n'), - { fontSize: '12px', fill: '#cccccc', wordWrap: { width: this.infoBarConfig.width - 40 } } - ).setOrigin(0, 0); + 10, // X位置 + 0, // Y位置 + config.content.join('\n'), // 内容文本,将数组元素用换行符连接 + { + fontSize: '12px', + fill: '#cccccc', + wordWrap: { width: this.infoBarConfig.width - 40 } // 自动换行 + } + ).setOrigin(0, 0); // 锚点在左上角 // 将内容添加到内容容器 contentContainer.add([contentText]); @@ -580,8 +717,8 @@ export default class TmpScene extends Phaser.Scene { // 保存组件状态 const componentState = { - expanded: true, - contentVisible: true + expanded: true, // 是否展开 + contentVisible: true // 内容是否可见 }; // 添加展开/收起点击事件 @@ -590,9 +727,10 @@ export default class TmpScene extends Phaser.Scene { }); // 计算高度 - const collapsedHeight = 40; - const expandedHeight = config.height || (50 + contentText.height) + 10; + const collapsedHeight = 40; // 收起时的高度 + const expandedHeight = config.height || (50 + contentText.height) + 10; // 展开时的高度 + // 返回组件实例对象 return { group: componentGroup, componentContent: componentContent, @@ -611,9 +749,17 @@ export default class TmpScene extends Phaser.Scene { }; } - // 更新信息栏组件内容 + /** + * 更新信息栏组件内容 + * 目前仅支持更新文本类型组件的内容 + * @param {string} id - 组件唯一标识符 + * @param {Array} newContent - 新的内容数组 + */ updateInfoBarComponent(id, newContent) { + // 获取组件实例 const component = this.infoBarComponents[id]; + + // 检查组件是否存在且为文本类型 if (component && component.type === 'text') { // 清空现有内容 component.content.forEach(text => text.destroy()); @@ -622,11 +768,11 @@ export default class TmpScene extends Phaser.Scene { // 添加新内容 newContent.forEach((line, index) => { const text = this.add.text( - 0, - 30 + index * 25, - line, - { fontSize: '12px', fill: '#cccccc' } - ).setOrigin(0, 0); + 0, // X位置 + 30 + index * 25, // Y位置:标题栏高度 + 行索引 * 行高 + line, // 文本内容 + { fontSize: '12px', fill: '#cccccc' } // 样式 + ).setOrigin(0, 0); // 锚点在左上角 component.group.add(text); component.content.push(text); }); @@ -636,28 +782,39 @@ export default class TmpScene extends Phaser.Scene { } } - // 重新排列组件 + /** + * 重新排列组件 + * 按自定义顺序排列组件,并更新它们的Y位置 + */ rearrangeComponents() { let currentY = 20; // 起始Y位置,顶部边距20px - // 按自定义顺序排列组件 + // 获取按自定义顺序排序的组件列表 const orderedComponents = this.getOrderedComponents(); + + // 遍历组件,设置它们的Y位置 orderedComponents.forEach(({id}) => { const component = this.infoBarComponents[id]; if (component && component.group) { - component.group.setY(currentY); - currentY += component.height + 10; // 组件高度 + 间距10px + component.group.setY(currentY); // 设置组件的Y位置 + currentY += component.height + 10; // 更新当前Y位置:组件高度 + 间距10px } }); - // 更新滚动区域 + // 更新滚动区域大小 this.updateScrollArea(); } - // 切换组件显示/隐藏 + /** + * 切换组件显示/隐藏 + * @param {string} id - 组件唯一标识符 + */ toggleInfoBarComponent(id) { + // 获取组件配置 const componentConfig = this.infoBarConfig.components[id]; + if (componentConfig) { + // 切换组件启用状态 componentConfig.enabled = !componentConfig.enabled; if (componentConfig.enabled) { @@ -674,18 +831,28 @@ export default class TmpScene extends Phaser.Scene { } } - // 销毁组件实例 + /** + * 销毁组件实例 + * @param {string} id - 组件唯一标识符 + */ destroyComponentInstance(id) { if (this.infoBarComponents[id]) { + // 销毁组件的组容器 this.infoBarComponents[id].group.destroy(); + // 从组件管理对象中删除 delete this.infoBarComponents[id]; } } - // 清理资源密集型组件 + /** + * 清理资源密集型组件 + * 在信息栏收起时调用,释放资源 + */ cleanupResourceIntensiveComponents() { + // 遍历所有组件配置 for (const id in this.infoBarConfig.components) { const componentConfig = this.infoBarConfig.components[id]; + // 检查是否为资源密集型组件且存在实例 if (componentConfig.resourceIntensive && this.infoBarComponents[id]) { this.destroyComponentInstance(id); } @@ -694,50 +861,72 @@ export default class TmpScene extends Phaser.Scene { this.rearrangeComponents(); } - // 重新创建资源密集型组件 + /** + * 重新创建资源密集型组件 + * 在信息栏展开时调用,重新加载资源 + */ recreateResourceIntensiveComponents() { + // 遍历所有组件配置 for (const id in this.infoBarConfig.components) { const componentConfig = this.infoBarConfig.components[id]; + // 检查是否为资源密集型组件且已启用 if (componentConfig.resourceIntensive && componentConfig.enabled) { this.createComponentInstance(id, componentConfig.config); } } } - // 切换信息栏显示/隐藏 + /** + * 切换信息栏显示/隐藏(优化版) + * 使用Phaser的tweens系统实现平滑的动画效果 + */ toggleInfoBar() { + // 切换信息栏可见性状态 this.infoBarVisible = !this.infoBarVisible; if (this.infoBarVisible) { // 展开信息栏 this.tweens.add({ - targets: this.infoBarContainer, - x: this.screenWidth - this.infoBarConfig.width, - duration: 300, - ease: 'Power1' + targets: this.infoBarContainer, // 动画目标:信息栏容器 + x: this.screenWidth, // 目标X位置 + duration: 300, // 动画持续时间 + ease: 'Power1' // 缓动函数 }); + + // 更新按钮文本 this.infoBarToggle.setText('-'); + // 只创建缺失的组件(主要是资源密集型组件) this.createMissingComponents(); + // 确保所有组件正确排列 this.rearrangeComponents(); } else { // 收起信息栏 this.tweens.add({ - targets: this.infoBarContainer, - x: this.screenWidth, - duration: 300, - ease: 'Power1' + targets: this.infoBarContainer, // 动画目标:信息栏容器 + x: this.screenWidth + this.infoBarConfig.width, // 目标X位置 + duration: 300, // 动画持续时间 + ease: 'Power1' // 缓动函数 }); + + // 更新按钮文本 this.infoBarToggle.setText('+'); + // 只清理资源密集型组件 this.cleanupResourceIntensiveComponents(); } } - // 创建缺失的组件 + /** + * 创建缺失的组件 + * 只创建已启用但尚未创建实例的组件 + */ createMissingComponents() { + // 获取按自定义顺序排序的组件列表 const orderedComponents = this.getOrderedComponents(); + + // 遍历组件,创建缺失的实例 orderedComponents.forEach(({id, config}) => { if (config.enabled && !this.infoBarComponents[id]) { this.createComponentInstance(id, config.config); @@ -745,10 +934,14 @@ export default class TmpScene extends Phaser.Scene { }); } - // 创建所有启用的组件 + /** + * 创建所有启用的组件(完整重建) + * 先销毁所有现有组件,然后重新创建 + */ createAllEnabledComponents() { // 先销毁所有现有组件,避免重叠 this.destroyAllComponents(); + // 然后创建所有启用的组件 const orderedComponents = this.getOrderedComponents(); orderedComponents.forEach(({id, config}) => { @@ -756,21 +949,35 @@ export default class TmpScene extends Phaser.Scene { this.createComponentInstance(id, config.config); } }); + // 排列组件 this.rearrangeComponents(); + // 更新滚动区域 this.updateScrollArea(); } - // 销毁所有组件 + /** + * 销毁所有组件 + * 清理所有组件实例 + */ destroyAllComponents() { + // 遍历所有组件实例 for (const id in this.infoBarComponents) { this.destroyComponentInstance(id); } } - // 切换组件展开/收起 + /** + * 切换组件展开/收起 + * @param {string} id - 组件唯一标识符 + * @param {Object} state - 组件状态对象 + * @param {Phaser.GameObjects.Container} contentContainer - 内容容器 + * @param {Phaser.GameObjects.Text} toggleBtn - 切换按钮 + * @param {boolean} isResourceIntensive - 是否为资源密集型组件 + */ toggleComponent(id, state, contentContainer, toggleBtn, isResourceIntensive = false) { + // 切换展开状态 state.expanded = !state.expanded; if (state.expanded) { @@ -785,7 +992,9 @@ export default class TmpScene extends Phaser.Scene { } } + // 显示内容容器 contentContainer.visible = true; + // 更新组件高度 this.infoBarComponents[id].height = this.infoBarComponents[id].expandedHeight; } else { @@ -798,54 +1007,76 @@ export default class TmpScene extends Phaser.Scene { state.contentCreated = false; } + // 隐藏内容容器 contentContainer.visible = false; + // 更新组件高度 this.infoBarComponents[id].height = this.infoBarComponents[id].collapsedHeight; } // 重新排列所有组件 this.rearrangeComponents(); + // 更新滚动区域 this.updateScrollArea(); } - // 销毁组件内容 + /** + * 销毁组件内容 + * 清理组件的内容容器中的所有子元素 + * @param {string} id - 组件唯一标识符 + */ destroyComponentContent(id) { + // 获取组件实例 const component = this.infoBarComponents[id]; + + // 检查组件和内容容器是否存在 if (component && component.contentContainer) { // 销毁内容容器中的所有子元素 + // removeAll(true) 中的true表示同时销毁这些元素 component.contentContainer.removeAll(true); } } - // 重新创建组件内容 + /** + * 重新创建组件内容 + * 为资源密集型组件重新创建内容 + * @param {string} id - 组件唯一标识符 + */ recreateComponentContent(id) { + // 获取组件实例 const component = this.infoBarComponents[id]; + + // 检查组件和内容容器是否存在 if (!component || !component.contentContainer) return; + // 获取组件配置 const config = component.config; + // 根据组件类型重新创建内容 switch (config.type) { case 'miniMap': case 'placeholder': // 重新创建小地图内容 const miniMapBg = this.add.rectangle( - (this.infoBarConfig.width - 20) / 2, - (config.height - 40) / 2, - this.infoBarConfig.width - 40, - config.height - 50, - 0x111111, - 1 - ).setOrigin(0.5, 0.5); + (this.infoBarConfig.width - 20) / 2, // 水平居中 + (config.height - 40) / 2, // 垂直居中 + this.infoBarConfig.width - 40, // 宽度 + config.height - 50, // 高度 + 0x111111, // 颜色 + 1 // 透明度 + ).setOrigin(0.5, 0.5); // 锚点在中心 const miniMapText = this.add.text( - (this.infoBarConfig.width - 20) / 2, - (config.height - 40) / 2, - '小地图', - { fontSize: '12px', fill: '#cccccc' } - ).setOrigin(0.5, 0.5); + (this.infoBarConfig.width - 20) / 2, // 水平居中 + (config.height - 40) / 2, // 垂直居中 + '小地图', // 文本 + { fontSize: '12px', fill: '#cccccc' } // 样式 + ).setOrigin(0.5, 0.5); // 锚点在中心 + // 添加到内容容器 component.contentContainer.add([miniMapBg, miniMapText]); + // 更新组件引用 component.map = miniMapBg; component.mapText = miniMapText; break; @@ -855,41 +1086,56 @@ export default class TmpScene extends Phaser.Scene { const contentTexts = []; config.content.forEach((line, index) => { const text = this.add.text( - 10, - index * 25, - line, - { fontSize: '12px', fill: '#cccccc' } - ).setOrigin(0, 0); + 10, // X位置 + index * 25, // Y位置 + line, // 文本 + { fontSize: '12px', fill: '#cccccc' } // 样式 + ).setOrigin(0, 0); // 锚点在左上角 contentTexts.push(text); }); + // 添加到内容容器 component.contentContainer.add(contentTexts); + // 更新组件引用 component.content = contentTexts; break; } } - // 设置信息栏自动清理策略 + /** + * 设置信息栏自动清理策略 + * @param {boolean} enabled - 是否启用自动清理 + */ setInfoBarAutoCleanup(enabled) { this.infoBarConfig.autoCleanup = enabled; } - // 更新信息栏内容的方法(向后兼容) + /** + * 更新信息栏内容的方法(向后兼容) + * 兼容旧接口,更新第一个文本组件 + * @param {Array} newContent - 新的内容数组 + */ updateInfoBarContent(newContent) { - // 兼容旧接口,更新第一个文本组件 + // 查找第一个文本类型组件 const firstTextComponentId = Object.keys(this.infoBarComponents).find( id => this.infoBarComponents[id] && this.infoBarComponents[id].type === 'text' ); + // 如果找到,更新其内容 if (firstTextComponentId) { this.updateInfoBarComponent(firstTextComponentId, newContent); } } + /** + * update方法 - 场景更新方法 + * 在Phaser中,每帧都会调用此方法 + */ update() { // 示例:模拟动态更新角色状态 if (this.infoBarVisible && this.infoBarComponents.playerStats) { // 这里可以添加真实的状态更新逻辑 + // 例如:根据游戏中的实际数据更新角色状态信息 } } } \ No newline at end of file diff --git a/scenes/testScenes/TestObjectsScene.js b/scenes/testScenes/TestObjectsScene.js new file mode 100644 index 0000000..8ccc8f1 --- /dev/null +++ b/scenes/testScenes/TestObjectsScene.js @@ -0,0 +1,757 @@ +/** + * TestObjectsScene - 测试场景,展示Phaser中的各种对象类型 + */ +export default class TestObjectsScene extends Phaser.Scene { + constructor() { + super('TestObjectsScene'); + } + + preload() { + // 注意:实际项目中需要先加载纹理 + // 本示例使用内置图形,不需要加载外部资源 + } + + create() { + // 设置背景色 + this.cameras.main.setBackgroundColor('#222222'); + + // 获取屏幕宽度,用于响应式布局 + const screenWidth = this.cameras.main.width; + const screenHeight = this.cameras.main.height; + const centerX = screenWidth / 2; + + // 设置世界边界,允许滚动 + this.cameras.main.setBounds(0, 0, screenWidth, 3000); + + // 滚动相关变量 + this.scrollVelocity = 0; + this.scrollAcceleration = 0.98; + + // 启用鼠标/触摸滚动 + this.input.on('pointermove', (pointer) => { + if (pointer.isDown) { + // 调整滚动速度和方向:向上拖动时内容向上滚动,速度更快 + this.scrollVelocity = -pointer.velocity.y * 0.15; + this.cameras.main.scrollY += this.scrollVelocity; + // 限制滚动范围 + this.cameras.main.scrollY = Phaser.Math.Clamp(this.cameras.main.scrollY, 0, 2400); + } + }); + + // 停止触摸时应用惯性滚动 + this.input.on('pointerup', () => { + // 创建惯性滚动 + this.tweens.add({ + targets: this, + scrollVelocity: 0, + duration: 500, + ease: 'Power2', + onUpdate: (tween) => { + this.cameras.main.scrollY += this.scrollVelocity; + // 限制滚动范围 + this.cameras.main.scrollY = Phaser.Math.Clamp(this.cameras.main.scrollY, 0, 2400); + } + }); + }); + + // 1. 文本对象 + this.createTextObjects(centerX); + + // 2. 图像和精灵 + this.createImageObjects(centerX); + + // 3. 图形对象 + this.createGraphicsObjects(centerX); + + // 4. 容器对象 + this.createContainerObjects(centerX); + + // 5. 粒子系统 + this.createParticles(centerX); + + // 6. 物理对象(简单示例) + this.createPhysicsObjects(centerX); + + // 7. 精灵对象 + this.createSpriteObjects(centerX); + + // 8. 瓦片地图 + this.createTilemapObjects(centerX); + + // 9. 点阵文字 + this.createBitmapTextObjects(centerX); + + // 10. 渲染纹理 + this.createRenderTextureObjects(centerX); + + // 11. 形状对象 + this.createShapeObjects(centerX); + + // 12. 多相机系统 + this.createCameraObjects(centerX); + + // 13. 灯光系统 + this.createLightObjects(centerX); + + // 14. 路径系统 + this.createPathObjects(centerX); + + // 15. 网格系统 + this.createGridObjects(centerX); + + // 16. 时间线 + this.createTimelineObjects(centerX); + + // 添加滚动指示器 + this.add.text(centerX, 2850, '↓ 向下滚动查看更多 ↓', { + fontSize: '14px', + fill: '#aaaaaa', + backgroundColor: '#333333', + padding: { x: 15, y: 8 } + }) + .setOrigin(0.5) + .setScrollFactor(0); // 固定在屏幕底部 + + // 添加顶部指示器 + this.add.text(centerX, 10, '↑ 向上滚动返回顶部 ↑', { + fontSize: '14px', + fill: '#aaaaaa', + backgroundColor: '#333333', + padding: { x: 15, y: 8 } + }) + .setOrigin(0.5) + .setScrollFactor(0); // 固定在屏幕顶部 + + // 添加返回按钮 + this.add.text(20, 20, '按 ESC 返回', { fontSize: '16px', fill: '#ffffff' }) + .setInteractive() + .on('pointerdown', () => { + this.scene.start('TmpScene'); + }); + } + + // 创建文本对象 + createTextObjects(centerX) { + // 基本文本 + this.add.text(centerX, 50, '1. 文本对象示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 带样式的文本 + this.add.text(centerX, 90, '普通文本', { + fontSize: '16px', + fill: '#cccccc' + }).setOrigin(0.5); + + // 彩色文本 + this.add.text(centerX, 120, '彩色文本', { + fontSize: '16px', + fill: '#ff0000' + }).setOrigin(0.5); + + // 带背景的文本 + this.add.text(centerX, 150, '带背景的文本', { + fontSize: '16px', + fill: '#ffffff', + backgroundColor: '#444444', + padding: { x: 10, y: 5 } + }).setOrigin(0.5); + } + + // 创建图像和精灵 + createImageObjects(centerX) { + // 标题 + this.add.text(centerX, 200, '2. 图像和精灵示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 使用图形替代图像 + const logo = this.add.graphics() + .fillStyle(0x3498db, 1) + .fillRect(0, 0, 100, 50) + .setPosition(centerX - 50, 255) + .setInteractive(new Phaser.Geom.Rectangle(0, 0, 100, 50), Phaser.Geom.Rectangle.Contains) + .on('pointerdown', function() { + this.scaleX *= 1.1; + this.scaleY *= 1.1; + }); + + // 添加文本标签 + this.add.text(centerX, 270, 'Phaser Logo', { + fontSize: '12px', + fill: '#ffffff' + }).setOrigin(0.5); + + // 精灵(使用圆形替代纹理) + const redDot = this.add.circle(centerX, 320, 10, 0xff0000, 1) + .setInteractive() + .on('pointerdown', function() { + this.angle += 45; + }); + } + + // 创建图形对象 + createGraphicsObjects(centerX) { + // 标题 + this.add.text(centerX, 350, '3. 图形对象示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 矩形 + this.add.rectangle(centerX - 80, 420, 100, 60, 0xff0000, 0.5) + .setInteractive() + .on('pointerdown', function() { + this.fillColor = Phaser.Math.Between(0x000000, 0xffffff); + }); + + // 圆形 + this.add.circle(centerX, 420, 30, 0x00ff00, 0.5) + .setInteractive() + .on('pointerdown', function() { + this.radius = Phaser.Math.Between(20, 40); + }); + + // 线段 + this.add.line(centerX + 80, 420, 0, -30, 0, 30, 0xffff00, 1) + .setInteractive() + .on('pointerdown', function() { + this.angle += 15; + }); + } + + // 创建容器对象 + createContainerObjects(centerX) { + // 标题 + this.add.text(centerX, 480, '4. 容器对象示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 创建容器 + const container = this.add.container(centerX, 550); + + // 容器背景 + const bg = this.add.rectangle(0, 0, 200, 100, 0x444444, 0.8); + container.add(bg); + + // 容器内的文本 + const text = this.add.text(0, 0, '容器示例', { + fontSize: '16px', + fill: '#ffffff' + }).setOrigin(0.5); + container.add(text); + + // 容器内的圆形 + const circle = this.add.circle(0, 30, 10, 0x00ffff, 1); + container.add(circle); + + // 使容器可交互 + container.setInteractive(new Phaser.Geom.Rectangle(-100, -50, 200, 100), Phaser.Geom.Rectangle.Contains) + .on('pointerdown', () => { + container.angle += 10; + }); + } + + // 创建粒子系统 + createParticles(centerX) { + // 标题 + this.add.text(centerX, 650, '5. 粒子系统示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 注意:粒子系统需要纹理,实际项目中需要先加载 + // 本示例使用图形替代粒子效果 + const particles = this.add.graphics() + .fillStyle(0x3498db, 1) + .fillCircle(0, 0, 5) + .setPosition(centerX, 720) + .setVisible(false); + + // 添加交互,点击时显示粒子效果 + this.add.text(centerX, 750, '点击显示粒子效果', { + fontSize: '14px', + fill: '#ffffff', + backgroundColor: '#444444', + padding: { x: 10, y: 5 } + }) + .setOrigin(0.5) + .setInteractive() + .on('pointerdown', () => { + // 创建多个圆形模拟粒子效果 + for (let i = 0; i < 20; i++) { + const particle = this.add.circle(centerX, 720, 3, 0x3498db, 1); + this.tweens.add({ + targets: particle, + x: centerX + Phaser.Math.Between(-100, 100), + y: 720 + Phaser.Math.Between(-100, -50), + alpha: 0, + scale: 0, + duration: 1000, + onComplete: function() { + particle.destroy(); + } + }); + } + }); + } + + // 创建物理对象(简单示例) + createPhysicsObjects(centerX) { + // 标题 + this.add.text(centerX, 800, '6. 物理对象示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 注意:物理系统需要在游戏配置中启用 + // 本示例使用图形替代物理对象 + const ground = this.add.rectangle(centerX, 880, 300, 20, 0x666666, 1); + + // 创建圆形图形 + const ball = this.add.circle(centerX, 820, 10, 0xe74c3c, 1) + .setInteractive() + .on('pointerdown', function() { + // 模拟物理效果 + this.setY(this.y - 50); + this.scene.tweens.add({ + targets: this, + y: 820, + duration: 500, + ease: 'Bounce.easeOut' + }); + }); + + // 添加交互,点击时给球一个向上的力 + this.add.text(centerX, 880, '点击小球', { + fontSize: '14px', + fill: '#ffffff' + }) + .setOrigin(0.5); + } + + update() { + // 可以在这里添加对象的更新逻辑 + } + + // 7. 精灵对象 + createSpriteObjects(centerX) { + // 标题 + this.add.text(centerX, 950, '7. 精灵对象示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 注意:精灵需要纹理,实际项目中需要先加载 + // 本示例使用图形替代精灵 + const sprite = this.add.graphics() + .fillStyle(0x9b59b6, 1) + .fillCircle(0, 0, 20) + .setPosition(centerX, 1020) + .setInteractive(new Phaser.Geom.Circle(0, 0, 20), Phaser.Geom.Circle.Contains) + .on('pointerdown', function() { + this.angle += 30; + }); + + // 添加文本标签 + this.add.text(centerX, 1060, '精灵示例', { + fontSize: '14px', + fill: '#ffffff' + }).setOrigin(0.5); + } + + // 8. 瓦片地图 + createTilemapObjects(centerX) { + // 标题 + this.add.text(centerX, 1100, '8. 瓦片地图示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 注意:瓦片地图需要纹理,实际项目中需要先加载 + // 本示例使用图形替代瓦片地图 + const tilemap = this.add.graphics() + .fillStyle(0x27ae60, 0.8) + .fillRect(0, 0, 200, 100) + .setPosition(centerX - 100, 1140); + + // 添加模拟瓦片 + for (let i = 0; i < 5; i++) { + for (let j = 0; j < 10; j++) { + this.add.rectangle( + centerX - 90 + j * 20, + 1150 + i * 20, + 18, + 18, + 0x2ecc71, + 0.6 + ); + } + } + + // 添加文本标签 + this.add.text(centerX, 1260, '瓦片地图示例', { + fontSize: '14px', + fill: '#ffffff' + }).setOrigin(0.5); + } + + // 9. 点阵文字 + createBitmapTextObjects(centerX) { + // 标题 + this.add.text(centerX, 1300, '9. 点阵文字示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 注意:点阵文字需要字体纹理,实际项目中需要先加载 + // 本示例使用普通文本替代 + this.add.text(centerX, 1340, '点阵文字示例', { + fontSize: '16px', + fill: '#f1c40f', + fontFamily: 'monospace' + }).setOrigin(0.5); + + // 添加文本标签 + this.add.text(centerX, 1380, '(使用普通文本模拟)', { + fontSize: '12px', + fill: '#cccccc' + }).setOrigin(0.5); + } + + // 10. 渲染纹理 + createRenderTextureObjects(centerX) { + // 标题 + this.add.text(centerX, 1420, '10. 渲染纹理示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 创建渲染纹理 + const rt = this.add.renderTexture(centerX - 100, 1460, 200, 100); + + // 绘制一些内容到渲染纹理 + const graphics = this.add.graphics().setVisible(false); + graphics.fillStyle(0xe74c3c, 1); + graphics.fillCircle(100, 50, 30); + graphics.lineStyle(2, 0xffffff, 1); + graphics.lineBetween(50, 50, 150, 50); + + // 将图形绘制到渲染纹理 + rt.draw(graphics, 0, 0); + + // 添加交互,点击时清除并重新绘制 + rt.setInteractive(new Phaser.Geom.Rectangle(0, 0, 200, 100), Phaser.Geom.Rectangle.Contains) + .on('pointerdown', function() { + this.clear(); + this.draw(graphics, Phaser.Math.Between(0, 100), Phaser.Math.Between(0, 50)); + }); + } + + // 11. 形状对象 + createShapeObjects(centerX) { + // 标题 + this.add.text(centerX, 1550, '11. 形状对象示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 创建三角形(使用graphics) + const triangle = this.add.graphics() + .fillStyle(0x3498db, 0.8) + .beginPath() + .moveTo(0, -40) + .lineTo(-30, 40) + .lineTo(30, 40) + .closePath() + .fillPath() + .setPosition(centerX - 40, 1620) + .setInteractive(new Phaser.Geom.Triangle(-30, 40, 30, 40, 0, -40), Phaser.Geom.Triangle.Contains) + .on('pointerdown', function() { + this.angle += 30; + }); + + // 创建圆角矩形 + this.add.rectangle(centerX + 40, 1620, 80, 60, 0xe74c3c, 0.8) + .setInteractive() + .on('pointerdown', function() { + this.setScale(this.scaleX * 1.1); + }); + } + + // 12. 多相机系统 + createCameraObjects(centerX) { + // 标题 + this.add.text(centerX, 1750, '12. 多相机系统示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 添加说明文本 + this.add.text(centerX, 1790, '多相机系统可以同时显示不同视角的内容', { + fontSize: '14px', + fill: '#aaaaaa' + }).setOrigin(0.5); + + // 创建第二个相机(左侧) + const camera2 = this.cameras.add(centerX - 110, 1830, 180, 120); + camera2.setBackgroundColor(0x2c3e50); + + // 创建第三个相机(右侧) + const camera3 = this.cameras.add(centerX + 10, 1830, 180, 120); + camera3.setBackgroundColor(0x34495e); + + // 在第二个相机中创建对象 + const leftText = this.add.text(camera2.x + camera2.width / 2, camera2.y + camera2.height / 2 - 20, '左侧相机', { + fontSize: '14px', + fill: '#ffffff' + }).setOrigin(0.5); + + const leftCircle = this.add.circle(camera2.x + camera2.width / 2, camera2.y + camera2.height / 2 + 20, 15, 0x3498db, 1); + + // 在第三个相机中创建对象 + const rightText = this.add.text(camera3.x + camera3.width / 2, camera3.y + camera3.height / 2 - 20, '右侧相机', { + fontSize: '14px', + fill: '#ffffff' + }).setOrigin(0.5); + + const rightSquare = this.add.rectangle(camera3.x + camera3.width / 2, camera3.y + camera3.height / 2 + 20, 30, 30, 0xe74c3c, 1); + + // 添加交互,点击时控制相机 + this.add.text(centerX, 1970, '点击切换相机视角', { + fontSize: '14px', + fill: '#ffffff', + backgroundColor: '#444444', + padding: { x: 15, y: 8 } + }) + .setOrigin(0.5) + .setInteractive() + .on('pointerdown', () => { + // 移动左侧相机中的圆形 + this.tweens.add({ + targets: leftCircle, + x: leftCircle.x + 50, + duration: 800, + yoyo: true, + repeat: 1 + }); + + // 旋转右侧相机中的正方形 + this.tweens.add({ + targets: rightSquare, + angle: 360, + duration: 1600, + ease: 'Linear' + }); + + // 改变相机背景色 + camera2.setBackgroundColor(Phaser.Display.Color.RandomRGB(50, 100).color); + camera3.setBackgroundColor(Phaser.Display.Color.RandomRGB(50, 100).color); + }); + + // 添加相机功能说明 + this.add.text(centerX, 2010, '相机1: 主视角 | 相机2: 左侧视角 | 相机3: 右侧视角', { + fontSize: '12px', + fill: '#aaaaaa' + }).setOrigin(0.5); + } + + // 13. 灯光系统 + createLightObjects(centerX) { + // 标题 + this.add.text(centerX, 2050, '13. 灯光系统示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 注意:实际灯光系统需要特殊配置 + // 本示例使用图形模拟灯光效果 + + // 创建灯光图形 + const light = this.add.graphics() + .fillStyle(0xffffff, 0.3) + .fillCircle(0, 0, 100) + .setPosition(centerX, 2130); + + // 创建一些对象来展示灯光效果 + this.add.rectangle(centerX - 50, 2110, 30, 30, 0x666666, 1); + this.add.rectangle(centerX + 50, 2110, 30, 30, 0x666666, 1); + this.add.rectangle(centerX, 2150, 30, 30, 0x666666, 1); + + // 添加交互,点击时移动灯光 + this.add.text(centerX, 2200, '点击移动灯光', { + fontSize: '14px', + fill: '#ffffff' + }) + .setOrigin(0.5) + .setInteractive() + .on('pointerdown', () => { + const x = centerX + Phaser.Math.Between(-50, 50); + const y = 2100 + Phaser.Math.Between(-30, 30); + light.setPosition(x, y); + }); + } + + // 14. 路径系统 + createPathObjects(centerX) { + // 标题 + this.add.text(centerX, 2250, '14. 路径系统示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 绘制路径 + const graphics = this.add.graphics(); + graphics.lineStyle(2, 0xffffff, 0.5); + graphics.strokeRect(centerX - 100, 2300, 200, 100); + + // 创建一个对象沿着路径移动 + const follower = this.add.circle(centerX - 100, 2300, 10, 0xff0000, 1); + + // 创建路径动画 + this.tweens.add({ + targets: { pos: 0 }, + pos: 1, + duration: 4000, + repeat: -1, + ease: 'Linear', + onUpdate: (tween) => { + const progress = tween.targets[0].pos; + + // 矩形路径:右 -> 下 -> 左 -> 上 + if (progress < 0.25) { + // 右 + follower.x = centerX - 100 + (progress * 4) * 200; + follower.y = 2300; + } else if (progress < 0.5) { + // 下 + follower.x = centerX + 100; + follower.y = 2300 + ((progress - 0.25) * 4) * 100; + } else if (progress < 0.75) { + // 左 + follower.x = centerX + 100 - ((progress - 0.5) * 4) * 200; + follower.y = 2400; + } else { + // 上 + follower.x = centerX - 100; + follower.y = 2400 - ((progress - 0.75) * 4) * 100; + } + } + }); + } + + // 15. 网格系统 + createGridObjects(centerX) { + // 标题 + this.add.text(centerX, 2450, '15. 网格系统示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 创建网格 + const grid = this.add.grid(centerX, 2520, 200, 100, 20, 20, 0x444444, 0, 0x666666, 0.3); + + // 在网格上添加一些对象 + for (let i = 0; i < 5; i++) { + const x = centerX - 90 + i * 40; + for (let j = 0; j < 2; j++) { + const y = 2490 + j * 40; + this.add.circle(x, y, 5, 0x2ecc71, 1); + } + } + } + + // 16. 时间线 + createTimelineObjects(centerX) { + // 标题 + this.add.text(centerX, 2600, '16. 时间线示例', { + fontSize: '20px', + fill: '#ffffff', + fontWeight: 'bold' + }).setOrigin(0.5); + + // 创建对象 + const obj1 = this.add.rectangle(centerX - 40, 2670, 40, 40, 0x3498db, 1); + const obj2 = this.add.circle(centerX, 2670, 20, 0xe74c3c, 1); + const obj3 = this.add.graphics() + .fillStyle(0xf1c40f, 1) + .beginPath() + .moveTo(0, -20) + .lineTo(-20, 20) + .lineTo(20, 20) + .closePath() + .fillPath() + .setPosition(centerX + 40, 2670); + + // 添加交互,点击时播放动画序列 + this.add.text(centerX, 2750, '点击播放动画', { + fontSize: '14px', + fill: '#ffffff' + }) + .setOrigin(0.5) + .setInteractive() + .on('pointerdown', () => { + // 动画序列 + this.tweens.add({ + targets: obj1, + y: 2620, + duration: 500, + ease: 'Power2', + onComplete: () => { + this.tweens.add({ + targets: obj2, + scale: 1.5, + duration: 500, + ease: 'Power2', + onComplete: () => { + this.tweens.add({ + targets: obj3, + angle: 360, + duration: 1000, + ease: 'Linear', + onComplete: () => { + this.tweens.add({ + targets: obj1, + y: 950, + duration: 500, + ease: 'Power2' + }); + this.tweens.add({ + targets: obj2, + scale: 1, + duration: 500, + ease: 'Power2' + }); + this.tweens.add({ + targets: obj3, + angle: 0, + duration: 500, + ease: 'Power2' + }); + } + }); + } + }); + } + }); + }); + } +} \ No newline at end of file