TaylorN

Question about implementing Phaser states

Recommended Posts

Hi all,

I'm trying to get a handle on using states correctly. I'm creating a fishing game, which has an over-world you walk around in, and can approach different bodies of water. Once you get near one you can press space to fish. I then start a new state, which will be a mini-game where you try to catch the fish. Then I want to return to the over-world with a successful (or not) catch.

Right now, I can start the mini-game phase (miniGame.js), passing in the fish to catch, but when I return to the overworld (Game.js), I can't display the fish or add it to the inventory, because I'm trying to do this in the init function, which requires functions that are defined later in phaser. the player character's position is also reset because create runs right after init.

I don't need to run everything in create again right? Because I've already created the map and sprites.

Looking at the docs for the phaser state manager, I'm doing:

this.state.start('miniGame', false, false, fishOnLine);

where the two booleans are for not clearing the world and not clearing the cache, I thought that this would make it easier to return to game state. The fishOnLine contains data about the fish to be caught.

After the miniGame I try to return to the Game with the following:

this.state.start('Game', false, false, caughtFish, this.fishOnLine);

caughtFish is a boolean for if the catch was successful. For now I haven't made the miniGame, and I always return it true. this.fishOnLine is the same fish data as fishOnLine from before.

But when the Game state starts, the player's position is reset, and the inventory and display functionality don't work or throw an error. Nothing happens.

What am I missing? How can I fluidly transition between two states? Most state examples show you how to add a top score to a title screen, but I need to be able to not reset the game when returning to it.

Below is my code for the two game states, the cull code can be seen here

Game.js:

var TopDownGame = TopDownGame || {};

//title screen
TopDownGame.Game = function() {};

TopDownGame.Game.prototype = {
    init: function(caughtFish, fishOnLine) {

        if (caughtFish != null || undefined && caughtFish) {
            var fish = fishOnLine;
            this.makeFlowersDance();
            console.log('caught a ' + fish.name);
            //show the fish on screen above player
            this.displayFish(fish);
            //add a copy of the fish to player's inventory
            var fishCopy = new this.Fish(fish.name, fish.size, fish.price);
            this.addFishToInventory(fishCopy);
        } else  if (caughtFish != null || undefined && !caughtFish){
            console.log('no fish, sorry man');
        }
    },
    create: function() {
        this.map = this.game.add.tilemap('beach');

        //the first parameter is the tileset name as specified in Tiled, the second is the key to the asset
        this.map.addTilesetImage('basicTiles', 'gameTiles');

        //create layers
        this.backgroundlayer = this.map.createLayer('background');
        this.blockedLayer = this.map.createLayer('blockedLayer');
        //console.log(this.blockedLayer);
        //console.log(this.blockedLayer._results);
        console.log(fishJSON);

        //create yellow flowers group
        this.yellowFlowers = this.game.add.group();
        for (var i = 0; i < 5; i++) {
            this.yellowFlowers.create(this.game.rnd.integerInRange(0, 400), this.game.rnd.integerInRange(100, 300), 'yellowFlower', 0);
        }

        this.yellowFlowers.callAll('scale.setTo', 'scale', .5, .5);
        this.yellowFlowers.callAll('animations.add', 'animations', 'dance', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 8, false);

        //create purple flower sprite
        this.purpleFlower = this.game.add.sprite(150, 240, 'purpleFlower');
        this.purpleFlower.animations.add('dance', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 8, false);
        this.purpleFlower.scale.setTo(.5, .5)

        //create fishing group
        this.fishingZones = [];
        for (var i = 0; i < this.map.objects.objectsLayer.length; i++) {
            var zone = this.createFishingTiles(this.map.objects.objectsLayer[i]);
            this.fishingZones.push(zone);
        }
        //collision on blockedLayer
        this.map.setCollisionBetween(1, 2000, true, 'blockedLayer');

        //resizes the game world to match the layer dimensions
        this.backgroundlayer.resizeWorld();

        this.game.physics.startSystem(Phaser.Physics.ARCADE);

        //Get the Hour
        this.hour = this.getTime();
        //and draw it in the top left corner
        this.getTimeText(this.hour);
        //Get Time of Day: Morning, Day or Night
        this.timeOfDay = this.getTimeOfDay(this.hour);
        //for testing only
        this.timeOfDay = "day";
        console.log(this.timeOfDay);

        //create inventory
        this.inventory = [];

        //create player
        this.player = this.game.add.sprite(100, 300, 'player');
        this.player.animations.add('right', [0, 1, 2, 3], 10, true);
        this.player.animations.add('left', [4, 5, 6, 7], 10, true);
        this.game.physics.arcade.enable(this.player);
        this.player.body.collideWorldBounds = true;

        //the camera will follow the player in the world
        this.game.camera.follow(this.player);

        //move player with cursor keys
        this.cursors = this.game.input.keyboard.createCursorKeys();
        this.spacebar = this.game.input.keyboard.addKey(32);

        this.spacebar.onDown.add(this.fishCheck, this);

    },
    createFishingTiles: function(obj) {
        var fishingTiles = new Phaser.Rectangle(obj.x, obj.y, obj.width, obj.height);
        fishingTiles.name = obj.name;
        return fishingTiles;
    },
    update: function() {

        //collisions
        this.game.physics.arcade.collide(this.player, this.blockedLayer);

        //player movement
        this.player.body.velocity.y = 0;
        this.player.body.velocity.x = 0;

        if (this.cursors.up.isDown) {
            this.player.body.velocity.y -= 50;
            this.player.facing = "up";
        } else if (this.cursors.down.isDown) {
            this.player.body.velocity.y += 50;
            this.player.facing = "down";
        }
        if (this.cursors.left.isDown) {
            this.player.body.velocity.x -= 50;
            this.player.animations.play('left');
            this.player.facing = "left";
        } else if (this.cursors.right.isDown) {
            this.player.body.velocity.x += 50;
            this.player.animations.play('right');
            this.player.facing = "right";
        } else {
            this.player.animations.stop();
        }

    },
    fishCheck: function() {
        for (var x = 0; x < this.fishingZones.length; x++) {
            //if the center of the player is in range
            if (this.fishingZones[x].contains(this.player.x + this.player.width / 2, this.player.y + this.player.height / 2)) {
                console.log('fishing ' + this.fishingZones[x].name);
                //get the fish to be caught from zone and time of day
                var fish = this.getFish(this.fishingZones[x].name, this.timeOfDay);

                //start the mini-game
                this.chanceToCatch(fish);
            }
        }
    },
    getTime: function() {
        var d = new Date();
        var hour = d.getHours();

        return hour;
    },
    getTimeText: function(hour) {
        var meridiem = "am"
        if (hour > 12) {
            hour = hour - 12;
            meridiem = "pm"
        }
        hour = hour + meridiem;

        this.style = {
            font: "12px Arial",
            fill: "white",
            wordWrap: true,
            wordWrapWidth: 100,
            align: "center",
            backgroundColor: "black"
        };

        text = this.game.add.text(0, 0, hour, this.style);
        text.fixedToCamera = true;
    },
    getTimeOfDay: function(hour) {
        console.log(hour);
        if (hour < 5) {
            return "night";
        } else if (hour >= 5 && hour < 11) {
            return "morning";
        } else if (hour >= 11 && hour < 19) {
            return "day";
        } else if (hour >= 19 && hour < 24) {
            return "night";
        }
    },
    makeFlowersDance: function() {
        this.yellowFlowers.getRandom().animations.play('dance')
        this.purpleFlower.animations.play('dance');
    },
    chanceToCatch: function(fishOnLine) {
        /*
        var num = this.game.rnd.integerInRange(0, 1);
        if(num == 0){
          return true;
        } else {
          return false;
        }
        */
        this.state.start('miniGame', false, false, fishOnLine);
    },
    getFish: function(zone, timeOfDay) {
        //zone and timeOfDay are working as a way to get into the object
        zone = zone.toLowerCase();
        console.log(fishJSON.zone[zone].time[timeOfDay]);
        return fishJSON.zone[zone].time[timeOfDay].fish[1];
    },
    displayFish: function(fish) {
        var sprite = fish.name.toString().toLowerCase();
        this.fish = this.game.add.sprite(this.player.x + 8, this.player.y - 16, sprite);
        this.fish.animations.add('wiggle', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 8, true);

        this.fish.animations.play('wiggle', 8, false, true);

    },
    addFishToInventory: function(fish) {
        this.inventory.push(fish);
        console.log(this.inventory);
        this.updateInventoryDisplay();
    },
    Fish: function(name, size, value) {
        this.name = name;
        this.size = size;
        this.value = value;
    },
    updateInventoryDisplay: function() {
        //for every item in the inventory
        for (var i = 0; i < this.inventory.length; i++) {
            //get the sprite image from the name in the inventory
            var sprite = this.inventory[i].name.toString().toLowerCase();
            // add the sprite
            var invFish = this.game.add.sprite(350, 10 * i, sprite);
            invFish.scale.setTo(.5, .5);
            invFish.fixedToCamera = true
        }
    }
}

MiniGame.js:

TopDownGame.miniGame = function(){};

TopDownGame.miniGame.prototype = {
  init: function(fishOnLine){
    this.fishOnLine = fishOnLine;
  },
  preload: function() {
    //show loading screen
    this.preloadBar = this.add.sprite(this.game.world.centerX, this.game.world.centerY, 'preloadbar');
    this.preloadBar.anchor.setTo(0.5);

    this.load.setPreloadSprite(this.preloadBar);

  },
  create: function(fishOnLine) {
    var caughtFish = true;
    this.state.start('Game', false, false, caughtFish, this.fishOnLine);
  }
};

 

Share this post


Link to post
Share on other sites

Hi @plicatibu,

Thanks for the answer! That's what I'm doing now, however something's not working. Functions written after init aren't being called in init. 

this.displayFish(fish);

and

this.addFishToInventory(fishCopy);

are both not running properly, but I'm also not getting an error

init: function(caughtFish, fishOnLine) {

        if (caughtFish != null || undefined && caughtFish) {
            var fish = fishOnLine;
            console.log('caught a ' + fish.name);

            //show the fish on screen above player
            this.displayFish(fish);

            //add a copy of the fish to player's inventory
            var fishCopy = new this.Fish(fish.name, fish.size, fish.price);
            this.addFishToInventory(fishCopy);

        } else  if (caughtFish != null || undefined && !caughtFish){
            console.log('no fish, sorry man');
        }
    },

Where am I going wrong?

Share this post


Link to post
Share on other sites

Hi @samme thanks for the reply.

Right, so since init and create are run each time, should I try to implement the miniGame within game.js and not in its own state?

I'm looking through those docs now. Thanks for the direction.

You're right about adding duplicate objects, if I run the miniGame many times over the whole game starts to chug with a dwindling framerate.

Share this post


Link to post
Share on other sites

You might find it easier to put the mini game in the same state since your update loop is pretty simple. Setting exists: false, visible: true on the player while the mini game is running might be enough.

If you use 2 states you can set and check a flag in Game#init or Game#create indicating whether it’s the state’s first run or not: https://github.com/samme/FishingGame/commit/04c32ee5025211dc5f97bd7a5d87ac5b060eb850

I think the missing displayFish was actually draw beneath the duplicate objects.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.