TaylorN Posted December 8, 2016 Share Posted December 8, 2016 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); } }; Link to comment Share on other sites More sharing options...
plicatibu Posted December 10, 2016 Share Posted December 10, 2016 You could do the following : In mini game you save the data (score, type and position of the fish,etc) and in the main state you read the storage and then you create items as needed. Link to comment Share on other sites More sharing options...
TaylorN Posted December 10, 2016 Author Share Posted December 10, 2016 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? Link to comment Share on other sites More sharing options...
plicatibu Posted December 10, 2016 Share Posted December 10, 2016 Probably your implementation of functions displayFish and addFishToInventory are incorrect. Link to comment Share on other sites More sharing options...
TaylorN Posted December 10, 2016 Author Share Posted December 10, 2016 When I run them outside of the init function, they work exactly as intended. Link to comment Share on other sites More sharing options...
samme Posted December 11, 2016 Share Posted December 11, 2016 Have a look at StateManager#setCurrentState and StateManager#clearCurrentState. `init` and `create` are run automatically each time a state is started. I’d guess that `TopDownGame.Game.prototype` is adding duplicate objects and overwriting the original references. TaylorN 1 Link to comment Share on other sites More sharing options...
TaylorN Posted December 11, 2016 Author Share Posted December 11, 2016 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. Link to comment Share on other sites More sharing options...
samme Posted December 12, 2016 Share Posted December 12, 2016 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. Tilde and TaylorN 2 Link to comment Share on other sites More sharing options...
TaylorN Posted December 22, 2016 Author Share Posted December 22, 2016 Hey @samme Thanks so much for taking the time to look at my project and contribute to it! I think I'll be taking the 2 game states route, just as a separation of concerns. Thank you again! samme 1 Link to comment Share on other sites More sharing options...
Recommended Posts