Jump to content

Phaser + requirejs


1-800-STAR-WARS
 Share

Recommended Posts

  • 1 month later...

After many hours tonight i get RequireJS to work with Phaser. It's a simple structure, but i'm a beginner with Phaser and RequireJs

 

This is my structure:

 

- index.html

-- js

--- main.js

--- vendor

---- require.js

---- phaser.js

--- inc

---- create.js

---- preload.js

---- update.js

 

In my main.js, i created a global object called app to stock all my global config.

var app = {}

And i create the main require

requirejs.config({  baseUrl: 'js',  paths: {    Phaser:   'vendor/phaser.min',    preload:  'inc/preload',    create:   'inc/create',    update:   'inc/update',  },});require(['Phaser','preload','create','update'], function( Phaser, preload, create, update ){  app.game = new Phaser.Game(800, 600, Phaser.AUTO, '', {preload: preload, create: create, update: update});  });

And after i create each files in the inc folder like this:

var app = app || {};define(function() {        console.log('Create');    return function(){    }});

If you need some dependencies for your modules, you can add them there. For me, i made the tutorial works very well like this. 

 

I gonna get some sleep to work with this structure tommorow!

 

If any of you have some advices, i'll be glad to optimize it!

Link to comment
Share on other sites

I got a better way to handle it with requirejs.

 

First, you have your main.js who will be the main application. Create two global variables; app and game. The first require is the core app. You have to create the Phaser.game there. The app variable is the global container.

 

var game = {},    app = {};requirejs.config({  baseUrl: 'js',  paths: {    Phaser:   'vendor/phaser.min',    Boot:   'inc/boot',    Preloader:   'inc/preloader'  },});require(['Phaser','Boot','Preloader'], function( Phaser ){  game = new Phaser.Game(800, 600, Phaser.AUTO, '');  game.state.add('Boot', app.Boot);  game.state.add('Preloader', app.Preloader);  game.state.start('Boot');});

You have to handle your app in states. In my exemple, i got the Boot state and the Preloader state. First i initialise my Boot state. Each state can be created like this:

 

app = app || {};define("Boot", ['Phaser'],  function( Phaser ) {    app.Boot= function ( game ){    };    app.Boot.prototype = {            preload: function(){},      create: function(){},      update: function(){},    }  });

You don't have to return anything, because each state is stocked in the app variable. You can access the game variable with this in your functions.

Link to comment
Share on other sites

Just as a preface to my post, I want to attach a disclaimer: while I am quite familiar with requirejs, I am still in the middle of my first Phaser project. 

 

That proposal regarding state is awesome.  I just checked out the code for the StateManager's add method and realized that it can take a constructor function.  I wasn't aware of this before.  Nice.

 

However, this is the code that I see:

else if (typeof state === 'function'){    newState = new state(this.game);}

But in your usage code, I see "game" passed in to the closure, but I don't see it added to the instance.  As it stands, it's just a constructor parameter that can only be accessed within the constructor itself.

 

This could be accessed from the methods if you created them on instantiation like

app.Boot= function ( game ){    this.preload: function(){        console.log(game);    };    this.create: function(){        console.log(game);    };    this.update: function(){        console.log(game);    };  };

Since states shouldn't be created at high rates, the overhead of instantiating each method on each individual state instantiation is negligible.

 

Alternatively, you could also simply attach it to the instance:

app.Boot= function ( game ) {  this.game = game;};app.Boot.prototype.preload = function() {  console.log(this.game);};

then freely access it from any method.

 

Also, I'm assuming that "app.Boot= {};" was a typo since Boot is reassigned on the next line, unless there is some js magic happening here that I'm not aware of.

 

 

> Create two global variables; app and game

 

You might want to be careful with this.  When you create and use things outside of requirejs, you can create huge pain in your build.

 

A good alternative to globals when using require is to create singletons.  All you have to do is return an instance of a module rather than a factory or constructor function.

 

For example, in my current set up (that is likely to change thanks to your protip, DWboutin!), I have a game singleton as a module:

 

phaser-game.js

define(function(require) {	"use strict";	var Config = require('config'),		Phaser = require('phaser'),		game = new Phaser.Game(Config.width, Config.height, Phaser.AUTO);	return game;});

And then when I use it, I can just say "var game = require('game');".  And I'm guaranteed to have the same instances everywhere.

 

Also, I'd highly recommend using the alternative syntax for require.  It makes life MUCH easier.  After a while, the pain of keeping both the array and parameter order straight can be just as bad as keeping script tags in order.

Link to comment
Share on other sites

This is great, guys, some good ideas. FWIW I did come up with something:

 

https://github.com/lewispollard/cityrogue

 

I ended up using a sort of singleton implementation using Require's exports on a lot of things and passing the state into the constructor which seems to work quite well:

define(['exports', 'phaser'], function (exports, Phaser) {    'use strict';    var instance = null;    function create (state) {        instance = new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, 'main', state);        return instance;    }    function getInstance () {        return instance;    }    exports.create = create;    exports.getInstance = getInstance;});

Invoked in the main.js file like:

var game = Game.create({preload: preload, create: create, update: update});

That way the Game module can be passed as a dependency to any other module and can call Game.getInstance() to get the initialised game object.

Link to comment
Share on other sites

  • 2 weeks later...
  • 2 months later...

Out of curiosity, what is the value proposition for using RequireJS in your projects? I am quite familiar with the API and have used it for non-game projects, but in my experience it has only proved truly useful in developing things like widgets for instance — where the module in question might not exist on page load, but gets async loaded later on to avoid making users pay a price even if they don't ever see the plugin.

In my view, if this is just a way to have cleaner syntax for module dependency management — why not use Browserify? Notwithstanding some of its problems, it gives you the node.js-esque module require directives but pulls down everything in a single file. It seems to me that for a game, since you have a 'preload' step anyways for bulky game assets and scripts, why not take this route? You avoid a lot of code smells this way and reduce request overload/congestion.

 

Alternatively, my choice has always been to concat/minify via a build script and use lexical scoping (passing deps via closure arguments) to accomplish the same type of management. Shared game state objects does help achieve this as well (example of this in my most recent effort: https://github.com/spmurrayzzz/FooFighter.js)

I'm sincerely curious as to the benefit here, hope its not parsed as being snarky. I'd love to try out a new project using RequireJS to evaluate the benefits, but I just want to understand the value-add more clearly.

Link to comment
Share on other sites

At the time I made the post, I wasn't aware of Browserify - it only really picked up in tech forums earlier this year. As you said, it's mainly for structure & organisation, forced module pattern, as well as dependency injection and the benefits that can bring in terms of reusable code. Really, that stuff just comes down to preference, and I happen to have had the most experience with requirejs. Also, require can do the same concatenation down to one file using its r.js script.

Link to comment
Share on other sites

@spmurrayzzz as Lewis said, it really just comes down to preference.  They've each got their ups and down

 

As you mentioned, Browserify's syntax is much cleaner since it's synchronous and you can just pull it down as one file and use source maps to debug.  However, this all comes with the price tag of running server side builds for every code change.  This can be overcome by a watch task (as any Sass or Coffeescript users are familiar with).  But once your project becomes larger, that time to recompile becomes larger (the app at the company I work for takes compass about 5 seconds to compile vs the instant feedback we had when we were still running Less).

 

With require, the major downside is the amount of ceremony with having to wrap all your modules in defines.  Also since it's async, the synchronous-looking syntax is still leading modules ahead of time making it impossible to conditionally load a module.  However, the upside of this is that it doesn't involve any special action on the server.  Everything can be done from your text editor and away you go.  And once you're done, you can then run your build.

 

Again, there is no real "correct" library to use.  Options exist for a reason.  Does setting up a watch task bother you?  If not, then browserify is a great option.  Does wrapping all your modules in define methods bother you?  If not, then require is a great option.

 

In the end, I don't think anyone would say either is a real issue.  It's probably just that a person perceives one path to be slightly less bumpy than the other.

Link to comment
Share on other sites

Thanks @david and @Lewis — appreciate the replies. 

I never thought about the idea that some devs would be anti-watch, but I totally understand why. In my most recent project, the grunt build takes less than 2s on average so I don't mind waiting for that to happen on every save. But at work, our JS builds take 20-30 seconds on average due to an exceedingly large code base. In light of that we made a config option that will use an index file of several script tags vs a single script tag depending on whether you're in development or production. The script dependencies are just managed in a separate JSON file.

Personally, in production, I've always believed in lowering the amount of requests as much as humanly possible to make time-to-glass the best it can possibly be. Clearly in dev this is a phantom problem. As always, its a balancing act of convenience and performance.

Thanks again for giving some clarity.

Link to comment
Share on other sites

  • 2 months later...
 Share

  • Recently Browsing   0 members

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