Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Lauri Inkilä
Published © MIT

Unleashing the mobile Rover robot

Revolutionize robotics: a 4WD Rover with LiDAR, ROS SLAM & RPI4. Experience the future!

IntermediateWork in progressOver 1 day540
Unleashing the mobile Rover robot

Things used in this project

Hardware components

12V DC Motor XD-37GB520
×4
Raspberry Pi 4 Model B
Raspberry Pi 4 Model B
×1
Adafruit HAT Motor controller
×1
LiDAR S2
×1
Chassis
×1

Software apps and online services

Raspbian
Raspberry Pi Raspbian

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Hot air blower

Story

Read more

Schematics

Raspberry Pi 4 CoC platform

ROS installed to Docker container to control dependencies.

Code

Untitled file

JavaScript
// https://phaser.io/tutorials/making-your-first-phaser-3-game/part1
// https://phaser.io/tutorials/coding-tips-003
// grass level music: https://www.chosic.com/download-audio/25477/
// boss fight music: https://pixabay.com/music/video-games-cruising-down-8bit-lane-159615/
// heart container: https://xxashuraxx.itch.io/heart
// ouch sound: https://pixabay.com/sound-effects/ouch-sound-effect-30-11844/
// characters: https://pixelfrog-assets.itch.io/pixel-adventure-2
// menu items: https://bdragon1727.itch.io/basic-pixel-gui-and-buttons-pack-2
// bricktexture: https://pucci-games.itch.io/stones-brick-textures
// second level music: https://pixabay.com/sound-effects/game-music-loop-3-144252/
// spaceship: https://craftpix.net/freebies/free-pixel-art-enemy-spaceship-2d-sprites/?num=1&count=23&sq=spaceship&pos=5
// second boss enemy: https://www.kenney.nl/assets/alien-ufo-pack


let game


const gameOptions = {
    characterGravity: 1000, // how heavy the slime is and how fast it falls
    characterSpeed: 300, // speed
    characterHealth: 3,
    characterHit: false,
    playerFlying: false,
    playerScore: 0,
    playerInFight: false,
    playerLevel: 0,


    enemyGravity: 1000,
    enemySpeed: 20,
    enemyHealth: 3,
    enemyHit: false
}


window.onload = function() {
    let gameConfig = {
        type: Phaser.AUTO, // what kind of game
        backgroundColor: "#87CEEB",
        scale: {
            mode: Phaser.Scale.FIT, // scale manager
            autoCenter: Phaser.Scale.CENTER_BOTH,
            width: 640,
            height: 700,
        },
        pixelArt: true,
        physics: {
            default: "arcade",
            arcade: {
                debug: false,
                gravity: {
                    y: 0 // nothing is dropping when y = 0
                }
            }
        },
        audio: {
            disabledWebAudio: true //  reference for audio https://rexrainbow.github.io/phaser3-rex-notes/docs/site/audio/
        },
        scene: [GameMenu, PlayGame, GameMusic, SecondLevel]
    }
    window.focus()
    game = new Phaser.Game(gameConfig)
}




class GameMenu extends Phaser.Scene {
    constructor() {
        super({key: 'gamemenu'})
    }


    init(info) {
        // to check if dead-variable is defined in the data (=info) passed to the scene
        this.dead = info.dead || false // defaults to false if not provided
    }


    preload() {
        this.load.spritesheet('menuBtns', 'assets/menu/Metal_Buttons_Text_small.png', {frameWidth: 64, frameHeight: 32})
        this.load.image("clouds", "assets/background/clouds.png")
       
    }


    create() {
        for (let i = 0; i < 8; i++) {
            this.add.tileSprite(330,  game.config.height/2, 640, game.config.height, 'clouds') // syntax: tileSprite(x, y, width, height, textureKey, frame)
        }
        let fadeRect = this.add.rectangle(0, 0, this.game.config.width, this.game.config.height, 0x000000, 0.4)
        fadeRect.setOrigin(0, 0)
       
        console.log(this.dead)
        if (!this.dead) {
           
            this.anims.create({
                key: 'startBtn',
                frames: this.anims.generateFrameNumbers('menuBtns', {start: 0, end: 2}),
                frameRate: 5,
                repeat: -1
            })


            var infoText = { // reference: https://www.html5gamedevs.com/topic/40401-text-styling/
                x: this.game.config.width / 4.5,
                y: 50,
                text: 'Game Project for Introduction to Web Programming',
                style: {
                    fontSize: '14px',
                    color: '#ffffff',
                    align: 'center'
                }
            }
            this.make.text(infoText)
   
            var GameName = { // reference: https://www.html5gamedevs.com/topic/40401-text-styling/
                x: this.game.config.width / 5,
                y: 180,
                text: 'Froggy Jump',
                style: {
                    fontSize: '64px',
                    fontFamily: 'Potta One',
                    color: '#32CD32',
                    align: 'center',
                    fontWeight: 'bold'
                }
            }
            this.make.text(GameName)
   
            let startGame = this.add.sprite(this.game.config.width / 2, this.game.config.height / 2, 'startBtn').setScale(2)
            startGame.play('startBtn')
            startGame.setInteractive()
            startGame.on('pointerdown', () => {
                this.scene.start('playgame')
            })
   
        } else {


            var menu = { // reference: https://www.html5gamedevs.com/topic/40401-text-styling/
                x: this.game.config.width / 4.5,
                y: 180,
                text: 'Froggy died! Play again?',
                style: {
                    fontSize: '32px',
                    fontFamily: 'Potta One',
                    color: '#00000',
                    align: 'center',
                    fontWeight: 'bold'
                }
            }
            this.make.text(menu)


            this.anims.create({
                key: 'yesBtn',
                frames: this.anims.generateFrameNumbers('menuBtns', {start: 8, end: 9}),
                frameRate: 5,
                repeat: -1
            })
            this.anims.create({
                key: 'noBtn',
                frames: this.anims.generateFrameNumbers('menuBtns', {start: 3, end: 4}),
                frameRate: 5,
                repeat: -1
            })
           
            let yes = this.add.sprite(this.game.config.width / 1.5, this.game.config.height / 2, 'yesBtn').setScale(2)
            yes.play('yesBtn')
            yes.setInteractive()
            yes.on('pointerdown', () => {
                this.scene.start('playgame')
            })


            let no = this.add.sprite(this.game.config.width / 2.5, this.game.config.height / 2, 'noBtn').setScale(2)
            no.play('noBtn')
            no.setInteractive()
            no.on('pointerdown', () => {
                this.dead = false
                this.scene.restart({dead: this.dead})
            })
        }
    }
       


       
}


class GameMusic extends Phaser.Scene { // multiple scenes reference: https://labs.phaser.io/edit.html?src=src/scenes/multiple%20scenes%20from%20classes.js


    constructor() {
        super({key: 'gamemusic', active: true}) // music is set to be always active
    }


    preload() { // loading the assets
        // audios and related images
        this.load.audio('GrassLevelMusic', "assets/audio/firstLevelMusic.mp3")
        this.load.audio('NextLevelMusic', "assets/audio/secondLevel.mp3")
        this.load.audio('firstBossMusic', 'assets/audio/firstBossfightMusic.mp3')
        this.load.image('volumeOn', "assets/audio/volume_on.png")
        this.load.image('volumeOff', "assets/audio/volume_off.png")


    }


    create() {
        this.firstmusic = this.sound.add('GrassLevelMusic')
        this.secondMusic = this.sound.add('NextLevelMusic')
        this.bossMusic = this.sound.add('firstBossMusic')




        this.bossMusic.setLoop(true)
        this.firstmusic.setLoop(true)
        this.secondMusic.setLoop(true)


        this.firstmusic.play()
        this.firstmusic.setVolume(0.2)


        this.volume = this.add.image(game.config.width/15, game.config.height/25, 'volumeOn').setScale(0.1)
        this.volume.setInteractive()
        this.input.on('gameobjectup', this.volumeHandler, this)


        // EventEmitter reference: https://photonstorm.github.io/phaser3-docs/Phaser.Events.EventEmitter.html
        this.events.on('playBossFightMusic', this.playBossFightMusic, this)
        this.events.on('stopBossFightMusic', this.stopBossFightMusic, this)
        this.events.on('resetMusic', this.resetMusicOnPlayerDeath, this)
        this.events.on('nextLevel', this.nextLevelMusic, this)
    }


    playBossFightMusic() {
        if (this.firstmusic.isPlaying) {
            this.tweens.add({ // refernce for fading out/in music: https://phaser.discourse.group/t/solved-fade-out-sound/3289
                targets: this.firstmusic,
                volume: 0,
                duration: 500
            })
            this.firstmusic.stop()


            this.bossMusic.play()
            this.bossMusic.setVolume(0)


            this.tweens.add({
                targets: this.bossMusic,
                volume: 0.2,
                duration: 1000
            })
        } else if (this.secondMusic.isPlaying) {
            this.tweens.add({ // refernce for fading out/in music: https://phaser.discourse.group/t/solved-fade-out-sound/3289
                targets: this.secondMusic,
                volume: 0,
                duration: 500
            })
            this.secondMusic.stop()


            this.bossMusic.play()
            this.bossMusic.setVolume(0)


            this.tweens.add({
                targets: this.bossMusic,
                volume: 0.2,
                duration: 1000
            })
        } else {
            this.bossMusic.play()
            this.bossMusic.setVolume(0)
        }
    }


    stopBossFightMusic() {
        if (this.bossMusic.isPlaying) {
            this.tweens.add({
                targets: this.bossMusic,
                volume: 0,
                duration: 500
            })
            this.bossMusic.stop()
        } else {
            return
        }
    }


    resetMusicOnPlayerDeath() {
        if (this.firstmusic.isPlaying) {
            this.firstmusic.stop()
            this.firstmusic.play()
            this.firstmusic.setVolume(0.2)
        } else if (this.secondMusic.isPlaying) {
            this.secondMusic.stop()
            this.firstmusic.play()
            this.firstmusic.setVolume(0.2)          
        } else if (this.bossMusic.isPlaying) {
            this.tweens.add({ // refernce for fading out/in music: https://phaser.discourse.group/t/solved-fade-out-sound/3289
                targets: this.bossMusic,
                volume: 0,
                duration: 500
            })
            this.bossMusic.stop()
            this.firstmusic.play()
            this.firstmusic.setVolume(0.2)
        }
    }


    nextLevelMusic() {
        this.tweens.add({ // refernce for fading out/in music: https://phaser.discourse.group/t/solved-fade-out-sound/3289
            targets: this.bossMusic,
            volume: 0,
            duration: 500
        })
        this.bossMusic.stop()
        this.secondMusic.play()
        this.secondMusic.setVolume(0.2)
    }


    volumeHandler () {
        if (this.firstmusic.isPlaying) {
            this.firstmusic.pause()
            this.volume.setTexture('volumeOff').setScale(0.1)
            return
        } else if (!this.firstmusic.isPlaying) {
            this.firstmusic.resume()
            this.volume.setTexture('volumeOn')
            return
        }


        if (this.secondMusic.isPlaying) {
            this.secondMusic.pause()
            this.volume.setTexture('volumeOff').setScale(0.1)
            return
        } else if (!this.secondMusic.isPlaying) {
            this.secondMusic.resume()
            this.volume.setTexture('volumeOn')
            return
        }


        if (this.bossMusic.isPlaying) {
            this.bossMusic.pause()
            this.volume.setTexture('volumeOff').setScale(0.1)
            return
        } else {
            this.bossMusic.resume()
            this.volume.setTexture('volumeOn')
            return
        }
    }
}


class SecondLevel extends Phaser.Scene {
    constructor () {
        super({key: 'secondlevel'});
    }


    preload() {
        // background stuff
        this.load.image("citybg", "assets/background/citybg.jpg")
        this.load.image("brickbg", "assets/background/Brickwall.png")


        // platforms to stand on
        this.load.image("cityPlatform", "assets/platform/Pads/cityPlatform.png")
        this.load.image('cityTerrain', "assets/Free/Terrain/CityTerrain(16x16).png", {frameWidth: 16, frameHeight: 16})
        this.load.image('citySkyTerrain', "assets/Free/Terrain/CitySkyTerrain(16x16).png", {frameWidth: 16, frameHeight: 16})


        // enemies
        this.load.image('spaceShipRight', 'assets/enemies/Ship1/Ship1Right.png')
        this.load.image('spaceShipLeft', 'assets/enemies/Ship1/Ship1Left.png')
        this.load.spritesheet('bossEnemyRight', 'assets/enemies/NightBorneRight.png', {frameWidth: 80, frameHeight: 80})
        this.load.spritesheet('bossEnemyLeft', 'assets/enemies/NightBorneLeft.png', {frameWidth: 80, frameHeight: 80})


    }


    create() {
        this.physics.world.setBounds(0, 0, 640, 4000) // world height is 4000 pixls
        this.worldBounds = this.physics.world.bounds
        this.cursors = this.input.keyboard.createCursorKeys() // initializing the keyboard
        this.input.keyboard.manager.enabled = true


        this.add.image(game.config.width/2, this.worldBounds.height-320, 'citybg').setScale(0.35)
        this.cameras.main.setBackgroundColor('#010e14') // bg color




        this.rock = this.add.tileSprite(0, this.worldBounds.height+200, game.config.width*8, 1200, 'brickbg').setScale(0.3)


        this.battleGround = this.add.tileSprite(320, 400, game.config.width, 48, 'citySkyTerrain')
        this.physics.world.enable(this.battleGround)
        this.battleGround.body.setImmovable(true)
        this.battleGround.body.allowGravity = false
        this.battleGround.body.checkCollision.down = false


        // syntax: tileSprite(x, y, width, height, textureKey, frame)
        this.cityGround = this.add.tileSprite(320, this.worldBounds.height, this.worldBounds.height, 48, 'cityTerrain') // the bottom ground
        this.physics.world.enable(this.cityGround)
        this.cityGround.body.setImmovable(true)
        this.cityGround.body.checkCollision.down = false


        this.cityPlatforms = this.physics.add.group({
            immovable: true, // the platforms won't move if the player touches them
            allowGravity: false // normal platforms won't fall down
        })


        let x = 0, y = this.worldBounds.height-200 // y is the starting point for the first platform
        while (y > 500) { // create(x-cordinate, y-cordinate, item) when going up until y coordinate(?) meets its limit
            x = Phaser.Math.Between(0,game.config.width)


            let platform = this.cityPlatforms.create(x, y, "cityPlatform").setScale(0.1)
            platform.body.velocity.x = Phaser.Math.Between(70,200) // random speed for platforms
            platform.refreshBody().body.checkCollision.down = false // ability to jump through platforms but stand on them, reference: https://cedarcantab.wixsite.com/website-1/post/one-way-pass-through-platforms-in-phaser-3-sprites
            platform.setFrictionX(1) // making the player ride with the platform, reference: https://labs.phaser.io/edit.html?src=src/physics/arcade/friction.js&v=3.60.0


       
            y = y - 100 - 50 * Math.random(); // the platforms will be 100 to 150 pixels apart
        }


        this.spaceShips = this.physics.add.group({
            immovable: true, // the birds won't move if the player touches them
            allowGravity: false // birds won't fall down
        })


        let x_ss = 0, y_ss = this.worldBounds.height-500 // y is the starting point for the first bird
        while (y_ss > 500) { // create(x-cordinate, y-cordinate, item) when going up until y coordinate(?) meets its limit
            x_ss = Phaser.Math.Between(0,game.config.width)


            let spaceship =  this.spaceShips.create(x_ss, y_ss, 'spaceShipRight').setScale(0.9)
            spaceship.setTexture('spaceShipRight', 0)
            spaceship.body.velocity.x = 200 // speed for birds


            y_ss = y_ss - 200 - 100 * Math.random(); // the birds will be 70 to 120 pixels apart
            //bird.play("birdFlyRight")
            spaceship.setCollideWorldBounds(true);
        }


        this.coins = this.physics.add.group({
        })




       


        //creating animations for the sprites
        // enemy anims
        this.anims.create({
            key: 'enemyIdleRight',
            frames: this.anims.generateFrameNumbers("bossEnemyRight", {start: 0, end: 8}),
            frameRate: 10,
            repeat: -1
        })
        this.anims.create({
            key: 'enemyRunRight',
            frames: this.anims.generateFrameNumbers('bossEnemyRight', {start: 23, end: 28}),
            frameRate: 15,
            repeat: -1
        })
        this.anims.create({
            key: 'enemyAttackRight',
            frames: this.anims.generateFrameNumbers('bossEnemyRight', {start: 46, end: 57}),
            frameRate: 15,
            repeat: -1
        })
        this.anims.create({
            key: 'enemyHit',
            frames: this.anims.generateFrameNumbers('bossEnemyRight', {start: 69, end: 73}),
            frameRate: 10,
            repeat: -1
        })
        this.anims.create({
            key: 'enemyDeadRight',
            frames: this.anims.generateFrameNumbers('bossEnemyRight', {start: 91, end: 114}),
            frameRate: 10
        })
        // left side for enemy
        this.anims.create({
            key: 'enemyIdleLeft',
            frames: this.anims.generateFrameNumbers("bossEnemyLeft", {start: 14, end: 22}),
            frameRate: 10,
            repeat: -1
        })
        this.anims.create({
            key: 'enemyRunLeft',
            frames: this.anims.generateFrameNumbers('bossEnemyLeft', {start: 40, end: 45}),
            frameRate: 15,
            repeat: -1
        })
        this.anims.create({
            key: 'enemyAttackLeft',
            frames: this.anims.generateFrameNumbers('bossEnemyLeft', {start: 57, end: 68}),
            frameRate: 15,
            repeat: -1
        })


        // adding the characters to the world
        this.frog = this.physics.add.sprite(game.config.width / 2, this.worldBounds.height - 100, 'frog_idle').setScale(1.5) // this.worldBounds.height-100
        this.frog.anims.play('frog_idle')
        this.frog.body.gravity.y = gameOptions.characterGravity
        this.frog.body.bounce.y = 0.2
        this.frog.setCollideWorldBounds(true) // player cannot go over the worldbounds


        // main character properties
        this.frog.health = gameOptions.characterHealth // character health
        this.frog.isHit = gameOptions.characterHit // flag to check if player is hit
        this.frog.score = gameOptions.playerScore // score is for coins player collects
        this.frog.isFlying = gameOptions.playerFlying // flag to check if player is flying, needed in the update()
        this.frog.inFight = gameOptions.playerInFight // flag to check if player is in fight, also needed in update()
        this.frog.level = 2 // flag to check which level player is on. Used for e.g., music and enemy animations


        this.enemy = this.physics.add.sprite(game.config.width / 1.2, this.worldBounds.height - 3800, 'enemyIdleRight').setScale(3) // this.worldBounds.height-100
        this.enemy.anims.play('enemyIdleLeft')
        this.enemy.body.setOffset(20,35)
        this.enemy.body.gravity.y = gameOptions.enemyGravity
        this.enemy.setCollideWorldBounds(true) // player cannot go over the worldbounds


        // enemy characteristics
        this.enemy.health = gameOptions.enemyHealth
        this.enemyisHit = gameOptions.enemyHit
        this.enemy.attacking = false


        this.coins = this.physics.add.group({
        })


        this.coinCount = 0
        let x_c = 0, y_c = this.worldBounds.height-150
        while (y_c > 450) { // create(x-cordinate, y-cordinate, item) when going up until y coordinate(?) meets its limit
            x_c = Phaser.Math.Between(0,game.config.width)


            let coin = this.coins.create(x_c, y_c, 'coin')
            coin.play("coinAnim")
            coin.setCollideWorldBounds(true)
       
            y_c = y_c - 140 - 50 * Math.random()
            this.physics.add.overlap(this.frog, coin, collectCoin, null, this)
            this.coinCount++
            if (this.coinCount == 20) {
                break
            }
        }


        this.collectHearts = this.physics.add.group({
        })
        let x_h = 0, y_h = this.worldBounds.height-1000
        while (y_h > 100) { // create(x-cordinate, y-cordinate, item) when going up until y coordinate(?) meets its limit
            x_h = Phaser.Math.Between(0,game.config.width)


            let heart = this.collectHearts.create(x_h, y_h, 'heart').setScale(2)
            heart.setOffset(-8,-8) // setting heart in the middle of the hitting box
            heart.play("heart")
            heart.setCollideWorldBounds(true)
       
            y_h = y_h - 300 - 200 * Math.random()
        }


        let x_fb = 0, y_fb = this.worldBounds.height-1000
        while (y_fb > 600) { // create(x-cordinate, y-cordinate, item) when going up until y coordinate(?) meets its limit
            x_fb = Phaser.Math.Between(0,game.config.width)


            let bonus = this.coins.create(x_fb, y_fb, 'flightBonus').setScale(0.3) // adding coins on platforms
            bonus.setCollideWorldBounds(true)
       
            y_fb = y_fb - 800 - 500 * Math.random()
            this.physics.add.overlap(this.frog, bonus, flightBonusAction, null, this)
        }


        // colliders / overlaps
        this.physics.add.collider(this.frog, this.cityGround)
        this.physics.add.collider(this.frog, this.cityPlatforms)
        this.physics.add.overlap(this.frog, this.spaceShips, playerHit, null, this)
        this.physics.add.overlap(this.frog, this.collectHearts, collectHeart, null, this)
       
        this.physics.add.collider(this.frog, this.enemy)
        this.physics.add.collider(this.frog, this.battleGround)
        this.physics.add.collider(this.enemy, this.battleGround)


        this.cameras.main.startFollow(this.frog, false, 0.09, 0.09) // reference: https://photonstorm.github.io/phaser3-docs/Phaser.Cameras.Scene2D.Camera.html
        this.cameras.main.setDeadzone(game.config.width, game.config.height/2) // cameras start following the frog after it has passed the first half of the start screen




        // UI texts like amount of coins and score and health
        this.heart1 = this.add.image(game.config.width/1.05, game.config.height/25, 'hearts').setScale(1).setVisible(true).setScrollFactor(0)
        this.heart2 = this.add.image(game.config.width/1.1, game.config.height/25, 'hearts').setScale(1).setVisible(true).setScrollFactor(0)
        this.heart3 = this.add.image(game.config.width/1.15, game.config.height/25, 'hearts').setScale(1).setVisible(true).setScrollFactor(0)
        this.frog.hearts = [this.heart1, this.heart2, this.heart3]


        this.scoreText = this.add.text(game.config.width/1.23, game.config.height/12, "0" + "/" + this.coinCount, {fontSize: "30px", fill: "#000000"}).setVisible(true).setScrollFactor(0).setColor('white')


        this.coinImage = this.add.sprite(game.config.width/1.05, game.config.height/10, 'coin').setScrollFactor(0).setScale(2)
        this.coinImage.play("coinAnim")
    }


    update() {
        this.cityPlatforms.children.iterate(function(platform) { // moving the platforms
            if (platform.body.velocity.x == 0) {
                platform.setVelocityX(Phaser.Math.Between(70,200)) // if the platform is not moving, added this check because if character got in between the border and platform the platform stopped moving
            }


            if (platform.body.velocity.x < 0 && platform.x <= 40) { // if platform is moving to th§e left and the x location of it is less or same as 0
                platform.setVelocityX(Phaser.Math.Between(70,200)) // change direction to right
            } else if (platform.body.velocity.x > 0 && platform.x >= game.config.width-40) {
                platform.setVelocityX(-Phaser.Math.Between(70,200)); // change direction to left
            }


        }, this)


       
        this.spaceShips.children.iterate(function(spaceShip) { // moving the spaceship and checking collisions between current spaceship and player
            if (spaceShip.body.velocity.x == 0) {
                if (spaceShip.texture.key === "spaceShipRight") {
                    spaceShip.body.velocity.x = -200
                    spaceShip.setTexture("spaceShipLeft")
                } else {
                    spaceShip.body.velocity.x = 200 // change direction to right
                    spaceShip.setTexture("spaceShipRight")
                }
               
            }
            // movements of spaceships
            if (spaceShip.body.velocity.x < 0 && spaceShip.x <= 0) {
                spaceShip.body.velocity.x = 200 // change direction to right
                spaceShip.setTexture("spaceShipRight")
            } else if (spaceShip.body.velocity.x > 0 && spaceShip.x >= this.worldBounds.width) {
                spaceShip.body.velocity.x = -200; // change direction to left
                spaceShip.setTexture("spaceShipLeft")
            }
        }, this)


        if (!this.frog.isHit && this.frog.health > 0) {
           
            if (this.cursors.up.isDown && this.frog.body.touching.down) {
                this.frog.body.velocity.y = -gameOptions.characterGravity / 1.4
                this.frog.anims.play("frog_jump", true)
                const jump = this.sound.add('jump')
                jump.play()
            }


            if (this.frog.body.velocity.y < 0 && !this.frog.body.touching.down) {
                this.frog.anims.play("frog_jump", true)
            } else if (this.frog.body.velocity.y > 0 && !this.frog.body.touching.down) {
                this.frog.setTexture('fall', 0)
            }
   
            if (this.cursors.right.isDown) {
                this.frog.body.velocity.x = gameOptions.characterSpeed
                this.frog.anims.play('frog_run_right', true)
            } else if (this.cursors.left.isDown) {
                this.frog.body.velocity.x = -gameOptions.characterSpeed
                this.frog.anims.play('frog_run_left', true)
            } else {
                this.frog.body.velocity.x = 0
                this.frog.anims.play("frog_idle", true)
            }


            if (this.frog.inFight) {
                if (!this.enemy.isHit) {
                    if (Phaser.Math.Distance.BetweenPoints(this.frog, this.enemy) > 120) {
                        this.enemy.attacking = false
                        bossFightLogic2(this, this.frog, this.enemy)
                    }




                    if (this.enemy.anims.getName() !== 'enemyRunLeft' && this.frog.x < this.enemy.x) {
                        //console.log("tuleeko tänne", this.enemy.body.velocity.x)
                        this.enemy.anims.play('enemyRunLeft')
                    } else if (this.enemy.anims.getName() !== 'enemyRunRight' && this.frog.x > this.enemy.x) {
                        this.enemy.anims.play('enemyRunRight')
                    }
                   
               
                    if (Phaser.Math.Distance.BetweenPoints(this.frog, this.enemy) <= 120 && this.frog.y > this.enemy.y) {


                        this.enemy.attacking = true
                        this.enemy.body.velocity.x = 0
                        this.enemy.body.velocity.y = 0


                        if (this.frog.x > this.enemy.x && this.enemy.anims.getName() !== 'enemyAttackRight') {
                            this.enemy.anims.play('enemyAttackRight')
                        } else if (this.frog.x < this.enemy.x && this.enemy.anims.getName() !== 'enemyAttackLeft') {
                            this.enemy.anims.play('enemyAttackLeft')
                        }
                    }


                    if (this.enemy.body.touching.up && this.physics.collide(this.frog, this.enemy)) { // if player jumps on top of enemy it will get hit
                        this.enemy.body.velocity.x = 0
                        this.enemy.anims.stop()
                        enemyHit(this.enemy, this.frog, this)
                    } else if (this.enemy.attacking && !this.enemy.body.touching.up) {
                        playerHit.call(this, this.frog, this.enemy)  
                    }
                } // if enemy is hit
               
            } // if player in fight


            if (this.frog.body.y <= 330 && this.frog.body.touching.down && !this.frog.inFight) {
                startBossFight(this.frog, this.enemy, this)
            }
        }// if frog is hit
    }
}














class PlayGame extends Phaser.Scene { // ensimmäisen tason pelin toiminnallisuuksia
   
    constructor () {
        super({key: 'playgame'});
    }
   
    preload() { // loading the assets


        // platforms and grounds on which the characters can stand on and interact with
        this.load.image('tileSet', "assets/Free/Terrain/GrassTerrain(16x16).png", {frameWidth: 16, frameHeight: 16})
        this.load.image("grassPlatform", "assets/platform/Pads/Pad_04_1.png")
        this.load.image("cloudPlatform", "assets/platform/cloudPlatform.png")
        // background assets
        this.load.image("clouds", "assets/background/clouds.png")
        this.load.image("rock", "assets/background/rocktile.png")


        // frog asset
        this.load.spritesheet('idle', 'assets/Free/Characters/Frog/Idle(32x32).png', {frameWidth: 32, frameHeight: 32})
        this.load.spritesheet('runRight', 'assets/Free/Characters/Frog/Run(32x32).png', {frameWidth: 32, frameHeight: 32})
        this.load.spritesheet('runLeft', 'assets/Free/Characters/Frog/Run(32x32)_left.png', {frameWidth: 32, frameHeight: 32})
        this.load.spritesheet('jump', 'assets/Free/Characters/Frog/jump1.png', {frameWidth: 32, frameHeight: 32})
        this.load.spritesheet('hit', 'assets/Free/Characters/Frog/Hit(32x32).png', {frameWidth: 32, frameHeight: 32})
        this.load.spritesheet('fall', 'assets/Free/Characters/Frog/fall2.png', {frameWidth: 32, frameHeight: 32})


        // enemies
        this.load.spritesheet('plant_idle', "assets/enemies/Plant/Idle(44x42).png", {frameWidth: 44, frameHeight: 42})
        this.load.image('plant_bullet', 'assets/enemies/Plant/Bullet.png')
        this.load.spritesheet('plant_hit', 'assets/enemies/Plant/Hit(44x42).png', {frameWidth: 44, frameHeight: 42})
        this.load.spritesheet('plant_attack', 'assets/enemies/Plant/Attack(44x42).png', {frameWidth: 44, frameHeight: 42})
        this.load.spritesheet('plant_attack_right', 'assets/enemies/Plant/AttackRight(44x42).png', {frameWidth: 44, frameHeight: 42})


        this.load.spritesheet('bird', 'assets/enemies/birdSprite2.png', {frameWidth: 16, frameHeight: 16})


        // hearts for player and enemy
        this.load.image('hearts', 'assets/free/Characters/Heart/heart3.png', {frameWidth: 16, frameHeight: 16})
        this.load.spritesheet('collectHearts', 'assets/free/Characters/Heart/collectHeart.png', {frameWidth: 17, frameHeight: 17})
        this.load.image('enemyHearts', 'assets/free/Characters/Heart/enemy_heart.png', {frameWidth: 16, frameHeight: 16})


        // bonus items
        this.load.spritesheet('coin', 'assets/platform/Bonus_items/coin16x16.png', {frameWidth: 16, frameHeight: 16})
        this.load.image('flightBonus', 'assets/platform/Bonus_items/Flight_Bonus_01.png')


        // audios for functions
        this.load.audio('jump', "assets/audio/jump.mp3")
        this.load.audio('ouch', "assets/audio/ouch.mp3")
        this.load.audio('death', "assets/audio/gameOver.mp3")
        this.load.audio('coin', "assets/audio/collectcoin.mp3")
        this.load.audio('flightBonus', "assets/audio/flightBonus.mp3")
    }




    create() { // creating everything we will use in the game (animations, keyboard etc
        this.physics.world.setBounds(0, 0, 640, 4000) // world height is 4000 pixls
        this.worldBounds = this.physics.world.bounds
        this.cursors = this.input.keyboard.createCursorKeys() // initializing the keyboard
        game.input.keyboard.manager.enabled = true
       
        for (let i = 0; i < 8; i++) {
            this.add.tileSprite(330,  this.worldBounds.height/2, 640, this.worldBounds.height+1000, 'clouds') // syntax: tileSprite(x, y, width, height, textureKey, frame) (800,600)
        }
        this.rock = this.add.tileSprite(320, this.worldBounds.height+200, game.config.width*2, 400, 'rock')


        this.battleGround = this.add.tileSprite(320, 400, game.config.width, 49, 'cloudPlatform')
        this.physics.world.enable(this.battleGround)
        this.battleGround.body.setImmovable(true)
        this.battleGround.body.allowGravity = false
        this.battleGround.body.checkCollision.down = false


        this.ground = this.add.tileSprite(320, this.worldBounds.height, game.config.width, 49, 'tileSet') // the bottom ground
        this.physics.world.enable(this.ground)
        this.ground.body.setImmovable(true)
        this.ground.body.allowGravity = false




        this.basicPlatforms = this.physics.add.group({
            immovable: true, // the platforms won't move if the player touches them
            allowGravity: false // normal platforms won't fall down
        })


   
        // 1st boss enemy
        this.anims.create({
            key: 'plantIdle',
            frames: this.anims.generateFrameNumbers('plant_idle', {start: 0, end: 10}),
            frameRate: 20,
            repeat: -1
        })
        this.anims.create({
            key: 'plantHit',
            frames: this.anims.generateFrameNumbers('plant_hit', {start: 0, end: 4}),
            frameRate: 15,
            repeat: -1
        })
        this.anims.create({
            key: 'plantAttackLeft',
            frames: this.anims.generateFrameNumbers('plant_attack', {start: 0, end: 7}),
            frameRate: 10,
            repeat: -1
        })
        this.anims.create({
            key: 'plantAttackRight',
            frames: this.anims.generateFrameNumbers('plant_attack_right', {start: 0, end: 7}),
            frameRate: 15,
            repeat: -1
        })


        // frog
        this.anims.create({
            key: 'frog_idle',
            frames: this.anims.generateFrameNumbers("idle", {start: 0, end: 7}),
            frameRate: 20,
            repeat: -1
        })
        this.anims.create({
            key: 'frog_run_left',
            frames: this.anims.generateFrameNumbers('runLeft', {start: 0, end: 11}),
            repeat: -1
        });
        this.anims.create({
            key: 'frog_run_right',
            frames: this.anims.generateFrameNumbers('runRight', {start: 0, end: 11}),
            repeat: -1
        })
        this.anims.create({
            key: 'frog_jump',
            frames: this.anims.generateFrameNumbers('jump', {start: 0, end: 1}),
            repeat: -1
        })
        this.anims.create({
            key: 'frog_hit',
            frames: this.anims.generateFrameNumbers('hit', {start: 0, end: 6}),
            frameRate: 10
        })


        // bird anims
        this.anims.create({
            key: 'birdFlyLeft',
            frames: this.anims.generateFrameNumbers('bird', {start: 26, end: 33}),
            frameRate: 10,
            repeat: -1
        })
        this.anims.create({
            key: 'birdFlyRight',
            frames: this.anims.generateFrameNumbers('bird', {start: 9, end: 15}),
            frameRate: 10,
            repeat: -1
        })


        // item animations
        this.anims.create({
            key: 'coinAnim',
            frames: this.anims.generateFrameNumbers('coin', {start: 0, end: 14}),
            frameRate: 10,
            repeat: -1
        })
        this.anims.create({
            key: 'heart',
            frames: this.anims.generateFrameNumbers('collectHearts', {start: 0, end: 3}),
            frameRate: 10,
            repeat: -1
        })
       


        // reference for getting the platforms be quite evenly but a bit randomly apart from each other: https://stackoverflow.com/questions/26648207/placing-platforms-randomly-in-world-with-phaser
        let x = 0, y = this.worldBounds.height-200 // y is the starting point for the first platform
        while (y > 500) { // create(x-cordinate, y-cordinate, item) when going up until y coordinate(?) meets its limit
            x = Phaser.Math.Between(0,game.config.width)


            let platform = this.basicPlatforms.create(x, y, "grassPlatform").setScale(0.2)
            platform.body.velocity.x = Phaser.Math.Between(70,200) // random speed for platforms
            platform.refreshBody().body.checkCollision.down = false // ability to jump through platforms but stand on them, reference: https://cedarcantab.wixsite.com/website-1/post/one-way-pass-through-platforms-in-phaser-3-sprites
            platform.setFrictionX(1) // making the player ride with the platform, reference: https://labs.phaser.io/edit.html?src=src/physics/arcade/friction.js&v=3.60.0


       
            y = y - 100 - 50 * Math.random(); // the platforms will be 100 to 150 pixels apart
        }


       
        // adding the characters to the world
        this.frog = this.physics.add.sprite(game.config.width / 2, this.worldBounds.height-100, 'frog_idle').setScale(1.5) // this.worldBounds.height-100
        this.frog.anims.play('frog_idle')
        this.frog.body.gravity.y = gameOptions.characterGravity
        this.frog.body.bounce.y = 0.2


        // main character characteristics
        this.frog.health = gameOptions.characterHealth
        this.frog.isHit = gameOptions.characterHit
        this.frog.score = gameOptions.playerScore
        this.frog.isFlying = gameOptions.playerFlying
        this.frog.inFight = gameOptions.playerInFight
        this.frog.level = 1




        // adding birds that fly in the game and gamer has to avoid them
        this.birds = this.physics.add.group({
...

This file has been truncated, please download it to see its full contents.

Credits

Lauri Inkilä
1 project • 1 follower
Contact

Comments

Please log in or sign up to comment.