效果展示
资源
图片资源
地图资源
src/GameScenes/Scene02/Tilemaps/map.json
{ "compressionlevel":-1,
"height":6,
"infinite":true,
"layers":[
{
"chunks":[
{
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":16,
"width":16,
"x":0,
"y":0
}],
"height":16,
"id":1,
"name":"sky",
"opacity":1,
"startx":0,
"starty":0,
"type":"tilelayer",
"visible":true,
"width":16,
"x":0,
"y":0
},
{
"chunks":[
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 6, 5, 4, 6, 5, 4, 6, 5, 4, 6, 5, 0, 0, 0, 0,
7, 9, 8, 7, 9, 8, 7, 9, 8, 7, 9, 8, 0, 0, 0, 0,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":16,
"width":16,
"x":0,
"y":0
}],
"height":16,
"id":2,
"name":"ground",
"opacity":1,
"startx":0,
"starty":0,
"type":"tilelayer",
"visible":true,
"width":16,
"x":0,
"y":0
}],
"nextlayerid":3,
"nextobjectid":1,
"orientation":"orthogonal",
"renderorder":"left-up",
"tiledversion":"1.9.0",
"tileheight":16,
"tilesets":[
{
"columns":1,
"firstgid":1,
"image":"sky.png",
"imageheight":48,
"imagewidth":16,
"margin":0,
"name":"sky",
"spacing":0,
"tilecount":3,
"tileheight":16,
"tilewidth":16
},
{
"columns":3,
"firstgid":4,
"image":"ground.png",
"imageheight":48,
"imagewidth":48,
"margin":0,
"name":"ground",
"spacing":0,
"tilecount":9,
"tileheight":16,
"tilewidth":16
}],
"tilewidth":16,
"type":"map",
"version":"1.9",
"width":12
}
创建地图
天空地面循环滚动
左键:
减速
右键:
加速
不按:
普通速度
import Phaser from 'phaser';
export default class MainScene extends Phaser.Scene {
// 地图
private map: Phaser.Tilemaps.Tilemap | undefined;
// 天空图层
private skyLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 地面图层
private groundLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 缩放系数
private mapScale: number = 6.25;
// 当前速度
private currentVelocity: number = 1.5;
// 速度
private velocity: number = 1.5;
// 加速度
private acceleration: number = 1;
// 距离
private distance: number = 0;
// 键盘
private cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
constructor() {
super({
key: 'MainScene',
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
});
}
preload() {
// 天空地面
{
const map = new URL(`../Tilemaps/map.json`, import.meta.url).href;
const sky = new URL(`../Tilemaps/sky.png`, import.meta.url).href;
const ground = new URL(`../Tilemaps/ground.png`, import.meta.url).href;
this.load.tilemapTiledJSON('map', map);
this.load.image('sky', sky);
this.load.image('ground', ground);
}
}
create() {
// 添加键盘控制
{
this.cursors = this.input.keyboard.createCursorKeys();
}
// 创建天空地面
{
this.map = this.make.tilemap({key: 'map'});
const sky = this.map.addTilesetImage('sky', 'sky');
const ground = this.map.addTilesetImage('ground', 'ground');
this.skyLayer = this.map.createLayer('sky', sky, 0, 0).setScale(this.mapScale);
this.groundLayer = this.map.createLayer('ground', ground, 0, 0).setScale(this.mapScale);
this.groundLayer.setCollision([4, 5, 6, 7, 8, 9, 10]);
}
}
update(time: number, delta: number) {
super.update(time, delta);
// 天空地面运动
{
if (this.cursors?.left.isDown) { // 减速
this.currentVelocity = this.velocity - this.acceleration;
} else if (this.cursors?.right.isDown) { // 加速
this.currentVelocity = this.velocity + this.acceleration;
} else { // 默认速度
this.currentVelocity = this.velocity;
}
this.distance += this.currentVelocity;
let isTolerance = Phaser.Math.Within(this.map!.tileWidth * this.mapScale, this.distance, 1); // 容差在1以内
if (isTolerance) {
let prev, current;
for (let y = 0; y < this.map!.height; y++) {
for (let x = 1; x < this.map!.width; x++) {
if (y < 3) {
prev = this.skyLayer?.getTileAt(x - 1, y);
current = this.skyLayer?.getTileAt(x, y);
prev!.index = current!.index;
} else if (y >= 3) {
prev = this.groundLayer?.getTileAt(x - 1, y);
current = this.groundLayer?.getTileAt(x, y);
prev!.index = current!.index;
if (y === 3) {
current!.index = Phaser.Math.RND.weightedPick([4, 5, 6]);
}
if (y === 4) {
if (this.groundLayer?.getTileAt(x, 3).index === 6) {
current!.index = 9;
} else {
current!.index = Phaser.Math.RND.weightedPick([7, 8]);
}
}
if (y === 5) {
current!.index = Phaser.Math.RND.weightedPick([10]);
}
}
}
}
this.distance = 0;
}
this.skyLayer?.setX(-this.distance * 0.5);
this.groundLayer?.setX(-this.distance);
}
}
}
放置障碍物
import Phaser from 'phaser';
export default class MainScene extends Phaser.Scene {
// 地图
private map: Phaser.Tilemaps.Tilemap | undefined;
// 天空图层
private skyLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 地面图层
private groundLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 缩放系数
private mapScale: number = 6.25;
// 当前速度
private currentVelocity: number = 1.5;
// 速度
private velocity: number = 1.5;
// 加速度
private acceleration: number = 1;
// 距离
private distance: number = 0;
// 键盘
private cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
// 时间监听
private timer: Phaser.Time.TimerEvent | undefined;
// 障碍物集合
private obstacles: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody[] = [];
// 分数
private score: number = 0;
// 分数文本
private scoreText: Phaser.GameObjects.Text | undefined;
constructor() {
super({
key: 'MainScene',
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
});
}
preload() {
// 障碍物
{
const {href: cactusA} = new URL(`../Sprites/cactus A.png`, import.meta.url);
const {href: cactusB} = new URL(`../Sprites/cactus B.png`, import.meta.url);
const {href: cactusC} = new URL(`../Sprites/cactus C.png`, import.meta.url);
this.load.spritesheet('obstacle A', cactusA, {frameWidth: 12, frameHeight: 20});
this.load.spritesheet('obstacle B', cactusB, {frameWidth: 21, frameHeight: 15});
this.load.spritesheet('obstacle C', cactusC, {frameWidth: 28, frameHeight: 20});
}
// 分数
{
this.scoreText = this.add.text(16, 16, `Score: ${this.score}`, {fontSize: '32px', color: '#48ff00'});
this.scoreText.setDepth(2);
}
}
create() {
// 添加键盘控制
{
this.cursors = this.input.keyboard.createCursorKeys();
}
// 障碍物
{
this.setObstacles();
}
}
update(time: number, delta: number) {
super.update(time, delta);
// 障碍物速度
{
this.obstacles.forEach(obstacle => {
obstacle.x -= this.currentVelocity;
if (obstacle.x < -100) {
obstacle.destroy();
}
})
}
}
// 放置障碍物
setObstacles() {
this.score += 1;
this.scoreText!.setText(`Score: ${this.score * 10}`);
if (this.timer) this.timer.destroy();
let delay = Math.cos(this.score / 600) * 3000;
// 秒数小于2秒固定为2秒
if (delay < 2000) {
delay = 2000;
}
// 按左键固定秒数,避免障碍物过近
if (this.cursors?.left.isDown) {
delay = 6000;
}
this.timer = this.time.addEvent({
delay,
callback: this.setObstacles,
callbackScope: this,
loop: true
});
let item = Phaser.Math.RND.weightedPick([
{key: 'obstacle A', w: 12, h: 20},
{key: 'obstacle B', w: 21, h: 15},
{key: 'obstacle C', w: 28, h: 20}
]);
let x = this.map!.widthInPixels * this.mapScale + 100; // Math.cos(this.score / 600) * 1600;
let y = this.map!.tileHeight * this.mapScale * 3 - item.h / 2 * this.mapScale;
let obstacle = this.physics.add.sprite(x, y, item.key).setScale(this.mapScale).refreshBody();
obstacle.setCircle(item.w / 2); // 碰撞区域
this.obstacles.push(obstacle);
}
}
添加玩家操作和动画
import Phaser from 'phaser';
export default class MainScene extends Phaser.Scene {
// 地图
private map: Phaser.Tilemaps.Tilemap | undefined;
// 天空图层
private skyLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 地面图层
private groundLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 缩放系数
private mapScale: number = 6.25;
// 当前速度
private currentVelocity: number = 1.5;
// 速度
private velocity: number = 1.5;
// 加速度
private acceleration: number = 1;
// 距离
private distance: number = 0;
// 键盘
private cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
// 时间监听
private timer: Phaser.Time.TimerEvent | undefined;
// 障碍物集合
private obstacles: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody[] = [];
// 分数
private score: number = 0;
// 分数文本
private scoreText: Phaser.GameObjects.Text | undefined;
// 玩家
private player: (Phaser.Physics.Arcade.Sprite & { body: Phaser.Physics.Arcade.Body; }) | undefined;
// 重力
private gravityY: number = 600;
// 跳跃速度
private jumpVelocity: number = 500;
constructor() {
super({
key: 'MainScene',
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
});
}
preload() {
// 玩家
{
const {href: player} = new URL(`../Sprites/player.png`, import.meta.url);
this.load.spritesheet('player', player, {frameWidth: 16.8, frameHeight: 16});
}
}
create() {
// 添加键盘控制
{
this.cursors = this.input.keyboard.createCursorKeys();
}
// 玩家
{
this.player = this.physics.add.sprite(100, 100, 'player').setScale(this.mapScale).refreshBody();
this.player.setDepth(1);
// 左右
this.anims.create({
key: 'run',
frames: this.anims.generateFrameNumbers('player', {start: 0, end: 3}),
frameRate: 10,
repeat: -1
});
// 跳跃
this.anims.create({
key: 'jump',
frames: [{key: 'player', frame: 4}],
frameRate: 20
});
// 死亡
this.anims.create({
key: 'died',
frames: [{key: 'player', frame: 5}],
frameRate: 20
});
this.player.setGravityY(this.gravityY);
}
// 玩家与地面碰撞
{
this.physics.add.collider(this.player, this.groundLayer);
}
}
update(time: number, delta: number) {
super.update(time, delta);
// 玩家移动跳跃
{
// 在地面上
if (this.player?.body.onFloor()) {
// 获取当前动画是否为 run
this.player?.anims.getName() !== 'run' && this.player?.anims.play('run');
// 在地面时可跳跃
if (this.cursors?.space.isDown || this.cursors?.up.isDown) {
this.player?.setVelocityY(-this.jumpVelocity);
}
}
// 不在地面上 动画jump
else {
this.player?.anims.play('jump');
}
}
}
}
玩家与障碍物碰撞游戏结束
import Phaser from 'phaser';
export default class MainScene extends Phaser.Scene {
// 地图
private map: Phaser.Tilemaps.Tilemap | undefined;
// 天空图层
private skyLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 地面图层
private groundLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 缩放系数
private mapScale: number = 6.25;
// 当前速度
private currentVelocity: number = 1.5;
// 速度
private velocity: number = 1.5;
// 加速度
private acceleration: number = 1;
// 距离
private distance: number = 0;
// 键盘
private cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
// 时间监听
private timer: Phaser.Time.TimerEvent | undefined;
// 障碍物集合
private obstacles: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody[] = [];
// 分数
private score: number = 0;
// 分数文本
private scoreText: Phaser.GameObjects.Text | undefined;
// 玩家
private player: (Phaser.Physics.Arcade.Sprite & { body: Phaser.Physics.Arcade.Body; }) | undefined;
// 重力
private gravityY: number = 600;
// 跳跃速度
private jumpVelocity: number = 500;
// 游戏结束
private gameOver: boolean = false;
constructor() {
super({
key: 'MainScene',
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
});
}
preload() {
}
create() {
// 玩家与障碍物碰撞游戏结束
{
this.physics.add.overlap(this.player, this.obstacles, this.hitObstacle, undefined, this);
}
}
update(time: number, delta: number) {
super.update(time, delta);
// 游戏结束
{
if (this.gameOver) {
this.timer && this.timer.destroy();
this.scoreText!.setText(`游戏结束, Score: ${this.score * 10}`);
return
}
}
}
// 放置障碍物
setObstacles() {
if (this.gameOver) return;
}
// 角色碰撞障碍物
hitObstacle(player: Phaser.Types.Physics.Arcade.GameObjectWithBody, _obstacle: Phaser.Types.Physics.Arcade.GameObjectWithBody) {
// 暂停物理引擎
this.physics.pause();
// player.body.gameObject.setTint(0xff0000);
player.body.gameObject.anims.play('died');
this.timer && this.timer.destroy();
this.gameOver = true;
}
}
添加场景装饰云和石头
import Phaser from 'phaser';
export default class MainScene extends Phaser.Scene {
// 地图
private map: Phaser.Tilemaps.Tilemap | undefined;
// 天空图层
private skyLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 地面图层
private groundLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 缩放系数
private mapScale: number = 6.25;
// 当前速度
private currentVelocity: number = 1.5;
// 速度
private velocity: number = 1.5;
// 加速度
private acceleration: number = 1;
// 距离
private distance: number = 0;
// 键盘
private cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
// 障碍物时间监听
private obstacleTimer: Phaser.Time.TimerEvent | undefined;
// 障碍物集合
private obstacles: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody[] = [];
// 分数
private score: number = 0;
// 分数文本
private scoreText: Phaser.GameObjects.Text | undefined;
// 玩家
private player: (Phaser.Physics.Arcade.Sprite & { body: Phaser.Physics.Arcade.Body; }) | undefined;
// 重力
private gravityY: number = 600;
// 跳跃速度
private jumpVelocity: number = 500;
// 游戏结束
private gameOver: boolean = false;
// 云
private clouds: Phaser.GameObjects.Image[] = [];
// 石头
private rocks: Phaser.GameObjects.Image[] = [];
// 云石头时间监听
private crTimer: Phaser.Time.TimerEvent | undefined;
constructor() {
super({
key: 'MainScene',
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
});
}
preload() {
// 云和石头
{
const cloudA = new URL(`../Sprites/cloud A.png`, import.meta.url).href;
const cloudB = new URL(`../Sprites/cloud B.png`, import.meta.url).href;
const rockA = new URL(`../Sprites/rock A.png`, import.meta.url).href;
const rockB = new URL(`../Sprites/rock B.png`, import.meta.url).href;
this.load.image('cloud A', cloudA);
this.load.image('cloud B', cloudB);
this.load.image('rock A', rockA);
this.load.image('rock B', rockB);
}
}
create() {
// 云和石头监听
{
this.crTimer = this.time.addEvent({
delay: 1000,
callback: this.setCloudsRocks,
callbackScope: this,
loop: true
});
}
}
update(time: number, delta: number) {
super.update(time, delta);
// 游戏结束
{
if (this.gameOver) {
this.obstacleTimer && this.obstacleTimer.destroy();
this.crTimer && this.crTimer.destroy();
this.scoreText!.setText(`游戏结束, Score: ${this.score * 10}`);
return
}
}
// 云和石头
{
this.clouds.forEach(cloud => {
cloud.x -= this.currentVelocity * 0.6;
if (cloud.x < -100) {
cloud.destroy();
}
})
this.rocks.forEach(rock => {
rock.x -= this.currentVelocity * 0.8;
if (rock.x < -100) {
rock.destroy();
}
})
}
}
// 云和石头
setCloudsRocks() {
let cloudItem = Phaser.Math.RND.weightedPick([
{key: 'cloud A', w: 20, h: 11},
{key: 'cloud B', w: 11, h: 5}
]);
let rockItem = Phaser.Math.RND.weightedPick([
{key: 'rock A', w: 48, h: 24},
{key: 'rock B', w: 16, h: 16}
]);
let clodX = this.map!.widthInPixels * this.mapScale + 100;
let clodY = Math.random() * this.map!.tileHeight * 2 * this.mapScale;
let rockX = this.map!.widthInPixels * this.mapScale * (1 + Math.random());
let rockY = this.map!.tileHeight * this.mapScale * 3 - rockItem.h / 2 * this.mapScale;
let cloud = this.add.image(clodX, clodY, cloudItem.key).setScale(this.mapScale).setDepth(2);
let rock = this.add.image(rockX, rockY, rockItem.key).setScale(this.mapScale).setDepth(2);
this.clouds.push(cloud);
this.rocks.push(rock);
}
}
完整代码
import Phaser from 'phaser';
export default class MainScene extends Phaser.Scene {
// 地图
private map: Phaser.Tilemaps.Tilemap | undefined;
// 天空图层
private skyLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 地面图层
private groundLayer: Phaser.Tilemaps.TilemapLayer | undefined;
// 缩放系数
private mapScale: number = 6.25;
// 当前速度
private currentVelocity: number = 1.5;
// 速度
private velocity: number = 1.5;
// 加速度
private acceleration: number = 1;
// 距离
private distance: number = 0;
// 键盘
private cursors: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
// 障碍物时间监听
private obstacleTimer: Phaser.Time.TimerEvent | undefined;
// 障碍物集合
private obstacles: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody[] = [];
// 分数
private score: number = 0;
// 分数文本
private scoreText: Phaser.GameObjects.Text | undefined;
// 玩家
private player: (Phaser.Physics.Arcade.Sprite & { body: Phaser.Physics.Arcade.Body; }) | undefined;
// 重力
private gravityY: number = 600;
// 跳跃速度
private jumpVelocity: number = 500;
// 游戏结束
private gameOver: boolean = false;
// 云
private clouds: Phaser.GameObjects.Image[] = [];
// 石头
private rocks: Phaser.GameObjects.Image[] = [];
// 云石头时间监听
private crTimer: Phaser.Time.TimerEvent | undefined;
constructor() {
super({
key: 'MainScene',
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
});
}
preload() {
// 天空地面
{
const map = new URL(`../Tilemaps/map.json`, import.meta.url).href;
const sky = new URL(`../Tilemaps/sky.png`, import.meta.url).href;
const ground = new URL(`../Tilemaps/ground.png`, import.meta.url).href;
this.load.tilemapTiledJSON('map', map);
this.load.image('sky', sky);
this.load.image('ground', ground);
}
// 障碍物
{
const {href: cactusA} = new URL(`../Sprites/cactus A.png`, import.meta.url);
const {href: cactusB} = new URL(`../Sprites/cactus B.png`, import.meta.url);
const {href: cactusC} = new URL(`../Sprites/cactus C.png`, import.meta.url);
this.load.spritesheet('obstacle A', cactusA, {frameWidth: 12, frameHeight: 20});
this.load.spritesheet('obstacle B', cactusB, {frameWidth: 21, frameHeight: 15});
this.load.spritesheet('obstacle C', cactusC, {frameWidth: 28, frameHeight: 20});
}
// 分数
{
this.scoreText = this.add.text(16, 16, `Score: ${this.score}`, {fontSize: '32px', color: '#48ff00'});
this.scoreText.setDepth(5);
}
// 玩家
{
const {href: player} = new URL(`../Sprites/player.png`, import.meta.url);
this.load.spritesheet('player', player, {frameWidth: 16.8, frameHeight: 16});
}
// 云和石头
{
const cloudA = new URL(`../Sprites/cloud A.png`, import.meta.url).href;
const cloudB = new URL(`../Sprites/cloud B.png`, import.meta.url).href;
const rockA = new URL(`../Sprites/rock A.png`, import.meta.url).href;
const rockB = new URL(`../Sprites/rock B.png`, import.meta.url).href;
this.load.image('cloud A', cloudA);
this.load.image('cloud B', cloudB);
this.load.image('rock A', rockA);
this.load.image('rock B', rockB);
}
}
create() {
// 添加键盘控制
{
this.cursors = this.input.keyboard.createCursorKeys();
}
// 创建天空地面
{
this.map = this.make.tilemap({key: 'map'});
const sky = this.map.addTilesetImage('sky', 'sky');
const ground = this.map.addTilesetImage('ground', 'ground');
this.skyLayer = this.map.createLayer('sky', sky, 0, 0).setScale(this.mapScale);
this.groundLayer = this.map.createLayer('ground', ground, 0, 0).setScale(this.mapScale);
this.groundLayer.setCollision([4, 5, 6, 7, 8, 9, 10]);
}
// 障碍物
{
this.setObstacles();
}
// 玩家
{
this.player = this.physics.add.sprite(200, 100, 'player').setScale(this.mapScale).refreshBody();
this.player.setDepth(4);
// 左右
this.anims.create({
key: 'run',
frames: this.anims.generateFrameNumbers('player', {start: 0, end: 3}),
frameRate: 10,
repeat: -1
});
// 跳跃
this.anims.create({
key: 'jump',
frames: [{key: 'player', frame: 4}],
frameRate: 20
});
// 死亡
this.anims.create({
key: 'died',
frames: [{key: 'player', frame: 5}],
frameRate: 20
});
this.player.setGravityY(this.gravityY);
}
// 玩家与地面碰撞
{
this.physics.add.collider(this.player, this.groundLayer);
}
// 玩家与障碍物碰撞游戏结束
{
this.physics.add.overlap(this.player, this.obstacles, this.hitObstacle, undefined, this);
}
// 云和石头监听
{
this.crTimer = this.time.addEvent({
delay: 1000,
callback: this.setCloudsRocks,
callbackScope: this,
loop: true
});
}
}
update(time: number, delta: number) {
super.update(time, delta);
// 游戏结束
{
if (this.gameOver) {
this.obstacleTimer && this.obstacleTimer.destroy();
this.crTimer && this.crTimer.destroy();
this.scoreText!.setText(`游戏结束, Score: ${this.score * 10}`);
return
}
}
// 天空地面运动
{
if (this.cursors?.left.isDown) { // 减速
this.currentVelocity = this.velocity - this.acceleration;
} else if (this.cursors?.right.isDown) { // 加速
this.currentVelocity = this.velocity + this.acceleration;
} else { // 默认速度
this.currentVelocity = this.velocity;
}
this.distance += this.currentVelocity;
let isTolerance = Phaser.Math.Within(this.map!.tileWidth * this.mapScale, this.distance, 1); // 容差在1以内
if (isTolerance) {
let prev, current;
for (let y = 0; y < this.map!.height; y++) {
for (let x = 1; x < this.map!.width; x++) {
if (y < 3) {
prev = this.skyLayer?.getTileAt(x - 1, y);
current = this.skyLayer?.getTileAt(x, y);
prev!.index = current!.index;
} else if (y >= 3) {
prev = this.groundLayer?.getTileAt(x - 1, y);
current = this.groundLayer?.getTileAt(x, y);
prev!.index = current!.index;
if (y === 3) {
current!.index = Phaser.Math.RND.weightedPick([4, 5, 6]);
}
if (y === 4) {
if (this.groundLayer?.getTileAt(x, 3).index === 6) {
current!.index = 9;
} else {
current!.index = Phaser.Math.RND.weightedPick([7, 8]);
}
}
if (y === 5) {
current!.index = Phaser.Math.RND.weightedPick([10]);
}
}
}
}
this.distance = 0;
}
this.skyLayer?.setX(-this.distance * 0.5);
this.groundLayer?.setX(-this.distance);
}
// 障碍物速度
{
this.obstacles.forEach(obstacle => {
obstacle.x -= this.currentVelocity;
if (obstacle.x < -100) {
obstacle.destroy();
}
})
}
// 玩家移动跳跃
{
// 在地面上
if (this.player?.body.onFloor()) {
// 获取当前动画是否为 run
this.player?.anims.getName() !== 'run' && this.player?.anims.play('run');
// 在地面时可跳跃
if (this.cursors?.space.isDown || this.cursors?.up.isDown) {
this.player?.setVelocityY(-this.jumpVelocity);
}
}
// 不在地面上 动画jump
else {
this.player?.anims.play('jump');
}
}
// 云和石头
{
this.clouds.forEach(cloud => {
cloud.x -= this.currentVelocity * 0.6;
if (cloud.x < -100) {
cloud.destroy();
}
})
this.rocks.forEach(rock => {
rock.x -= this.currentVelocity * 0.8;
if (rock.x < -100) {
rock.destroy();
}
})
}
}
// 放置障碍物
setObstacles() {
if (this.gameOver) return;
this.score += 1;
this.scoreText!.setText(`Score: ${this.score * 10}`);
this.obstacleTimer && this.obstacleTimer.destroy();
let delay = Math.cos(this.score / 600) * 3000;
// 秒数小于2秒固定为2秒
if (delay < 2000) {
delay = 2000;
}
// 按左键固定秒数,避免障碍物过近
if (this.cursors?.left.isDown) {
delay = 6000;
}
this.obstacleTimer = this.time.addEvent({
delay,
callback: this.setObstacles,
callbackScope: this,
loop: true
});
let item = Phaser.Math.RND.weightedPick([
{key: 'obstacle A', w: 12, h: 20},
{key: 'obstacle B', w: 21, h: 15},
{key: 'obstacle C', w: 28, h: 20}
]);
let x = this.map!.widthInPixels * this.mapScale + 100;
let y = this.map!.tileHeight * this.mapScale * 3 - item.h / 2 * this.mapScale;
let obstacle = this.physics.add.sprite(x, y, item.key).setScale(this.mapScale).refreshBody();
obstacle.setCircle(item.w / 2.5, 1); // 碰撞区域
obstacle.setDepth(3);
this.obstacles.push(obstacle);
}
// 角色碰撞障碍物
hitObstacle(player: Phaser.Types.Physics.Arcade.GameObjectWithBody, _obstacle: Phaser.Types.Physics.Arcade.GameObjectWithBody) {
// 暂停物理引擎
this.physics.pause();
// player.body.gameObject.setTint(0xff0000);
player.body.gameObject.anims.play('died');
this.obstacleTimer && this.obstacleTimer.destroy();
this.gameOver = true;
}
// 云和石头
setCloudsRocks() {
let cloudItem = Phaser.Math.RND.weightedPick([
{key: 'cloud A', w: 20, h: 11},
{key: 'cloud B', w: 11, h: 5}
]);
let rockItem = Phaser.Math.RND.weightedPick([
{key: 'rock A', w: 48, h: 24},
{key: 'rock B', w: 16, h: 16}
]);
let clodX = this.map!.widthInPixels * this.mapScale + 100;
let clodY = Math.random() * this.map!.tileHeight * 2 * this.mapScale;
let rockX = this.map!.widthInPixels * this.mapScale * (1 + Math.random());
let rockY = this.map!.tileHeight * this.mapScale * 3 - rockItem.h / 2 * this.mapScale;
let cloud = this.add.image(clodX, clodY, cloudItem.key).setScale(this.mapScale).setDepth(2);
let rock = this.add.image(rockX, rockY, rockItem.key).setScale(this.mapScale).setDepth(2);
this.clouds.push(cloud);
this.rocks.push(rock);
}
}
import Phaser from "phaser";
new Phaser.Game({
type: Phaser.AUTO,
parent: 'phaser3-game',
width: 1024,
height: 600,
pixelArt: true,
scene: MainScene,
});