Phaser 基础概念 #
游戏实例 #
创建游戏 #
Phaser 游戏的核心是 Phaser.Game 实例:
javascript
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
scene: GameScene
};
const game = new Phaser.Game(config);
游戏实例属性 #
javascript
game.canvas // Canvas 元素
game.renderer // 渲染器实例
game.scene // 场景管理器
game.loop // 游戏循环
game.scale // 缩放管理器
game.input // 输入管理器
game.sound // 音频管理器
game.textures // 纹理管理器
game.cache // 缓存管理器
游戏循环 #
text
┌─────────────────────────────────────────────────────────────┐
│ 游戏循环 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌──────────┐ │ │
│ │ │ 开始帧 │ │ │
│ │ └────┬─────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │ 处理输入 │ │ │
│ │ └────┬─────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │ 更新逻辑 │ ◄─── scene.update() │ │
│ │ └────┬─────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │ 渲染画面 │ │ │
│ │ └────┬─────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ │ │ 结束帧 │ │ │
│ │ └────┬─────┘ │ │
│ │ │ │ │
│ │ └──────────────┐ │ │
│ │ │ │ │
│ └────────────────────────┼───────────────────────┘ │
│ │ │
│ └─────► 下一帧 │
│ │
└─────────────────────────────────────────────────────────────┘
场景系统 #
场景生命周期 #
javascript
class GameScene extends Phaser.Scene {
constructor() {
super({ key: 'GameScene' });
}
init(data) {
// 1. 初始化
// 接收场景启动时传递的数据
console.log('Received data:', data);
this.score = data.score || 0;
}
preload() {
// 2. 加载资源
// 在 create 之前完成所有资源加载
this.load.image('sky', 'assets/sky.png');
this.load.image('ground', 'assets/platform.png');
this.load.image('star', 'assets/star.png');
}
create() {
// 3. 创建游戏对象
// 资源加载完成后调用
this.add.image(400, 300, 'sky');
this.player = this.physics.add.sprite(100, 450, 'dude');
}
update(time, delta) {
// 4. 游戏循环
// 每帧调用,处理游戏逻辑
if (this.cursors.left.isDown) {
this.player.setVelocityX(-160);
}
}
shutdown() {
// 5. 场景关闭
// 清理资源、事件监听器
this.events.off('customEvent');
}
}
场景配置 #
javascript
const sceneConfig = {
key: 'GameScene', // 场景唯一标识
active: false, // 是否立即激活
visible: true, // 是否可见
pack: { // 预加载资源
files: [
{ type: 'image', key: 'loading', url: 'loading.png' }
]
},
mapAdd: { // 注入场景的属性
score: 0
},
map: { // 映射插件
game: 'game'
}
};
class GameScene extends Phaser.Scene {
constructor() {
super(sceneConfig);
}
}
场景管理 #
javascript
// 启动场景
this.scene.start('GameScene', { level: 1 });
// 暂停场景
this.scene.pause('GameScene');
// 恢复场景
this.scene.resume('GameScene');
// 停止场景
this.scene.stop('GameScene');
// 休眠场景(暂停但不销毁)
this.scene.sleep('GameScene');
// 唤醒场景
this.scene.wake('GameScene');
// 切换场景
this.scene.switch('MenuScene');
// 并行运行场景
this.scene.launch('UIScene');
// 移除场景
this.scene.remove('GameScene');
// 获取场景实例
const gameScene = this.scene.get('GameScene');
多场景协作 #
javascript
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
scene: [BootScene, PreloadScene, MenuScene, GameScene, UIScene]
};
// BootScene.js
class BootScene extends Phaser.Scene {
preload() {
this.load.image('logo', 'assets/logo.png');
}
create() {
this.scene.start('PreloadScene');
}
}
// GameScene.js - 游戏主场景
class GameScene extends Phaser.Scene {
create() {
// 启动 UI 场景
this.scene.launch('UIScene');
// 与 UI 场景通信
this.events.emit('scoreUpdate', this.score);
}
}
// UIScene.js - UI 覆盖层
class UIScene extends Phaser.Scene {
create() {
// 监听游戏场景事件
const gameScene = this.scene.get('GameScene');
gameScene.events.on('scoreUpdate', (score) => {
this.scoreText.setText('Score: ' + score);
});
}
}
游戏对象 #
常见游戏对象类型 #
text
┌─────────────────────────────────────────────────────────────┐
│ 游戏对象类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 基础对象: │
│ ├── Image - 静态图像 │
│ ├── Sprite - 动画精灵 │
│ ├── Text - 文本 │
│ ├── TileSprite - 平铺精灵 │
│ └── RenderTexture - 渲染纹理 │
│ │
│ 图形对象: │
│ ├── Graphics - 矢量图形 │
│ ├── Rectangle - 矩形 │
│ ├── Circle - 圆形 │
│ ├── Ellipse - 椭圆 │
│ ├── Triangle - 三角形 │
│ ├── Line - 线条 │
│ └── Polygon - 多边形 │
│ │
│ 容器对象: │
│ ├── Container - 容器 │
│ ├── Group - 分组 │
│ └── Layer - 图层 │
│ │
│ 特殊对象: │
│ ├── ParticleEmitter - 粒子发射器 │
│ ├── Light - 光源 │
│ ├── Zone - 区域 │
│ └── BitmapText - 位图文本 │
│ │
└─────────────────────────────────────────────────────────────┘
创建游戏对象 #
javascript
// 图像
const image = this.add.image(400, 300, 'sky');
// 精灵
const sprite = this.add.sprite(100, 100, 'player');
// 文本
const text = this.add.text(400, 300, 'Hello', {
fontSize: '32px',
fill: '#fff'
});
// 矩形
const rect = this.add.rectangle(400, 300, 200, 100, 0xff0000);
// 圆形
const circle = this.add.circle(400, 300, 50, 0x00ff00);
// 容器
const container = this.add.container(400, 300);
container.add([image, text]);
游戏对象属性 #
javascript
// 位置
sprite.x = 100;
sprite.y = 200;
sprite.setPosition(100, 200);
// 大小
sprite.width = 64;
sprite.height = 64;
sprite.setSize(64, 64);
sprite.setScale(2, 2); // 缩放
sprite.scaleX = 2;
sprite.scaleY = 2;
// 旋转
sprite.rotation = Math.PI / 4; // 弧度
sprite.angle = 45; // 角度
// 原点
sprite.setOrigin(0.5, 0.5); // 中心
sprite.setOrigin(0, 0); // 左上角
sprite.setOrigin(1, 1); // 右下角
// 透明度
sprite.alpha = 0.5;
sprite.setAlpha(0.5);
// 可见性
sprite.visible = true;
sprite.setVisible(true);
// 深度(层级)
sprite.depth = 10;
sprite.setDepth(10);
// 翻转
sprite.setFlipX(true);
sprite.setFlipY(true);
// 混合模式
sprite.setBlendMode(Phaser.BlendModes.ADD);
// 着色
sprite.setTint(0xff0000);
sprite.clearTint();
游戏对象方法 #
javascript
// 销毁
sprite.destroy();
// 复制
const clone = Phaser.Utils.Objects.Clone(sprite);
// 获取边界
const bounds = sprite.getBounds();
// 获取中心点
const center = sprite.getCenter();
// 获取顶部
const top = sprite.getTopCenter();
// 世界坐标转换
const worldPoint = sprite.getWorldTransformMatrix();
// 检查点是否在对象内
const isInside = sprite.getBounds().contains(x, y);
资源加载 #
加载器基础 #
javascript
preload() {
// 加载图像
this.load.image('sky', 'assets/sky.png');
// 加载精灵表
this.load.spritesheet('dude', 'assets/dude.png', {
frameWidth: 32,
frameHeight: 48
});
// 加载音频
this.load.audio('bgm', 'assets/bgm.mp3');
// 加载 JSON
this.load.json('data', 'assets/data.json');
// 加载文本
this.load.text('dialog', 'assets/dialog.txt');
// 加载 XML
this.load.xml('data', 'assets/data.xml');
// 加载 SVG
this.load.svg('icon', 'assets/icon.svg');
}
加载事件 #
javascript
preload() {
// 加载进度
this.load.on('progress', (value) => {
console.log('Loading: ' + Math.round(value * 100) + '%');
progressBar.setScale(value, 1);
});
// 加载完成
this.load.on('complete', () => {
console.log('All assets loaded!');
this.scene.start('MenuScene');
});
// 单个文件加载完成
this.load.on('filecomplete', (key, type, data) => {
console.log('Loaded:', key);
});
// 加载错误
this.load.on('loaderror', (file) => {
console.error('Error loading:', file.key);
});
// 开始加载
this.load.on('start', () => {
console.log('Loading started');
});
}
制作加载界面 #
javascript
class PreloadScene extends Phaser.Scene {
constructor() {
super({ key: 'PreloadScene' });
}
preload() {
// 创建加载界面
this.createLoadingUI();
// 加载资源
this.load.image('sky', 'assets/sky.png');
this.load.image('ground', 'assets/platform.png');
this.load.spritesheet('dude', 'assets/dude.png', {
frameWidth: 32,
frameHeight: 48
});
}
createLoadingUI() {
const width = this.cameras.main.width;
const height = this.cameras.main.height;
// 进度条背景
const progressBox = this.add.graphics();
progressBox.fillStyle(0x222222, 0.8);
progressBox.fillRect(width / 2 - 160, height / 2 - 25, 320, 50);
// 进度条
const progressBar = this.add.graphics();
// 加载文字
const loadingText = this.add.text(width / 2, height / 2 - 50, 'Loading...', {
fontSize: '20px',
fill: '#fff'
}).setOrigin(0.5);
// 百分比文字
const percentText = this.add.text(width / 2, height / 2, '0%', {
fontSize: '18px',
fill: '#fff'
}).setOrigin(0.5);
// 监听加载进度
this.load.on('progress', (value) => {
percentText.setText(Math.round(value * 100) + '%');
progressBar.clear();
progressBar.fillStyle(0x00ff00, 1);
progressBar.fillRect(width / 2 - 150, height / 2 - 15, 300 * value, 30);
});
this.load.on('complete', () => {
progressBar.destroy();
progressBox.destroy();
loadingText.destroy();
percentText.destroy();
});
}
create() {
this.scene.start('MenuScene');
}
}
加载多文件 #
javascript
// 批量加载图像
this.load.image([
{ key: 'sky', url: 'assets/sky.png' },
{ key: 'ground', url: 'assets/platform.png' },
{ key: 'star', url: 'assets/star.png' },
{ key: 'bomb', url: 'assets/bomb.png' }
]);
// 使用 atlas
this.load.atlas('game', 'assets/game.png', 'assets/game.json');
// 加载瓦片地图
this.load.tilemapTiledJSON('map', 'assets/map.json');
资源缓存 #
javascript
// 获取缓存资源
const texture = this.textures.get('player');
const json = this.cache.json.get('data');
const audio = this.cache.audio.get('bgm');
// 检查资源是否存在
if (this.textures.exists('player')) {
// 资源存在
}
// 移除缓存
this.textures.remove('player');
this.cache.json.remove('data');
坐标系统 #
世界坐标与屏幕坐标 #
text
┌─────────────────────────────────────────────────────────────┐
│ 坐标系统 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 屏幕坐标 (0, 0) │
│ │ │
│ │ ┌─────────────────────┐ │
│ │ │ │ │
│ │ │ 世界坐标 │ │
│ │ │ (相机偏移) │ │
│ │ │ │ │
│ │ │ ● (100, 100) │ │
│ │ │ │ │
│ │ └─────────────────────┘ │
│ │ │
│ │
└─────────────────────────────────────────────────────────────┘
坐标转换 #
javascript
// 世界坐标转屏幕坐标
const screenPoint = this.cameras.main.worldView.contains(x, y);
// 屏幕坐标转世界坐标
const worldPoint = this.cameras.main.getWorldPoint(pointer.x, pointer.y);
// 相机滚动
this.cameras.main.scrollX = 100;
this.cameras.main.scrollY = 50;
原点与锚点 #
text
┌─────────────────────────────────────────────────────────────┐
│ 原点位置 │
├─────────────────────────────────────────────────────────────┤
│ │
│ setOrigin(0, 0) setOrigin(0.5, 0.5) setOrigin(1, 1)│
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │● │ │ │ │ ●│ │
│ │ │ │ ● │ │ │ │
│ │ │ │ │ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ 左上角 中心 右下角 │
│ │
└─────────────────────────────────────────────────────────────┘
javascript
// 设置原点
sprite.setOrigin(0, 0); // 左上角
sprite.setOrigin(0.5, 0.5); // 中心(默认)
sprite.setOrigin(1, 1); // 右下角
sprite.setOrigin(0.5, 1); // 底部中心
// 设置原点并更新位置
sprite.setOrigin(0.5, 0.5);
时间与计时器 #
游戏时间 #
javascript
// 获取游戏时间
const time = this.time.now; // 游戏开始后的毫秒数
const delta = this.game.loop.delta; // 帧间隔(毫秒)
// update 方法中的时间
update(time, delta) {
// time: 当前时间戳
// delta: 距离上一帧的时间
}
计时器 #
javascript
// 延迟执行
this.time.delayedCall(1000, () => {
console.log('1秒后执行');
});
// 带参数的延迟执行
this.time.delayedCall(1000, (message) => {
console.log(message);
}, ['Hello!']);
// 重复执行
this.time.addEvent({
delay: 1000,
callback: () => {
console.log('每秒执行一次');
},
loop: true
});
// 有限次数重复
this.time.addEvent({
delay: 1000,
callback: () => {
console.log('执行');
},
repeat: 4 // 执行5次(初始1次 + 重复4次)
});
// 保存计时器引用以便清除
const timer = this.time.addEvent({
delay: 1000,
callback: updateScore,
loop: true
});
// 清除计时器
timer.remove();
// 暂停/恢复计时器
timer.paused = true;
timer.paused = false;
计时器事件 #
javascript
const timerEvent = this.time.addEvent({
delay: 2000,
callback: onEvent,
callbackScope: this,
loop: true
});
// 获取计时器信息
console.log(timerEvent.elapsed); // 已过时间
console.log(timerEvent.progress); // 进度 (0-1)
console.log(timerEvent.repeatCount); // 剩余重复次数
// 手动触发
timerEvent.dispatch();
下一步 #
现在你已经掌握了 Phaser 的基础概念,接下来学习 场景系统,深入了解场景的管理与通信!
最后更新:2026-03-29