Sign in to follow this  
piobug

How to refactor basic phaser code to start using prototypes?

Recommended Posts

Hi,

 

I've been building my game by following the tutorial in the official "Discover Phaser" guide, and because of that I have now one huge play.js file. I'd like to break a bit, and to adapt it to use the code from the Shoot-em-up Tutorial that uses prototypes.

 

My code 

 

game.js

var game = new Phaser.Game(640, 480, Phaser.AUTO, 'gameDiv');game.state.add('boot', bootState);game.state.add('load', loadState);game.state.add('menu', menuState);game.state.add('play', playState);// Start the 'boot' stategame.state.start('boot');

play.js

var playState = {//standard functionscreate: function() {   createPlayer();   createEnemy();   ...}update: function() {   movePlayer();   moveEnemy();   ...}//many custom functionscratePlayer: function() {//code...}movePlayer: function() {//code...}createEnemy: function() {//code...}moveEnemy: function() {//code...}

The Shoot-em-up tutorial uses one file that both contains prototypes to create objects and "regular" phaser code.

//bullet prototypesvar Bullet = function (game, key) {//code...};Bullet.prototype = Object.create(Phaser.Sprite.prototype);Bullet.prototype.constructor = Bullet;Bullet.prototype.fire = function () {//code...}Bullet.prototype.update = function () {//code...}//weapon prototypesvar Weapon = {};Weapon.SingleBullet.prototype = Object.create(Phaser.Group.prototype);Weapon.SingleBullet.prototype.constructor = Weapon.SingleBullet;Weapon.SingleBullet.prototype.fire = function () {//code... this.add(new Bullet(game, 'bullet'), true);//code...}//"regular code"var PhaserGame = function () {//code...}PhaserGame.prototype = { create: function () {//code...} update: function () {//code...}}

Should I have separate files for Bullet.js file and Weapons.js or one BulletsAndWeapons.js file?

In case of two separate files how do they reference each other?

How do I then reference and use them in play.js?

Moving on I'd like also to move all player's related function into player.js and then reference them in play.js, how should I proceed?

 

I've snooping around the internet but there are not many tutorials on how to start using prototypes in phaser, so I'd appreciate any resources to learn from.

 

Thanks

p.

Share this post


Link to post
Share on other sites

Yes, I personally think that each file should be as small as possible, and most often it will only contain a single Class. So, split big files in smaller files for dev purposes, when you release the game you can just minify all the files into a single game.min.js file

 

It's easy to reference each other, simply include the JS files in the order of inheritance or reference. So if A.js uses stuff from B.js, just include B.js before A.js.

Share this post


Link to post
Share on other sites

I use Browserify, basejs, and Grunt to make basic classes/modules in Phaser. Here is an example:

/** * @author George Frick * @version 1.0.0 * @creation 09/21/2015 *  Draw a loading screen in Phaser. Expects resources to already be loaded. */(function () {    'use strict';    var Base = require('basejs');    var LoadingScreen = Base.extend({        constructor: function (game, settings) {            if (!settings                || !settings.loading_image_key || !settings.loading_bg_color                || !settings.loading_text || !settings.loading_font ) {                throw "Loading screen is missing a required configuration field.";            }            this.game = game;            this.settings = settings;        },        show: function () {            // 1. Create solid background.            this.bgColor = this.game.add.graphics(0, 0);            this.bgColor.beginFill(this.settings.loading_bg_color);            this.bgColor.drawRect(0, 0, this.game.world.width, this.game.world.height);            this.bgColor.endFill();            // 2. Create a loading image/icon/splash            this.splashImage = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY, this.settings.loading_image_key);            this.splashImage.y -= this.splashImage.height;            this.splashImage.anchor.setTo(0.5, 0.5);            // 3. Add a progress indicator            this.progress = this.game.add.text(this.game.world.centerX, this.game.world.centerY,                this.settings.loading_text + "0%", this.settings.loading_font);            this.progress.anchor.setTo(0.5, 0.5);            this.game.load.onFileComplete.add(this.fileComplete, this);        },        destroy: function () {            this.splashImage.cropEnabled = false;            this.splashImage.destroy();            this.splashImage = null;            this.bgColor.destroy();            this.bgColor = null;            this.progress.destroy();            this.progress = null;            this.game.load.onFileComplete.removeAll();        },        fileComplete: function (progress, cacheKey, success, totalLoaded, totalFiles) {            this.progress.text = this.settings.loading_text + progress + "%";        }    });    module.exports = LoadingScreen;}());

I have a full working game example of this on GitHub:

 

https://github.com/georgefrick/PhaserJsDemoGame

 

You can pull it down and build it with Grunt, it's a full working game. Each state is made as a module, so it gives you a base to start from.

Share this post


Link to post
Share on other sites

I do something similar. One class thing per file, using browserify to create the bundle. I use babelify so I can code in ES2015. Here's a WIP game using that setup: https://github.com/drhayes/blaster

 

If you're using browserify you don't need to wrap your modules in IIFEs; browserify will do that for you.

Share this post


Link to post
Share on other sites

I do something similar. One class thing per file, using browserify to create the bundle. I use babelify so I can code in ES2015. Here's a WIP game using that setup: https://github.com/drhayes/blaster

 

If you're using browserify you don't need to wrap your modules in IIFEs; browserify will do that for you.

 

This always seems to bother people. It's just a safety habit; I expect to see an IIFE when I open a javascript file...

Share this post


Link to post
Share on other sites

Thank you all for the replies, I have a couple more questions:

 

1. I'll check the code and Browserify, basejs, and Grunt and so on... but they seem to add overhead to production (e.g.learning new tools). Why can't I just break down my huge file into smaller pieces and be done with it?

 

2. I've managed to breakdown the Shoot-em-up tutorial into files and I can shoot and switch all weapons, but bullets can't collide with my world layer.

What should I put instead of "this.bullet" to dedect collision

//in update (); game.physics.arcade.collide(this.bullet, this.layerDirt, this.destroyTerrain, null, this);
the rest of the code (working)
//create bullets in bullets.jsvar Bullet = function (game, key) {Phaser.Sprite.call(this, game, 0, 0, key);//code...};Bullet.prototype = Object.create(Phaser.Sprite.prototype);Bullet.prototype.constructor = Bullet;//weapons use bullets in weapon.jsWeapon.SingleBullet = function (game) {//code...this.add(new Bullet(game, 'bullet1'), true);}Weapon.FrontAndBack = function (game) {//code...this.add(new Bullet(game, 'bullet2'), true);}//and so on...//play.js creates weapons in create();this.weapons.push(new Weapon.SingleBullet(this.game));this.weapons.push(new Weapon.FrontAndBack(this.game));//and so on for all weapons...//play.js shoots bullets in update();if (this.spaceBarInputIsActive()) {    this.weapons[this.currentWeapon].fire(this.player); }

3. Before trying to use prototypes I was successfully creating the player and referencing to it through "this.player" in my main play.js file.

After I've moved the player code out of the main play.js file and started using prototypes this reference is not fully working (e.g. I can create a player but not move it and other part of the code don't see the reference) What am I missing?

//In player.jsvar Player = function(game) {Phaser.Sprite.call(this, game, 10, 10, 'player');//other code...};Player.prototype = Object.create(Phaser.Sprite.prototype);Player.prototype.constructor = Player;Player.prototype.move = function() {};
//in create(); in play.js this successfully creates the player but "this.player" is not usedby other parts of the codethis.player = new Player(this.game);this.add.existing(this.player);//in update(); doesn't move the playerthis.player.move();

Thanks

p.

Share this post


Link to post
Share on other sites

Great examples drhayes & george, thank you for sharing

I actually use TypeScript for Phaser currently but I may actually use your code to learn the tools (require, grunt etc) for non-Phaser purposes. Plus the behaviour stuff is something I'd wanted to look at after being advised one should "favour composition over inheritance".

Piobug , personally I would spend a day to learn those tools to help stop my code getting disorganised & unwieldy later. It's not an overhead if you then use it regularly and assists in scaling your projects up.

Share this post


Link to post
Share on other sites

Thank you all for the replies.

 

jmp909, as much I can appreciate the simplicity those tools would bring to development, I think that

 

1) there are too many of them (Grunt, Yeoman, Browserify, Require, Basejs,...) for me to evaluate them all now and guess what may or may be useful

2) automation makes it more difficult to understand how things work

 

It seems to me that for now I can solve my first problem by breaking down one huge file into smaller units. That's what I'm trying to learn now. Maybe once I have too many files I'll look into those tools. Or maybe even later.

 

I want to build and understand first and optimize and automate later. Does that make any sense or am I completely off here?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.