October 2, 2014

Tower of Fun - Part 1

TileMap and Player


This is where it really begun. Tower of Fun. Last time, I made myself a dungeon generation algorithm based on BSP trees and got it up and running on Phaser using tilemaps. Now, it’s time to really set the stage. Tower of Fun will build upon our simple dungeon generator and head to version 1, ending up something like this:

tofv1


SOURCE

Play








Game States using Phaser


If you have played games, then you would ahve noticed, that a games usually begins fancy initial credits and logos flashing, then some mysterious “Loading…” and then the main menu. You get to actually play the game where the real gameplay exists via the main menu, probably by clicking on something. Each of these phases, initial credits, Loading..., Main menu and the actual game are States of the Game. A game state describes the current phase of the game and, the game moves from one state to another when certain conditions are met. For example, the “Loading…” screen leads to the Main menu when all assets are done loading.


Phaser has a nifty way to handle game states. Here, Phaser docs on states tell you all about it. A state in phaser, on its own represents nothing. But, it’s a bundle of important Phaser core functions like preload(), create(), update() and render(). At each state, Phaser will execute those functions as it normally would. Moreover Phaser auto-destroys any content that we created during the state, so that we don’t have to do it. Hence, we can kinda look at it like a game within a game, and when certain inputs (like clicking Play) or conditions (assets are loaded) are met, the mini-game will move onto the next mini-game. Gameception!


Using Phaser states and enlisting them is as easy as it gets. As mentioned before, the State is nothing but an simple object with core functions that Phaser would call. You can enlist a state using the state.add(key, GameSateObject) and call the state using the state.start(key).




var Game = {};
Game.Preloader = function(){};
Game.Preloader.prototype = {
    preload: function() {
    }
};

Game.MainMenu = function(){};
Game.MainMenu.prototype = {
    create: function() {
    }
};

Game.Play = function(){};
Game.Play.prototype = {
    create: function() {
    },
    update: function() {
    },
    render: function() {
    },
};

var game = new Phaser.Game(800, 480, Phaser.AUTO, 'phaserCanvas');
game.state.add('Preloader' , Game.Preloader);
game.state.add('MainMenu' , Game.MainMenu);
game.state.add('Play' , Game.Play);
game.state.start('Preloader');

Tower of Fun will currently have 3 states:


Preloader
All Game assets such as sprites and tilesheets will be loaded here, and the game will move onto the next state when they are done loading. It will have minimal graphic content.
Main Menu
The main menu of the game, where the Player can start the game or check some options, maybe…
Play
The actual gameplay section. The Dungeon will be rendered using assets that were loaded during the Preloader state and the Player will be able to experience GOTY level gameplay.





Being classy


Most of the changes happen to main.js but a minor change was made to dungeon.js. The Dungeon object has now been made in to a class, so that it could be instantiated in the Game.




// Main Dungeon object
var Dungeon = function() {};
Dungeon.prototype= {





A Load in time saves nine


We create an empty object called Game, which will house all our game states. Same with Preloader. It starts off being empty and is then filled with regular Phaser core game loop functions.




// The main Game Object
// The Game!
// It shall hold all the Phaser game states
var Game = {};

// Preloader state. This where the loading screen and stuff would go... if I had one.
// Load all the assets into the cache, and onLoadComplete, run this.loadComplete
// and head to the next state.
Game.Preloader = function(){};
Game.Preloader.prototype = {
    preload: function() {
        this.game.stage.backgroundColor = '#000000';

        var style = { font: "24px Arial", fill: "white", align: "center" };
        this.add.text(game.world.centerX, game.world.centerY, "Preloading...", style);

        this.load.spritesheet('tileSheet', '../../assets/tiles1.png',32,32);
        this.load.image('player','../../assets/player_solo.png',32,32);

        this.load.onLoadComplete.add(this.loadComplete, this)
    },
    loadComplete: function() {
        this.game.state.start('MainMenu');
    }
};

You can see that the assets, tiles1.png and player_solo.png would be added to the cache. A Phaser event called onLoadComplete which is a part of the Phaser.Loader class can be used to track when the assets have been loaded. Here, I picked it from this Phaser example. It will call Game.Preloader.loadComplete() when the event is fired, which will lead to the MainMenu






What’s special on today’s Main Menu




// The state that states itself after the Preloader. The formidable MainMenu.
// There is nothing here now. Just click to Play, rendered via text
Game.MainMenu = function(){};
Game.MainMenu.prototype = {
    preload: function() {
    },
    create: function() {
        var style = { font: "24px Arial", fill: "white", align: "center" };
        this.add.text(game.world.centerX, game.world.centerY, "MainMenu\nPlay", style);
        // Click to go to the next state (Play)
        this.game.input.onDown.add(this.startGame, this);
    },
    update: function() {
    },
    startGame: function() {
        this.game.state.start('Play');
    }
};

The MainMenu state loads no asset and simply has a text indicator that says:




MainMenu
Play

You go the next, and finally interesting state when you click (anywhere in the game canvas).






Ready Player One


Finally the interesting game state. Well, the others where kinda placeholders. Phaser is capable if really cool features such as preloader bars, which I haven’t used yet (or rather didn’t know about when I wrote version 1 or 2 for that matter). The Game.Play object will have it’s own default vars and functions, like any other state. We shall use a tilesheet or 32x32 tiles instead of individual sprites, albeit still flat colored.


enter image description here


Most of rest of the code in Game.Play exactly the same as Dungeon Generator, except that part where the Dungeon class is instantiated as a local object Game.Play.dungeon. This time on, when we create the layer for the tilemap, we set the collision for any tile block with the index 0, ie: walls. That assigns these wall as impassable tiles.


        //  Creates a new blank layer and sets the map dimensions.
        this.layer0 = this.tileMap.create('layer0',this.MAP_SIZE,this.MAP_SIZE,32,32);
        this.layer0.resizeWorld();

        // Set collision on walls
        this.tileMap.setCollision(0);

The new part is where we add the Player in the create() function.

Player 1


// Add the Player sprite at the center of the first room in the room list (it could be anywhere)
        this.player = this.add.sprite(this.rooms[0].center.x*32, this.rooms[0].center.y*32, 'player');
        this.physics.arcade.enable(this.player);

        // Have the Viewport follow the Player. See how easy this is?
        this.camera.follow(this.player);

        // Graphics object. Maybe I'll need it if I want to draw things. Dunno.
        this.marker = this.add.graphics();

        // Have an object to track keyboard cursor input
        this.cursors = this.input.keyboard.createCursorKeys();

Here, we create a player sprite, starting in the center of some room and enable Phaser’s ARCADE physics on it. We also have the camere (viewport) follow the player as he moves around the world, with a single command. Lastly, to record input (arrow key presses on the keyboard) we use Phaser’s insta cursor object creation function. All of this, picked from Photon Storm’s tutorial on Phaser.


To actually do something about those cursors we need to update the update() function to poll for inputs. When a particular key press is detected, the Player’s velocity will be altered accordingly.




update: function() {
        this.physics.arcade.collide(this.player, this.layer0);

        // INPUT HANDLING
        // Reset the players velocity (movement)
        this.player.body.velocity.x = 0;
        this.player.body.velocity.y = 0;

        if (this.cursors.left.isDown) {
            //  Move to the left
            this.player.body.velocity.x = -this.PLAYER_SPEED;
        } else if (this.cursors.right.isDown) {
            //  Move to the right
            this.player.body.velocity.x = this.PLAYER_SPEED;
        }

        if (this.cursors.up.isDown) {
            // Move up
           this.player.body.velocity.y = -this.PLAYER_SPEED;
        } else if (this.cursors.down.isDown) {
            // Move down
           this.player.body.velocity.y = this.PLAYER_SPEED;
        }
    }



Start your engines


At last, put all the states together and fire up Phaser. The game will start on the Preloader and move onto the MainMenu when all assets are loaded. At this point the game looks like the Player is flying around above a sea of green, blue and gray sheets.




// Finally, instantiate Phaser with canvas dimensions of 800x480
// Assing the states to Phaser and start on the Preloader
var game = new Phaser.Game(800, 480, Phaser.AUTO, 'phaserCanvas');
game.state.add('Preloader' , Game.Preloader);
game.state.add('MainMenu' , Game.MainMenu);
game.state.add('Play' , Game.Play);
game.state.start('Preloader');

SOURCE

Play


Back to Tower of Fun

No comments:

Post a Comment

You got something to say? Wait! I need to get my microphone array online.