Phaser 游戏组 #
游戏组概述 #
Phaser 提供了 Group 和 Container 两种方式来管理多个游戏对象。
text
┌─────────────────────────────────────────────────────────────┐
│ 游戏组对比 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Group │
│ ├── 轻量级 │
│ ├── 不影响子对象位置 │
│ ├── 适合批量操作 │
│ └── 性能更好 │
│ │
│ Container │
│ ├── 有自己的位置和变换 │
│ ├── 子对象相对容器定位 │
│ ├── 适合 UI 组件 │
│ └── 支持嵌套 │
│ │
└─────────────────────────────────────────────────────────────┘
Group 基础 #
创建 Group #
javascript
create() {
this.enemies = this.add.group();
this.coins = this.physics.add.group();
this.platforms = this.physics.add.staticGroup();
}
添加对象 #
javascript
const group = this.add.group();
const sprite = this.add.sprite(100, 100, 'enemy');
group.add(sprite);
group.addMultiple([sprite1, sprite2, sprite3]);
const enemy = group.create(200, 100, 'enemy');
const enemies = group.createMultiple({
key: 'enemy',
repeat: 10,
setXY: { x: 100, y: 100, stepX: 70 }
});
const enemies = group.createMultiple([
{ key: 'enemy', x: 100, y: 100 },
{ key: 'enemy', x: 200, y: 100 },
{ key: 'enemy', x: 300, y: 100 }
]);
移除对象 #
javascript
group.remove(sprite);
group.remove(sprite, true);
group.remove(sprite, true, true);
group.clear(true, true);
group.removeAll();
group.destroy();
访问对象 #
javascript
const children = group.getChildren();
const first = group.getFirst();
const firstAlive = group.getFirstAlive();
const firstDead = group.getFirstDead();
const count = group.getLength();
const countAlive = group.countActive(true);
const countDead = group.countActive(false);
const size = group.getSize();
const random = group.getRandom();
遍历对象 #
javascript
group.children.iterate((child) => {
child.setTint(0xff0000);
});
group.children.each((child) => {
child.x += 10;
});
const visible = group.getChildren().filter(child => child.visible);
const found = group.getChildren().find(child => child.x > 400);
批量操作 #
javascript
group.setAlpha(0.5);
group.setVisible(true);
group.setTint(0xff0000);
group.setDepth(10);
group.setOrigin(0.5, 0.5);
group.setProperty('x', 100);
group.setXY(100, 100);
group.incXY(10, 10);
group.shiftPosition(100, 100);
group.rotate(45);
group.scale(2, 2);
物理组 #
javascript
const group = this.physics.add.group({
key: 'enemy',
repeat: 10,
setXY: { x: 100, y: 100, stepX: 70 },
bounceX: 1,
bounceY: 1,
collideWorldBounds: true,
velocityX: 100,
velocityY: 50
});
group.setVelocity(100, 50);
group.setVelocityX(100);
group.setVelocityY(50);
this.physics.add.collider(group, this.platforms);
this.physics.add.overlap(this.player, group, this.hitEnemy, null, this);
静态组 #
javascript
const group = this.physics.add.staticGroup();
group.create(400, 568, 'ground').setScale(2).refreshBody();
group.create(600, 400, 'ground');
group.create(50, 250, 'ground');
group.create(750, 220, 'ground');
const ground = group.create(400, 568, 'ground');
ground.setScale(2);
ground.refreshBody();
对象池 #
javascript
class Bullet extends Phaser.Physics.Arcade.Sprite {
constructor(scene, x, y) {
super(scene, x, y, 'bullet');
}
fire(x, y, velocityX, velocityY) {
this.setPosition(x, y);
this.setActive(true);
this.setVisible(true);
this.setVelocity(velocityX, velocityY);
}
deactivate() {
this.setActive(false);
this.setVisible(false);
this.setVelocity(0, 0);
}
}
create() {
this.bullets = this.physics.add.group({
classType: Bullet,
maxSize: 30,
runChildUpdate: true
});
}
fireBullet() {
const bullet = this.bullets.get();
if (bullet) {
bullet.fire(this.player.x, this.player.y, 0, -300);
}
}
update() {
this.bullets.children.iterate((bullet) => {
if (bullet && bullet.active && bullet.y < 0) {
bullet.deactivate();
}
});
}
Group 配置 #
创建配置 #
javascript
const group = this.add.group({
classType: Phaser.GameObjects.Sprite,
name: 'enemies',
active: true,
maxSize: -1,
runChildUpdate: false,
createCallback: (child) => {
console.log('Child added:', child);
},
removeCallback: (child) => {
console.log('Child removed:', child);
}
});
创建多个对象配置 #
javascript
const group = this.add.group();
group.createMultiple({
key: 'enemy',
frame: [0, 1, 2, 3],
repeat: 5,
randomKey: false,
randomFrame: true,
yoyo: false,
quantity: 2,
setXY: {
x: 100,
y: 100,
stepX: 70,
stepY: 50
},
setRotation: {
value: 0,
step: 0.1
},
setScale: {
x: 1,
y: 1,
stepX: 0.1,
stepY: 0.1
},
setAlpha: {
value: 1,
step: -0.1
},
hitArea: new Phaser.Geom.Rectangle(0, 0, 32, 32),
hitAreaCallback: Phaser.Geom.Rectangle.Contains
});
Container #
创建 Container #
javascript
const container = this.add.container(x, y);
const container = this.add.container(400, 300);
添加对象 #
javascript
const container = this.add.container(400, 300);
const image = this.add.image(0, 0, 'player');
const text = this.add.text(0, 50, 'Player 1', { fontSize: '16px' });
container.add(image);
container.add(text);
container.add([image, text]);
container.addAt(text, 0);
移除对象 #
javascript
container.remove(image);
container.remove(image, true);
container.removeAt(0);
container.removeBetween(0, 5);
container.removeAll();
container.destroy();
访问对象 #
javascript
const children = container.list;
const first = container.first;
const last = container.last;
const count = container.length;
const at = container.getAt(0);
const index = container.getIndex(image);
遍历对象 #
javascript
container.each((child) => {
child.setAlpha(0.5);
});
container.iterate('sprite', (child) => {
child.setTint(0xff0000);
});
container.contains(sprite);
Container 属性 #
javascript
container.x = 100;
container.y = 200;
container.setPosition(100, 200);
container.rotation = Math.PI / 4;
container.angle = 45;
container.scaleX = 2;
container.scaleY = 2;
container.setScale(2, 2);
container.alpha = 0.5;
container.visible = true;
container.depth = 10;
container.setDepth(10);
container.setSize(200, 150);
Container 嵌套 #
javascript
const outerContainer = this.add.container(400, 300);
const innerContainer = this.add.container(0, 0);
const image = this.add.image(0, 0, 'player');
innerContainer.add(image);
outerContainer.add(innerContainer);
Container 交互 #
javascript
const container = this.add.container(400, 300);
const image = this.add.image(0, 0, 'button');
const text = this.add.text(0, 0, 'Click Me', { fontSize: '24px' }).setOrigin(0.5);
container.add([image, text]);
container.setSize(image.width, image.height);
container.setInteractive();
container.on('pointerdown', () => {
console.log('Container clicked');
});
container.on('pointerover', () => {
container.setAlpha(0.8);
});
container.on('pointerout', () => {
container.setAlpha(1);
});
Container 物理 #
javascript
const container = this.add.container(100, 100);
const image = this.add.image(0, 0, 'player');
container.add(image);
container.setSize(32, 48);
this.physics.world.enable(container);
container.body.setCollideWorldBounds(true);
container.body.setBounce(0.2);
this.physics.add.collider(container, this.platforms);
Group vs Container #
使用 Group 的场景 #
javascript
const enemies = this.add.group();
for (let i = 0; i < 10; i++) {
enemies.create(Phaser.Math.Between(50, 750), Phaser.Math.Between(50, 550), 'enemy');
}
this.physics.add.collider(enemies, this.platforms);
this.physics.add.overlap(this.player, enemies, this.hitEnemy, null, this);
enemies.children.iterate((enemy) => {
enemy.setTint(0xff0000);
});
使用 Container 的场景 #
javascript
const button = this.add.container(400, 300);
const background = this.add.image(0, 0, 'button-bg');
const text = this.add.text(0, 0, 'Click Me', { fontSize: '24px' }).setOrigin(0.5);
const icon = this.add.image(-50, 0, 'icon');
button.add([background, text, icon]);
button.setSize(background.width, background.height);
button.setInteractive();
this.tweens.add({
targets: button,
y: 250,
duration: 1000,
yoyo: true,
repeat: -1
});
实用示例 #
敌人管理器 #
javascript
class EnemyManager {
constructor(scene) {
this.scene = scene;
this.enemies = scene.physics.add.group();
}
spawn(x, y, type = 'basic') {
const enemy = this.enemies.get(x, y, `enemy-${type}`);
if (!enemy) return null;
enemy.setActive(true);
enemy.setVisible(true);
enemy.setCollideWorldBounds(true);
switch (type) {
case 'fast':
enemy.setVelocity(Phaser.Math.Between(-200, 200), 0);
enemy.health = 50;
break;
case 'tank':
enemy.setVelocity(Phaser.Math.Between(-50, 50), 0);
enemy.health = 200;
break;
default:
enemy.setVelocity(Phaser.Math.Between(-100, 100), 0);
enemy.health = 100;
}
return enemy;
}
despawn(enemy) {
enemy.setActive(false);
enemy.setVisible(false);
enemy.setVelocity(0, 0);
enemy.setPosition(-100, -100);
}
update() {
this.enemies.children.iterate((enemy) => {
if (!enemy || !enemy.active) return;
if (enemy.health <= 0) {
this.despawn(enemy);
}
});
}
getGroup() {
return this.enemies;
}
}
UI 面板 #
javascript
class UIPanel extends Phaser.GameObjects.Container {
constructor(scene, x, y, width, height) {
super(scene, x, y);
this.width = width;
this.height = height;
this.background = scene.add.rectangle(0, 0, width, height, 0x333333, 0.9);
this.background.setStrokeStyle(2, 0xffffff);
this.title = scene.add.text(0, -height / 2 + 20, 'Panel Title', {
fontSize: '24px',
fill: '#ffffff'
}).setOrigin(0.5);
this.closeButton = scene.add.text(width / 2 - 20, -height / 2 + 20, 'X', {
fontSize: '20px',
fill: '#ffffff'
}).setOrigin(0.5).setInteractive();
this.closeButton.on('pointerdown', () => this.hide());
this.add([this.background, this.title, this.closeButton]);
scene.add.existing(this);
this.setAlpha(0);
this.setVisible(false);
}
show() {
this.setVisible(true);
this.scene.tweens.add({
targets: this,
alpha: 1,
duration: 200
});
}
hide() {
this.scene.tweens.add({
targets: this,
alpha: 0,
duration: 200,
onComplete: () => {
this.setVisible(false);
}
});
}
setTitle(text) {
this.title.setText(text);
}
}
下一步 #
现在你已经掌握了游戏组,接下来学习 着色器,了解如何使用 WebGL 着色器创建高级视觉效果!
最后更新:2026-03-29