diff --git a/main.js b/main.js index 020a2bf..2e4f273 100644 --- a/main.js +++ b/main.js @@ -5,6 +5,8 @@ import gameConfig from './config/gameConfig.js'; import BootScene from './scenes/BootScene.js'; import GameScene from './scenes/GameScene.js'; + +// 测试场景 // 导入移动测试场景 import KeyboardMovementTestScene from './scenes/testScenes/KeyboardMovementTestScene.js'; import TargetMovementTestScene from './scenes/testScenes/TargetMovementTestScene.js'; @@ -47,6 +49,12 @@ import CharacterClassTestScene from './scenes/testScenes/CharacterClassTestScene // 导入武器测试场景 import WeaponTestScene from './scenes/testScenes/WeaponTestScene.js'; +// 故事场景 +// 导入开天辟地 +import PrimordialDevide from './scenes/storeScenes/PrimordialDevide.js'; +// 导入女娲造人 +import BreatheLife from './scenes/storeScenes/BreatheLife.js'; + // 创建游戏的最终配置对象 const config = { // 使用扩展运算符(...)将gameConfig中的所有配置项复制到当前对象中 @@ -54,6 +62,10 @@ const config = { ...gameConfig, // 指定游戏使用的场景列表,包括主场景和所有测试场景 scene: [ + PrimordialDevide, + BreatheLife, + + // 测试场景 MenuScene, TmpScene, WeaponTestScene, diff --git a/scenes/storeScenes/BreatheLife.js b/scenes/storeScenes/BreatheLife.js new file mode 100644 index 0000000..0d8f0e6 --- /dev/null +++ b/scenes/storeScenes/BreatheLife.js @@ -0,0 +1,111 @@ +/** + * BreatheLife 场景类 + * + * 交互场景,允许用户通过点击屏幕创建角色 + * 当创建的角色超过3个时,点击已存在的角色会为其设置纹理 + * 当设置纹理的角色超过3个时,自动切换到 MenuScene 场景 + */ +export default class BreatheLife extends Phaser.Scene { + /** + * 构造函数 + * 初始化场景并设置场景键名为 'BreatheLife' + */ + constructor() {super('BreatheLife')} + + preload() { + // 加载角色动画和图片资源 + this.load.image(`player0-0`, `assets/PNG/Players/Tiles/tile_${String(0).padStart(4, '0')}.png`); + this.load.image(`player1-0`, `assets/PNG/Players/Tiles/tile_${String(8).padStart(4, '0')}.png`); + } + + /** + * 创建场景 + * 设置背景颜色,添加用户交互监听和自动切换计时器 + */ + create() { + // 设置场景背景颜色为灰色 + this.cameras.main.setBackgroundColor('#999999') + + // 初始化角色计数器,用于跟踪创建的角色数量 + this.spriteCount = 0 + this.spriteTextureCount = 0 + + // 监听鼠标点击事件,点击后创建一个新的角色 + this.input.on('pointerdown', () => { + // 获取点击位置的坐标 + const { x, y } = this.input.activePointer + this.createSprite(x, y) + }) + } + + /** + * 创建一个新的角色或获取点击的精灵 + * @param {number} x - 角色的 x 坐标 + * @param {number} y - 角色的 y 坐标 + */ + createSprite(x, y) { + // 获取点击位置的精灵 + const clickedSprite = this.getClickedSprite(x, y) + console.log("点击到的精灵:", clickedSprite) + console.log("已设置纹理的角色数量:", this.spriteTextureCount) + console.log("已创建的角色数量:", this.spriteCount) + if (this.spriteCount >= 3 && this.spriteTextureCount >= 3) { + this.scene.start('MenuScene') + return + }else if (clickedSprite) { // 如果点击到了精灵 + // 显示当前精灵的纹理 + console.log("当前精灵的纹理:", clickedSprite.texture.key) + // 如果没有纹理或纹理为默认值 + if (clickedSprite.texture.key === '__MISSING' || clickedSprite.texture.key === 'player') { + // 设置纹理 + this.setSpriteTexture(clickedSprite, `player1-0`) + } + return + }else if (this.spriteCount >= 3) { + return + } + + // 创建一个新的角色 sprite,缩放为1倍 + const sprite = this.physics.add.sprite(x, y, 'player').setScale(1) + + // 设置角色碰撞世界边界 + sprite.setCollideWorldBounds(true) + + // 增加角色计数器 + this.spriteCount++ + } + + /** + * 获取鼠标点击位置的精灵 + * @param {number} x - 点击位置的 x 坐标 + * @param {number} y - 点击位置的 y 坐标 + * @returns {Phaser.GameObjects.Sprite|null} - 点击位置的精灵,如果没有则返回 null + */ + getClickedSprite(x, y) { + // 获取场景中所有的精灵 + const sprites = this.children.getChildren().filter(child => child instanceof Phaser.GameObjects.Sprite) + + // 检查每个精灵是否被点击 + for (const sprite of sprites) { + // 检查点击位置是否在精灵的边界内 + if (sprite.getBounds().contains(x, y)) { + return sprite + } + } + + return null + } + + setSpriteTexture(sprite, textureKey) { + // 检查角色已设置的纹理数量是否超过3个 + if (this.spriteTextureCount > 3) { + // 当设置纹理的角色超过时,切换到 MenuScene 场景 + this.scene.start('MenuScene') + } + sprite.setTexture(textureKey).setScale(1) + + this.spriteTextureCount++ + + } + +} diff --git a/scenes/storeScenes/PrimordialDevide.js b/scenes/storeScenes/PrimordialDevide.js new file mode 100644 index 0000000..30fa358 --- /dev/null +++ b/scenes/storeScenes/PrimordialDevide.js @@ -0,0 +1,143 @@ +/** + * PrimordialDevide 场景类 + * + * 初始引导场景,显示空白背景并在用户交互或自动延迟后 + * 执行过渡动画切换到下一个场景 + */ +export default class PrimordialDevide extends Phaser.Scene { + /** + * 构造函数 + * 初始化场景并设置场景键名为 'PrimordialDevide' + */ + constructor() { + super('PrimordialDevide') + this.nextScene = 'BreatheLife' + } + + /** + * 创建场景 + * 设置背景颜色,添加用户交互监听和自动切换计时器 + */ + create() { + // 设置场景背景颜色为深灰色 + this.cameras.main.setBackgroundColor('#333333') + + // 设置动画播放状态为 false,避免多次触发 + this.animationPlaying = false + + // 监听鼠标点击事件,点击后执行场景过渡动画 + this.input.on('pointerdown', () => { + // 获取点击位置的坐标 + const { x, y } = this.input.activePointer + this.transitionToScene(x, y) + }) + + // 监听键盘按键事件,按键后执行场景过渡动画 + this.input.keyboard.on('keydown', () => { + this.transitionToScene() + }) + + // 设置1秒后自动执行场景过渡动画 + this.time.delayedCall(1000, () => { + this.transitionToScene() + }) + } + + /** + * 执行到下一个场景的过渡动画 + * + * 动画流程: + * 1. 从屏幕中心向两侧延伸一条白色直线(横向扩展) + * 2. 横向扩展完成后,直线向上下扩展铺满整个屏幕(纵向扩展) + * 3. 纵向扩展完成后,切换到MenuScene场景 + */ + transitionToScene(startX,startY) { + // 如果动画正在播放,直接返回 + if (this.animationPlaying) { + return + } + // 设置动画播放状态为 true + this.animationPlaying = true + + const graphics = this.add.graphics() // 创建图形对象,用于绘制过渡动画 + + const centerX = startX || this.cameras.main.centerX // 获取屏幕中心点的X坐标 + const centerY = startY || this.cameras.main.centerY // 获取屏幕中心点的Y坐标 + + const lineHeight = 2 // 初始线条高度(2像素) + + const maxWidth = this.cameras.main.width // 屏幕最大宽度,用于横向扩展的目标值 + + graphics.fillStyle(0xffffff, 1) // 设置初始填充颜色为白色,透明度为1 + + // 创建线条对象,用于控制横向扩展动画的属性 + const line = { + width: 0, // 初始宽度为0(仅中心点) + x: centerX // 初始X坐标为屏幕中心 + } + + // 创建横向扩展动画 + this.tweens.add({ + targets: line, // 动画目标对象 + width: maxWidth, // 目标宽度为屏幕宽度 + x: 0, // 目标X坐标为屏幕左侧 + duration: 300, // 动画持续时间(300毫秒) + ease: 'Power2.easeOut', // 动画缓动函数 + onUpdate: function() { // 动画更新回调函数 + graphics.clear() // 清除之前的绘制 + graphics.fillStyle(0x999999, 1) // 设置填充颜色 + // 绘制当前状态的线条 + graphics.fillRect(line.x, centerY - lineHeight / 2, line.width, lineHeight) + }, + onComplete: function() { // 动画完成回调函数 + // 横向动画完成后,调用纵向扩展动画方法 + this.expandVerticalAnimation(graphics, centerY, lineHeight, maxWidth) + }, + callbackScope: this // 回调函数的作用域(指向当前场景实例) + }) + } + + /** + * 执行纵向扩展动画 + * + * @param {Phaser.GameObjects.Graphics} graphics - 图形对象,用于绘制动画 + * @param {number} centerY - 屏幕中心点的Y坐标 + * @param {number} lineHeight - 初始线条高度 + * @param {number} maxWidth - 屏幕宽度,用于绘制横向铺满的矩形 + */ + expandVerticalAnimation(graphics, centerY, lineHeight, maxWidth) { + // 创建纵向线条对象,用于控制纵向扩展动画的属性 + const verticalLine = { + height: lineHeight, // 初始高度为线条高度 + y: centerY - lineHeight / 2 // 初始Y坐标为屏幕中心减去线条高度的一半 + } + + // 屏幕最大高度,用于纵向扩展的目标值 + const maxHeight = this.cameras.main.height + + // 创建纵向扩展动画 + this.tweens.add({ + targets: verticalLine, // 动画目标对象 + height: maxHeight, // 目标高度为屏幕高度 + y: 0, // 目标Y坐标为屏幕顶部 + duration: 300, // 动画持续时间 + ease: 'Power2.easeOut', // 动画缓动函数 + onUpdate: function() { // 动画更新回调函数 + graphics.clear() // 清除之前的绘制 + graphics.fillStyle(0x999999, 1) // 设置填充颜色 + // 绘制当前状态的矩形(已横向铺满,正在纵向扩展) + graphics.fillRect(0, verticalLine.y, maxWidth, verticalLine.height) + }, + onComplete: function() { // 动画完成回调函数 + // 纵向动画完成后,切换到指定场景 + // 加上内置过渡动画 + this.cameras.main.fadeOut(300, 0, 0, 0); + this.cameras.main.once('camerafadeoutcomplete', () => { + // 切换到游戏场景 + this.scene.start(this.nextScene); + }); + }, + callbackScope: this // 回调函数的作用域(指向当前场景实例) + }) + } +} \ No newline at end of file