Jump to content

Need a simple demo for switching state with Phaser and JS


Recommended Posts

Hello everyone,


I'm trying to make a simple title screen with Phaser and javascript, it works, but I don't know how to switch from one state to another. For example, when player click 'New Game' button, the screen changes from title state to character selection state.


I'm much appreciated if someone show me a simple demo.


Thank you and sorry for my bad english  :D.

Link to comment
Share on other sites

Would have appreciated an example like this in the forum, so I will paste my approach:
This code is for version 0.9.5 so maybe you will need to modify it to fit the new version. 
I hope it is usefull to you.

    var kGAME_SCALE_FACTOR = 2;    var kSCREEN_WIDTH      = 320;    var kSCREEN_HEIGHT     = 240;     var __extends = this.__extends || function (d,  {        function __() { this.constructor = d; }        __.prototype = b.prototype;        d.prototype = new __();    };     //--    var fnMainGame = (function (base) {            __extends(gameName, base);         function gameName(e) {            base.call(this, e);                }                // ... DEFINE HERE YOUR GAME LOGIC ...                return gameName;    })(Phaser.State);     //--    var fnPreloader = (function (base) {        __extends(loadScreen, base);         function loadScreen(e) {            base.call(this, e);        }                loadScreen.prototype.init = function () {            this.logo = this.createSprite(0, 0, "preloader");            this.logo.x    = this.stage.centerX - (this.logo.bounds.width * 0.5);            this.logo.y    = this.stage.centerY - (this.logo.bounds.height * 0.5);                        this.loadBar  = this.createSprite(this.logo.x, this.logo.y + this.logo.bounds.height, "loadBar");            this.loadBar.width  = 0;                        // ... LOAD HERE WHAT YOUR GAME NEEDS ..            this.loader.addTextureAtlas('id_atlas', 'graphics/img1.png', 'graphics/tiles.json');            this.loader.addTextFile('id_file', 'map/map00.json');            this.loader.addImageFile('id_image', 'graphics/img2.png');                        this.loader.load(this.fileLoaded);        };        loadScreen.prototype.fileLoaded = function (progress, previousKey, success) {            this.loadBar.width = (this.logo.width / 100) * progress;        };        loadScreen.prototype.create = function () {            this.game.switchState(gameObject.MainGame);        };        return loadScreen;    })(Phaser.State);     //--    var fnBoot = (function (base) {        __extends(bootScreen, base);         function bootScreen(e) {            base.call(this, e);        }                bootScreen.prototype.init = function () {            // Initialize the stage            this.stage.maxScaleX = kSCREEN_WIDTH  * kGAME_SCALE_FACTOR;            this.stage.maxScaleY = kSCREEN_HEIGHT * kGAME_SCALE_FACTOR;            this.stage.scaleMode = Phaser.StageScaleMode.SHOW_ALL;                        this.loader.addImageFile("preloader", "graphics/load.png");            this.loader.addImageFile("loadBar", "graphics/loadBar.png");            this.loader.load(this.fileLoaded);        };        bootScreen.prototype.create = function () {            this.game.switchState(gameObject.Preloader);        };        return bootScreen;    })(Phaser.State);     // Create the game object that holds the different game states    var gameObject = {};    gameObject.Preloader = fnPreloader;    gameObject.Boot      = fnBoot;    gameObject.MainGame  = fnMainGame;        // Load the first state    window.onload = function () {        var myGame = new Phaser.Game(this, 'game', kSCREEN_WIDTH, kSCREEN_HEIGHT);        myGame.switchState(gameObject.Boot);    };
Link to comment
Share on other sites

Thank you, rich, I tried but I there isn't game.switchState() function  :(


I'm using version 1.00JS.


That would be why it didn't work then :)


In 1.00JS you do:


game.state.add(key, state, autoStart);


Where "key" is a reference (like "MainMenu") and "state" is the State object. This can be an instance of Phaser.State or just a plain JS object.


You can add multiple states when your game boots if you like (just make sure autoStart is false, the default is 'true') and then start them with game.state.start("key")

Link to comment
Share on other sites

Thank rich, I did:


game.state.start('key', true, true) ;


but it didn't clear the sprites from the previous state, what's wrong with my code?  :(

<!DOCTYPE HTML><html><head>    <title>phaser.js - a new beginning</title>    <?php    require('js.php');    ?></head><body><input type="button" id="menu" value="Main Menu"/><input type="button" id="select" value="Level Select"/><br><script type="text/javascript">    (function () {        var mainMenu = {            preload: function () {                game.load.image('nocooper', 'assets/pics/1984-nocooper-space.png');            },            create: function () {                var nocooper = game.add.sprite(10, 10, 'nocooper');            }        }        var levelSelect = {            preload: function () {                game.load.image('touhou', 'assets/pics/aya_touhou_teng_soldier.png');            },            create: function () {                var touhou = game.add.sprite(10, 10, 'touhou');            }        }        var game = new Phaser.Game(640, 480);        game.state.add('menu', mainMenu, true);        game.state.add('select', levelSelect);        var b1 = document.getElementById('menu').onclick = function () {            game.state.start('menu', true, true);        };        var b2 = document.getElementById('select').onclick = function () {            game.state.start('select', true, true);        };    })();</script></body></html>
Link to comment
Share on other sites

There's no support for 'persistent' states at the moment, sorry - but the more I look at it, the more useful I know it will be, so I plan on bumping it up the todo list. I suspect you may need 2 things:


1) Non-destructive swapping of states. So swapping to a State without destroying the current one. Your Pause screen is a good example of this. Although when you swap back to a non-destroyed state it ought to bypass 'preloader' entirely and probably even 'create' actually. Perhaps it needs a startup function? Open to ideas.


2) Simultaneously running states. So literally having 2 or more states running in sequence. The issue with this is that there is only one central display list, it's not state specific. So a background running state could add a sprite that appears on-top of whatever the top-most state might be doing. I don't think this matters though. It means you could have a UI state controlling buttons, icons, etc and a Game state, and maybe a Shop state too for an in-game shop, all updating in sequence every frame. It's up to the developer to be careful to control which state owns which objects.

Link to comment
Share on other sites

What about for example being able to have a pause screen in the middle of the screen but that doesn't cover up all the game. Could it be possible to make it so you can have 2 boolean, one to tell if the state should be destroyed, and another optional one to stop update being called for the state if you decide not to destroy it. This would be really useful to make all kind of rpg styles menus or even small minigame. Not sure if input events could be stopped for objects belonging to the unactive state thought.

Link to comment
Share on other sites

Hmm it's not quite as simple as that though - Phaser has a global tween, sound and physics manager (and other subsystems), they are not State specific. So parallel states would all share the same subsystems. This means that displaying a pause menu over a game, but actually literally 'pausing' the game state, would be impossible without each state having its own set of subsystems (or each subsystem being changed to accept state values with every object, but then I'd have to do state object checks for every single object, in every system, every frame - which seems nuts really).


Open to suggestions on how to achieve this, but I'm leaning more towards allowing simultaneous states but if you want to pause something in one, it's your responsibility to do that.

Link to comment
Share on other sites

I think that is a good solution once you take those subsystem problems into account. Let the user worry about pausing animations once their state is exited. In fact sometimes u might want to keep some animations going for effect, or animate things out etx.

The way I usually do it in my games is have 3 properties:


Previous state

Next state.

Which have 4 main methods





Only the current state has its update method called.

When changeState is called the old previous state has destroy called and the current state has onExit called and is set to the new previousState

OnExit a state can remove input handlers or stop animations it wants to, that it can readd in OnEnter. Kind of like the ios model for view controllers

Just my two cents on it.

(Typed from phone excuse typos :)

Link to comment
Share on other sites

  • 3 months later...

Is it possible that each state can have an "initialized" flag that becomes set after the initial preload/create? That way when a new state is called in, it can preload/create, and when an old state is called in it can just go straight back to "update" loop?


That would be nice :). That way each state can pause/resume without having to preload/create, essentially restarting every time it becomes the current state.

Link to comment
Share on other sites

  • 11 months later...

Hi all, I know this thread is old, but hopefully I'll get a response.

I am currently building a simple sidescroller that has a Die state and a Game state. I call the Die state from Game, but then I'm not able to return to the Game state. The console gives me errors that should not be there like, 'this.state not defined'. Please help! Here is my code:



var SideScroller = SideScroller || {}; SideScroller.Game = function(){}; SideScroller.Game.prototype = {   preload: function() {       this.game.time.advancedTiming = true;     },   create: function() {     this.music = this.game.add.audio('music', 1, true);    this.music.play();    this.map = this.game.add.tilemap('level1');        //the first parameter is the tileset name as specified in Tiled, the second is the key to the asset        this.map.addTilesetImage('tiles_spritesheets', 'gameTiles');        //create layers        this.backgroundlayer = this.map.createLayer('backgroundLayer');        this.backgroundLayer2 = this.map.createLayer('backgroundLayer2');        this.blockedLayer = this.map.createLayer('blockedLayer');        this.deathLayer = this.map.createLayer('deathLayer');        //collision on blockedLayer        this.map.setCollisionBetween(1, 100000, true, 'blockedLayer');        this.map.setCollisionBetween(1, 100000, true, 'deathLayer');        //resizes the game world to match the layer dimensions        this.backgroundlayer.resizeWorld();    //create player     this.player = this.game.add.sprite(20, 215, 'player');    this.player.scale.setTo(0.5);    //enable physics on the player    this.game.physics.arcade.enable(this.player);    //player gravity    this.player.body.gravity.y = 1000;    //camera follows player    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(Phaser.Keyboard.SPACEBAR); },   update: function() {    //collision    this.game.physics.arcade.collide(this.player, this.blockedLayer, this.playerHit, null, this);    this.game.physics.arcade.collide(this.player, this.deathLayer, this.playerDie, null, this);    if(this.cursors.right.isDown) {        this.playerMoveRight();    } else if(this.cursors.left.isDown) {        this.playerMoveLeft();    } else {        this.playerStay();    }    if(this.cursors.up.isDown) {        this.playerJump();    }    if(this.spacebar.isDown) {        this.playerTransform();    }    if(this.player.y > 215) {        this.player.y = 170;    }    if(this.player.x < 5) {        this.player.x = 10;    }  },   render: function()     {         this.game.debug.text(this.game.time.fps || '--', 20, 70, "#000", "40px Courier");     },  playerTransform: function() {    if(this.player.texture == 'player') {        if(this.player.texture == 'player2') {            this.player.loadTexture('truck');        }    } else {        this.player.loadTexture('player');    }  },  playerHit: function(player, blockedLayer) {  },  playerJump: function() {    if(this.player.body.blocked.down) {        this.player.body.velocity.y -= 500;    }  },  playerMoveRight: function() {    this.player.body.velocity.x = 300;    this.player.loadTexture('player');  },  playerMoveLeft: function() {    this.player.body.velocity.x -= 20;    this.player.loadTexture('player2');  },  playerStay: function() {    this.player.body.velocity.x = 0;  },  playerDie: function() {    this.music.stop();    this.game.switchState('Die');  }};


var SideScroller = SideScroller || {}; SideScroller.Die = function(){}; SideScroller.Die.prototype = {   preload: function() {       this.game.time.advancedTiming = true;     },   create: function() {    this.endMusic = this.game.add.audio('endMusic', 1, true);    this.endMusic.play();    this.game.stage.backgroundColor = '#000';    this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;    this.scale.pageAlignHorizontally = true;    this.scale.pageAlignVertically = true;    this.scale.setScreenSize(true);    this.restart = this.game.add.text(this.game.world.centerX, this.game.world.height/4*3, 'Click to\nRestart');    this.restart.anchor.setTo(0.5, 0.5);    this.dead = this.game.add.sprite(this.game.world.centerX, this.game.world.height/4, 'gameOver');    this.dead.scale.setTo(0.5);    this.dead.anchor.setTo(0.5, 0.5);    this.restart.inputEnabled = true;    this.restart.events.onInputDown.add(this.restartGame);    this.game.camera.follow(this.dead);  },   update: function() {  },   restartGame: function() {    this.state.start('Game');  },  render: function() {   }};
Link to comment
Share on other sites


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...