Phaser(二):小恐龙跑酷游戏

效果展示

在这里插入图片描述

资源

在这里插入图片描述

图片资源

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

地图资源

在这里插入图片描述
在这里插入图片描述

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,
});

猜你喜欢

转载自blog.csdn.net/weixin_43526371/article/details/126085077