本文目录导读:

经典「躲避星星」小游戏(核心:物理引擎与碰撞检测)
这是 Phaser 官方教程的升级版,适合快速上手。
游戏玩法:控制角色移动,收集星星得分,碰到炸弹则游戏结束。
// 场景配置
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0 }, // 无重力,用于俯视游戏
debug: false
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
let player;
let stars;
let bombs;
let cursors;
let score = 0;
let scoreText;
// 资源加载
function preload() {
this.load.image('sky', 'assets/sky.png');
this.load.image('star', 'assets/star.png');
this.load.image('bomb', 'assets/bomb.png');
this.load.spritesheet('dude', 'assets/dude.png', { frameWidth: 32, frameHeight: 48 });
}
// 游戏初始化
function create() {
// 设置背景
this.add.image(400, 300, 'sky');
// 创建玩家(带动画)
player = this.physics.add.sprite(100, 450, 'dude');
player.setBounce(0.2);
player.setCollideWorldBounds(true);
// 动画
this.anims.create({
key: 'left',
frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
frameRate: 10,
repeat: -1
});
this.anims.create({
key: 'turn',
frames: [{ key: 'dude', frame: 4 }],
frameRate: 20
});
this.anims.create({
key: 'right',
frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }),
frameRate: 10,
repeat: -1
});
// 创建星星组(12个)
stars = this.physics.add.group({
key: 'star',
repeat: 11,
setXY: { x: 12, y: 0, stepX: 70 }
});
stars.children.iterate((child) => {
child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});
// 创建炸弹组(后面动态生成)
bombs = this.physics.add.group();
// 碰撞检测
this.physics.add.collider(player, stars);
this.physics.add.collider(player, bombs);
this.physics.add.collider(stars, bombs);
// 重叠检测(收集星星)
this.physics.add.overlap(player, stars, collectStar, null, this);
// 输入控制
cursors = this.input.keyboard.createCursorKeys();
// 分数显示
scoreText = this.add.text(16, 16, '分数: 0', { fontSize: '32px', fill: '#fff' });
}
// 收集星星
function collectStar(player, star) {
star.disableBody(true, true);
score += 10;
scoreText.setText('分数: ' + score);
// 生成炸弹
if (stars.countActive(true) === 0) {
stars.children.iterate((child) => {
child.enableBody(true, child.x, 0, true, true);
});
let x = (player.x < 400) ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);
let bomb = bombs.create(x, 16, 'bomb');
bomb.setBounce(1);
bomb.setCollideWorldBounds(true);
bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
}
}
// 游戏主循环
function update() {
// 玩家移动控制
if (cursors.left.isDown) {
player.setVelocityX(-160);
player.anims.play('left', true);
} else if (cursors.right.isDown) {
player.setVelocityX(160);
player.anims.play('right', true);
} else {
player.setVelocityX(0);
player.anims.play('turn');
}
if (cursors.up.isDown && player.body.touching.down) {
player.setVelocityY(-330);
}
// 游戏结束检测
this.physics.add.overlap(player, bombs, () => {
this.physics.pause();
player.setTint(0xff0000);
player.anims.play('turn');
this.add.text(300, 300, '游戏结束!', { fontSize: '64px', fill: '#ff0000' });
this.add.text(280, 380, '点击重新开始', { fontSize: '32px', fill: '#ffffff' });
this.input.once('pointerdown', () => {
this.scene.restart();
});
});
}
new Phaser.Game(config);
塔防游戏 AI(核心:路径规划与状态切换)
展示敌人如何按照路径点移动,并具有不同的攻击状态。
class Enemy extends Phaser.Physics.Arcade.Sprite {
constructor(scene, path) {
super(scene, path[0].x, path[0].y, 'enemy');
this.path = path;
this.pathIndex = 0;
this.speed = 100;
this.hp = 100;
this.state = 'moving';
scene.add.existing(this);
scene.physics.add.existing(this);
}
update() {
if (this.state === 'dead') return;
// 状态机逻辑
switch (this.state) {
case 'moving':
this.moveAlongPath();
this.checkRangeForAttack();
break;
case 'attacking':
this.attackTarget();
break;
case 'retreating':
this.moveBackToPath();
break;
}
}
// 路径移动
moveAlongPath() {
if (this.pathIndex >= this.path.length) {
this.state = 'attacking'; // 到达终点
return;
}
const targetPoint = this.path[this.pathIndex];
const distanceToPoint = Phaser.Math.Distance.Between(this.x, this.y, targetPoint.x, targetPoint.y);
if (distanceToPoint < 5) {
this.pathIndex++;
} else {
this.scene.physics.moveTo(this, targetPoint.x, targetPoint.y, this.speed);
}
}
// 检测攻击范围 (假设有炮台)
checkRangeForAttack() {
const tower = this.scene.tower;
if (tower && Phaser.Math.Distance.Between(this.x, this.y, tower.x, tower.y) < 150) {
this.state = 'retreating';
this.setTexture('enemy_angry'); // 切换表情
}
}
// 撤退逻辑
moveBackToPath() {
if (this.pathIndex === 0) {
this.state = 'moving';
this.setTexture('enemy');
return;
}
const backPoint = this.path[this.pathIndex - 1];
this.scene.physics.moveTo(this, backPoint.x, backPoint.y, this.speed * 1.2);
// 回到上一个点就继续前进
if (Phaser.Math.Distance.Between(this.x, this.y, backPoint.x, backPoint.y) < 10) {
this.state = 'moving';
}
}
}
// 在场景中使用
class GameScene extends Phaser.Scene {
constructor() {
super('GameScene');
this.path = [
{ x: 50, y: 100 },
{ x: 200, y: 100 },
{ x: 200, y: 300 },
{ x: 600, y: 300 }
];
}
create() {
// 绘制路径 (用于调试)
this.path.forEach((point, index) => {
if (index > 0) {
this.add.line(0, 0, this.path[index-1].x, this.path[index-1].y, point.x, point.y, 0xffffff).setOrigin(0);
}
});
// 创建测试塔
this.tower = this.add.sprite(400, 300, 'tower');
// 生成敌人
this.time.addEvent({
delay: 2000,
repeat: 3,
callback: () => {
new Enemy(this, this.path);
}
});
}
update() {
this.children.list.forEach(child => {
if (child instanceof Enemy) child.update();
});
}
}
RPG 对话系统(核心:数据驱动 UI)
当你需要一个可复用的对话系统并更新 UI 面板时。
class DialogueScene extends Phaser.Scene {
constructor() {
super('DialogueScene');
this.dialogues = [
{ speaker: '老人', text: '年轻人,你来了。', face: 'oldman' },
{ speaker: '玩家', text: '请问你知道宝藏在哪吗?', face: 'player' },
{ speaker: '老人', text: '穿过黑暗森林,你会找到答案。', face: 'oldman' },
{ speaker: '玩家', text: '谢谢!', face: 'player' }
];
this.currentIndex = 0;
}
create() {
// 半透明背景
this.add.rectangle(400, 300, 800, 600, 0x000000, 0.5);
// 对话框UI
this.dialogueBox = this.add.container(0, 0);
const boxBg = this.add.graphics();
boxBg.fillStyle(0xffffff, 0.9);
boxBg.fillRoundedRect(50, 400, 700, 150, 20);
this.speakerText = this.add.text(80, 420, '', { fontSize: '28px', fill: '#3d3d3d', fontStyle: 'bold' });
this.text1 = this.add.text(80, 460, '', { fontSize: '24px', fill: '#000000', wordWrap: { width: 640 } });
this.dialogueBox.add([boxBg, this.speakerText, this.text1]);
// 下一步按钮
this.nextButton = this.add.text(650, 520, '▼', { fontSize: '32px', fill: '#007acc' })
.setInteractive()
.on('pointerdown', () => this.nextDialogue());
// 首次对话
this.showDialogue(0);
}
showDialogue(index) {
if (index >= this.dialogues.length) {
this.closeDialogue();
return;
}
const data = this.dialogues[index];
this.speakerText.setText(data.speaker + ':');
this.text1.setText(data.text);
}
nextDialogue() {
this.currentIndex++;
this.showDialogue(this.currentIndex);
}
closeDialogue() {
console.log('对话结束');
this.scene.stop();
this.scene.resume('GameScene');
}
}
// 在游戏场景中触发
// this.scene.launch('DialogueScene'); // 启动对话
性能优化与调试建议
对于以上案例,如果遇到性能问题,可以这样优化:
对象池重用(用于案例一)
// 创建对象池
this.bombs = this.physics.add.group({
maxSize: 10,
// 当对象不存在时自动创建
defaultKey: 'bomb',
defaultFrame: undefined
});
// 从池中获取
let bomb = this.bombs.get(player.x, player.y, 'bomb');
if (bomb) {
bomb.setActive(true).setVisible(true);
bomb.setVelocity(100, -100);
}
调试工具(用于案例三)
// 在 create 中启用 this.physics.world.createDebugGraphic(); this.physics.world.debugGraphic.setVisible(true); // 路径可视化 this.add.graphics().lineStyle(2, 0xff0000, 1).strokePoints(this.path.map(p => new Phaser.Geom.Point(p.x, p.y)));
帧率显示
this.time.addEvent({
delay: 1000,
loop: true,
callback: () => {
const fps = this.game.loop.actualFps.toFixed(0);
this.fpsText.setText('FPS: ' + fps);
}
});
如何运行这些案例?
-
本地开发:使用
phaser3-project-template或手动引入 CDN:<script src="https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser.min.js"></script>
-
在线调试:将案例代码复制到 Phaser 官方示例编辑器 中。
-
资源替换:案例中的图片资源(
sky.png、star.png)可以在 Kenney 资源库 免费获取。
需要我针对某个案例进行深度扩展(如增加多人联机、WebGL 着色器特效等),请告诉我。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播