效果展示
项目搭建
$ npm init vite@latest my-game --template vanilla-ts
$ cd my-game
$ npm i
$ npm install phaser
$ npm run dev
引入Phaser
import Phaser from 'phaser';
游戏项目初始化
import Phaser from 'phaser';
export default class SampleScene extends Phaser.Scene {
constructor() {
// super(config); config 场景特定的配置参数
super('SampleScene');
}
// 场景的初始化回调
init() {
console.log('init');
}
// 场景的预加载回调
preload() {
console.log('preload');
}
// 场景的创建回调
create() {
console.log('create');
}
/**
* 场景的更新回调
* @param time 当前时间
* @param delta 自最后一帧以来的增量时间(毫秒)。这是基于FPS速率的平滑和封顶值
*/
update(time: number, delta: number) {
super.update(time, delta);
}
}
const config: Phaser.Types.Core.GameConfig = {
// 渲染方式
type: Phaser.AUTO,
width: 800,
height: 600,
// 物理配置
physics: {
// 默认的物理系统
default: 'arcade', // arcade impact matter
// arcade物理配置
arcade: {
// 重力
gravity: {
y: 300},
debug: true
}
},
// 场景
scene: SampleScene
}
const game: Phaser.Game = new Phaser.Game(config);
console.log(game);
资源
初始化背景
export default class SampleScene extends Phaser.Scene {
/* ···CODE··· */
// 场景的预加载回调
preload() {
// 获取场景中背景资源的地址
const {
href: sky} = new URL(`assets/resources/sky.png`, import.meta.url);
// 加载资源
this.load.image('sky', sky);
}
// 场景的创建回调
create() {
// 向场景中添加资源
this.add.image(400, 300, 'sky');
}
/* ···CODE··· */
}
初始化平台
export default class SampleScene extends Phaser.Scene {
// 平台
private platforms: Phaser.Physics.Arcade.StaticGroup | undefined;
/* ···CODE··· */
// 场景的预加载回调
preload() {
// 获取场景中背景资源的地址
const {
href: sky} = new URL(`assets/resources/sky.png`, import.meta.url);
// 获取场景中平台资源的地址
const {
href: ground} = new URL(`assets/resources/platform.png`, import.meta.url);
// 加载资源
this.load.image('sky', sky);
this.load.image('ground', ground);
}
// 场景的创建回调
create() {
// 向场景中添加资源
this.add.image(400, 300, 'sky');
// 添加平台
this.platforms = this.physics.add.staticGroup(); // 静态物理对象组
// 放大平台平刷新平台刚体
this.platforms.create(400, 568, 'ground').setScale(2).refreshBody();
// 放置其他平台
this.platforms.create(600, 400, 'ground');
this.platforms.create(50, 250, 'ground');
this.platforms.create(750, 220, 'ground');
}
/* ···CODE··· */
}
初始化星星
export default class SampleScene extends Phaser.Scene {
// 平台
private platforms: Phaser.Physics.Arcade.StaticGroup | undefined;
// 星星
private stars: Phaser.Physics.Arcade.Group | undefined;
preload() {
/* ···CODE··· */
const {
href: star} = new URL(`assets/resources/star.png`, import.meta.url);
this.load.image('star', star);
/* ···CODE··· */
}
create() {
/* ···CODE··· */
// 添加星星
this.stars = this.physics.add.group({
key: 'star',
repeat: 9, // 添加个数 n+1
setXY: {
x: 20, y: 0, stepX: 84} // 每隔84放置一个偏移量为20的星星
});
// 随机弹力
this.stars.children.iterate((child) => {
child.body.gameObject.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});
// 添加碰撞体(星星与地面碰撞)
this.physics.add.collider(this.stars, this.platforms);
/* ···CODE··· */
}
/* ···CODE··· */
}
初始化玩家
配置玩家是否与世界边界碰撞
export default class SampleScene extends Phaser.Scene {
// 玩家
private player: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody | undefined;
preload() {
const {
href: dude} = new URL(`assets/resources/dude.png`, import.meta.url);
this.load.spritesheet('dude', dude, {
frameWidth: 32, frameHeight: 48});
}
create() {
// 添加玩家
this.player = this.physics.add.sprite(100, 450, 'dude');
this.player.setCollideWorldBounds(true); // 设置此实体是否与世界边界碰撞
}
}
配置玩家与地面碰撞
export default class SampleScene extends Phaser.Scene {
// 玩家
private player: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody | undefined;
preload() {
const {
href: dude} = new URL(`assets/resources/dude.png`, import.meta.url);
this.load.spritesheet('dude', dude, {
frameWidth: 32, frameHeight: 48});
}
create() {
// 添加玩家
this.player = this.physics.add.sprite(100, 450, 'dude');
this.player.setCollideWorldBounds(true); // 设置此实体是否与世界边界碰撞
this.physics.add.collider(this.player, this.platforms);
}
}
配置玩家动画
export default class SampleScene extends Phaser.Scene {
create() {
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
});
this.player!.anims.play('left', true);
// this.player!.anims.play('turn', true);
// this.player!.anims.play('right', true);
}
}
配置鼠标控制玩家并播放动画
export default class SampleScene extends Phaser.Scene {
// 键盘监听
private cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
create() {
// 添加方向控制
this.cursors = this.input.keyboard.createCursorKeys();
}
/**
* 场景的更新回调
* @param time 当前时间
* @param delta 自最后一帧以来的增量时间(毫秒)。这是基于FPS速率的平滑和封顶值
*/
update(time: number, delta: number) {
super.update(time, delta);
// 控制方向
if (this.cursors!.left.isDown) {
// 左
this.player!.setVelocityX(-160);
this.player!.anims.play('left', true);
} else if (this.cursors!.right.isDown) {
// 右
this.player!.setVelocityX(160);
this.player!.anims.play('right', true);
} else {
// 停止
this.player!.setVelocityX(0);
this.player!.anims.play('turn');
}
// 跳跃(不支持连跳)
if (this.cursors!.up.isDown && this.player!.body.touching.down) {
this.player!.setVelocityY(-330);
}
}
}
添加分数文本
export default class SampleScene extends Phaser.Scene {
// 分数
private score: number = 0;
// 文本
private scoreText: Phaser.GameObjects.Text | undefined;
create() {
// 添加文本
this.scoreText = this.add.text(16, 16, `Score: ${
this.score}`, {
fontSize: '32px'});
}
}
收集星星并加分 - 检查碰撞
export default class SampleScene extends Phaser.Scene {
create() {
// 检测玩家与星星重叠
this.physics.add.overlap(this.player, this.stars, this.collectStar, undefined, this);
}
// 收集星星
collectStar(player: Phaser.Types.Physics.Arcade.GameObjectWithBody, star: Phaser.Types.Physics.Arcade.GameObjectWithBody) {
star.body.gameObject.disableBody(true, true);
this.score += 10;
this.scoreText!.setText(`Score: ${
this.score}`);
}
}
当星星被收集完成后重新添加星星
export default class SampleScene extends Phaser.Scene {
// 收集星星
collectStar(player: Phaser.Types.Physics.Arcade.GameObjectWithBody, star: Phaser.Types.Physics.Arcade.GameObjectWithBody) {
// 星星数量为0时重新创建星星
if (this.stars!.countActive(true) === 0) {
this.stars!.children.iterate((child) => {
child.body.gameObject.enableBody(true, child.body.gameObject.x, 0, true, true);
});
}
}
}
添加敌人
玩家每收集完一次全部行星是添加一个自动弹动的小球作为敌人
export default class SampleScene extends Phaser.Scene {
// 敌人
private bombs: Phaser.Physics.Arcade.Group | undefined;
preload() {
const {
href: bomb} = new URL(`assets/resources/bomb.png`, import.meta.url);
this.load.image('bomb', bomb);
}
create() {
// 添加敌人
this.bombs = this.physics.add.group();
this.physics.add.collider(this.bombs, this.platforms);
}
// 收集星星
collectStar(player: Phaser.Types.Physics.Arcade.GameObjectWithBody, star: Phaser.Types.Physics.Arcade.GameObjectWithBody) {
star.body.gameObject.disableBody(true, true);
this.score += 10;
this.scoreText!.setText(`Score: ${
this.score}`);
// 星星数量为0时重新创建星星
if (this.stars!.countActive(true) === 0) {
this.stars!.children.iterate((child) => {
child.body.gameObject.enableBody(true, child.body.gameObject.x, 0, true, true);
});
// 向场景内添加一个敌人
const x = (player.body.gameObject.x < 400) ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);
const bomb = this.bombs!.create(x, 16, 'bomb');
bomb.setBounce(1); // 弹力
bomb.setCollideWorldBounds(true);
bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
}
}
}
添加碰撞敌人游戏结束
export default class SampleScene extends Phaser.Scene {
// 游戏是否结束
private gameOver: boolean = false;
create() {
// 添加敌人
this.bombs = this.physics.add.group();
this.physics.add.collider(this.bombs, this.platforms);
this.physics.add.collider(this.player, this.bombs, this.hitBomb, undefined, this);
}
update(time: number, delta: number) {
super.update(time, delta);
if (this.gameOver) {
this.scoreText!.setText(`游戏结束,Score: ${
this.score}`);
return;
}
}
// 碰撞敌人
hitBomb(player: Phaser.Types.Physics.Arcade.GameObjectWithBody, _bomb: Phaser.Types.Physics.Arcade.GameObjectWithBody) {
// 暂停物理引擎
this.physics.pause();
player.body.gameObject.setTint(0xff0000);
player.body.gameObject.anims.play('turn');
this.gameOver = true;
}
}
完整代码
import Phaser from 'phaser';
export default class SampleScene extends Phaser.Scene {
// 平台
private platforms: Phaser.Physics.Arcade.StaticGroup | undefined;
// 星星
private stars: Phaser.Physics.Arcade.Group | undefined;
// 玩家
private player: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody | undefined;
// 键盘监听
private cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
// 分数
private score: number = 0;
// 文本
private scoreText: Phaser.GameObjects.Text | undefined;
// 敌人
private bombs: Phaser.Physics.Arcade.Group | undefined;
// 游戏是否结束
private gameOver: boolean = false;
constructor() {
// super(config); config 场景特定的配置参数
super('SampleScene');
}
// 场景的初始化回调
init() {
console.log('init');
}
// 场景的预加载回调
preload() {
console.log('preload');
// 获取场景中背景资源的地址
const {
href: sky} = new URL(`assets/resources/sky.png`, import.meta.url);
// 获取场景中平台资源的地址
const {
href: ground} = new URL(`assets/resources/platform.png`, import.meta.url);
const {
href: star} = new URL(`assets/resources/star.png`, import.meta.url);
const {
href: dude} = new URL(`assets/resources/dude.png`, import.meta.url);
const {
href: bomb} = new URL(`assets/resources/bomb.png`, import.meta.url);
// 加载资源
this.load.image('sky', sky);
this.load.image('ground', ground);
this.load.image('star', star);
this.load.spritesheet('dude', dude, {
frameWidth: 32, frameHeight: 48});
this.load.image('bomb', bomb);
}
// 场景的创建回调
create() {
console.log('create');
// 向场景中添加资源
this.add.image(400, 300, 'sky');
// 添加平台
this.platforms = this.physics.add.staticGroup(); // 静态物理对象组
// 放大平台平刷新平台刚体
this.platforms.create(400, 568, 'ground').setScale(2).refreshBody();
// 放置其他平台
this.platforms.create(600, 400, 'ground');
this.platforms.create(50, 250, 'ground');
this.platforms.create(750, 220, 'ground');
// 添加星星
this.stars = this.physics.add.group({
key: 'star',
repeat: 9, // 添加个数 n+1
setXY: {
x: 20, y: 0, stepX: 84} // 每隔84放置一个偏移量为20的星星
});
// 随机弹力
this.stars.children.iterate((child) => {
child.body.gameObject.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});
// 添加碰撞体(星星与地面碰撞)
this.physics.add.collider(this.stars, this.platforms);
// 添加玩家
this.player = this.physics.add.sprite(50, 450, 'dude');
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
});
this.player.setCollideWorldBounds(true); // 设置此实体是否与世界边界碰撞
this.physics.add.collider(this.player, this.platforms);
// 添加方向控制
this.cursors = this.input.keyboard.createCursorKeys();
// 添加文本
this.scoreText = this.add.text(16, 16, `Score: ${
this.score}`, {
fontSize: '32px'});
// 检测玩家与星星重叠
this.physics.add.overlap(this.player, this.stars, this.collectStar, undefined, this);
// 添加敌人
this.bombs = this.physics.add.group();
this.physics.add.collider(this.bombs, this.platforms);
this.physics.add.collider(this.player, this.bombs, this.hitBomb, undefined, this);
}
/**
* 场景的更新回调
* @param time 当前时间
* @param delta 自最后一帧以来的增量时间(毫秒)。这是基于FPS速率的平滑和封顶值
*/
update(time: number, delta: number) {
super.update(time, delta);
if (this.gameOver) {
this.scoreText!.setText(`游戏结束,Score: ${
this.score}`);
return;
}
// 控制方向
if (this.cursors!.left.isDown) {
// 左
this.player!.setVelocityX(-160);
this.player!.anims.play('left', true);
} else if (this.cursors!.right.isDown) {
// 右
this.player!.setVelocityX(160);
this.player!.anims.play('right', true);
} else {
// 停止
this.player!.setVelocityX(0);
this.player!.anims.play('turn');
}
// 跳跃(不支持连跳)
if (this.cursors!.up.isDown && this.player!.body.touching.down) {
this.player!.setVelocityY(-330);
}
}
// 收集星星
collectStar(player: Phaser.Types.Physics.Arcade.GameObjectWithBody, star: Phaser.Types.Physics.Arcade.GameObjectWithBody) {
star.body.gameObject.disableBody(true, true);
this.score += 10;
this.scoreText!.setText(`Score: ${
this.score}`);
// 星星数量为0时重新创建星星
if (this.stars!.countActive(true) === 0) {
this.stars!.children.iterate((child) => {
child.body.gameObject.enableBody(true, child.body.gameObject.x, 0, true, true);
});
// 并向场景内添加一个敌人
const x = (player.body.gameObject.x < 400) ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);
const bomb = this.bombs!.create(x, 16, 'bomb');
bomb.setBounce(1); // 弹力
bomb.setCollideWorldBounds(true);
bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
}
}
// 碰撞敌人
hitBomb(player: Phaser.Types.Physics.Arcade.GameObjectWithBody, _bomb: Phaser.Types.Physics.Arcade.GameObjectWithBody) {
// 暂停物理引擎
this.physics.pause();
player.body.gameObject.setTint(0xff0000);
player.body.gameObject.anims.play('turn');
this.gameOver = true;
}
}
const config: Phaser.Types.Core.GameConfig = {
// 渲染方式
type: Phaser.AUTO,
width: 800,
height: 600,
// 物理配置
physics: {
// 默认的物理系统
default: 'arcade', // arcade impact matter
// arcade物理配置
arcade: {
// 重力
gravity: {
y: 300},
debug: true
}
},
// 场景
scene: SampleScene
}
const game: Phaser.Game = new Phaser.Game(config);
console.log(game);