Jump to content

Organizing the code and few other questions


Tumetsu
 Share

Recommended Posts

In past I have developed games on Actionscript, Game Maker, C++ and various other languages. Recently I decided to jump into javascript and html5 and found Phaser. While JS in general seems rather straightforward and Phaser handy looking library, I need some clarification with some practices. While some questions are a bit more general, I'm going to work in Phaser context (which is why I posted this here).

 

1) How exactly I should organize my code during the development? I don't want to edit one huge html-file with inline js but instead separate different classes to different js-files for maintainability. After studying js, I noticed that there isn't such concept as "includes" or "imports" as in Java, Actionscript etc. Apparently I have to use some external tools to concatenate the files? If so, what is the best practice when using Phaser? Or should I just make a list of <script> tags to the index.html and try to introduce them in order they probably are going to used? That might create rather long list if each class has its own file...

 

2) I installed Brackets editor which seemed like best option for me for JS coding. I'm using JSHint to help me to learn the proper syntax & cleanliness of the code. Now, this is minor issue but I always get errors like these from js files such as load an image example:

 

 

'Phaser' is not defined. (W117) var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create });

How I should define the Phaser to avoid this error?

 

3) How much I have to worry about browser compatibility in general? Is most of the relevant stuff abstracted in Phaser? Like as long as I use the library as intended and avoid special things everything should work? Not saying that I'm not going to test my games on different browsers but I'd like to know this in advance :)

 

Thanks. Also, if you feel like this isn't Phaser relevant enough, feel free to move it to the more general board.

 

EDIT: I found this simple tutorial about how to split things to multiple code files: http://toastedware.com/?p=258 While it answered to how to split things, what confuses me a bit is how I should handle pasting them together. If I'm right, using multiple separate js-files will increase loading time of the game, so I'm not entirely convinced to just put full list of all of my classes to one long <script> tag list in the head of the html-document.

Link to comment
Share on other sites

I am new to Phaser as well, and the only method I have seen so far to load your javascript includes is to list them all in the header as separate script files. I don't think this affects the loading time too much because not all of the resources from the separate files are loading at once. You can control what resources are loaded using 'states' in the library which are like scenes for your game. Let's say you load your menu state first, your menu object would preload all assets related to the menu, and when you start your game and changes states to level1, then you are removing the previous state and loading the assets for level1. 

 

Perhaps someone with a more in depth knowledge can chime in to explain better, but I hope I got the idea across.

 

Also, if you use the canvas rendering option it appears to be supported across all major browsers and mobile browsers.

 

http://caniuse.com/canvas

Link to comment
Share on other sites

1) for development I use separate script tags to load all my files. for final deployment I use grunt to concatenate my files into a single file and minify it. using separate script tags in the HTML is really no different than a makefile that tells the compiler what files to build. yes, you have to manage the dependencies, but unless you're planning on writing hundreds of thousands of lines of javascript it's really not that hard. and if you are planning on writing that much javascript for a game, I recommend you just stop now ;) 

 

I do use a 'require' (import) method of my own devising, but only to import functionality into my top-level namespace - I don't have it do any actual file loading. it does help me keep my dependencies in order though.

 

if you're deploying as a web site/app (as opposed to a packaged mobile app, say) then you definitely want to concat and minify your code for deployment/production. I recommend using node.js. and grunt - since you're already writing javascript it makes sense to me to stick with a javascript tool. that said, yahoo's yui and google's closure can do a somewhat better job in many cases.

 

2) I don't use brackets, but for jshint you can add a .jshintrc file and add Phaser to the 'predef' section. my file for one of my projects looks something like:

{
  "predef" : [
    "console",
    "document",
    "window",
    "Phaser",
    "PIXI",
    "Float64Array"
  ]
}
 
3) worry about it. but not too much :) seriously, it depends entirely on your goals. if you want to reach every single person who uses the internet right now, then you'd better worry a lot. if you're happy to only support folks using a "modern" browser (incl iOS and android 4+), then you don't need to worry too much.
 
but either way it's best practice to run everything periodically on all your targets. 
 
Phaser (and Pixi) does take a lot of the pain out of the process (thanks Rich! and Mat!) but it doesn't mean you can just forget about it altogether. if your game pushes the envelope AT ALL, performance-wise, then you have to worry even more, because mobile platforms/browsers are not fast. even desktop-wise I find the firefox is usually much pickier than chrome and safari and will blow up on things that they just accept silently. and the perf characteristics of all three are different - different things slow them down.
 
 
hope any of that is remotely helpful. good luck!
Link to comment
Share on other sites

Thank for responses!

@Chimera

So this state thing is a part of Phaser? Interesting, I have to look into docs if I can make sense of it. Thank you for mentioning it. If anyone knows good explanation of how to use them I'd like to hear.

 

@jcs

Could you explain that require method a bit? I have seen few such kind of things in internet but haven't really studied it. Is it just a tag for separate tool (grunt?) to use while concatenating the files?

Good to know about performance. Not sure how much I have to worry about it atm, since most of my games are rather slow paced.

Link to comment
Share on other sites

If you refer to the Phaser download under resources >> project templates >> Basic, there is an example template for setting up a new game and separating your code into different files / objects. If you are familiar with scenes from flash or other frameworks then it works in a similar way. I am not clear on what resources are left over after changing states, it would seem any resources that are preloaded is persistent but any existing sprites/groups/etc are destroyed.

 

Depending on the scale of the project I am wondering whether just creating separate groups or objects would be easier to organize and create your own simple destroy method to clear the resources when removing/adding groups. That would be easier I think too that way to do transition effects like fading in the next group or sliding in from the top etc, unless the state has some sort of onEntry methods which are capable of doing this.

 

Basically I am thinking out loud lol, probably not much help!

Link to comment
Share on other sites

my version of 'require' doesn't affect script/file loading or concat'ing in any way (like something like 'require.js' does). the code is something like:

var myNamespace = function( options ){  "use strict";  var loaded = {};  var X =   {    require : function( modules )    {      if( !(modules instanceof Array)        throw new Error( "non-array passed to require()" );      for( var i = 0; i < modules.length; i++ )      {        // prevent re-load        var m = loaded[modules[i]];        if( !m )        {          m = myNamespace[modules[i] || modules[i];          if( !(m instanceof Function) )           throw new Error( "Unknown module '" + m + "' passed as module to require()" );          m( X );

a 'module' (I keep the code in it's own file, though it doesn't have to be), would look something like:

myNamespace.foobar = function( X ){  "use strict";  // add stuff to the 'main' object here  X.Foobar = function() { /* define a Foobar class */ };  X.someUsefulFunction = function(n) { };  X.someGlobalVariable = 42;};

the code that uses the namespace and modules would then be like:

"use strict";var X = myNamespace();X.require( ["foobar", "some_other_module"] );var a_foobar = new X.Foobar();X.someUsefulFunction( X.someGlobalVariable );

(this is similar, but not identical, to how libraries like jquery work)

 

the benefits of using a namespace/global object/module pattern like this are that

 

1) if you require() a module that isn't concat'd or included with a script tag you will get a handy error

2) it nicely isolates all your applications objects/code into one place

3) it lets you create multiple of your "global namespace objects" ('X' in the code above), using different modules, on the same web page

4) it lets you define data that is private to your modules (anything not added to the global object becomes, in effect, 'private')

5) it's quite flexible as far as what you can include in your global object/namespace

6) it can be extended to load modules from separate files if you later desire (but this is a large bag of worms to open - the asynchronous nature of javascript on the web makes this more complicated than you might think)

 

all that aside, there are lots of ways of organizing your code in javascript. this just happens to be one that I find useful and elegant

Link to comment
Share on other sites

@Chimera

Thanks, I'll definitely take a look into those states and try to figure out how they exactly work. The concept is familiar to me, it's really the implementation and usage which I'm not yet familiar.

 

@jcs

Thanks you for example code. Interesting pattern. Just to ensure that I figured it out correctly: you basically create a namespace function/class which has the require function. This function then checks if the required module is appropriate. I'm not sure if I understand what's happening here though:

// prevent re-load        var m = loaded[modules[i]];        if( !m )        {          m = myNamespace[modules[i] || modules[i];          if( !(m instanceof Function) )           throw new Error( "Unknown module '" + m + "' passed as module to require()" );          m( X );

What exactly goes to the "m" variable in first line? A module name if it exists in the loaded array? Otherwise "m" is going to be undefined and the if-statement is executed. I'm not sure what happens next. What is the difference between myNamespace[modules and modules? Where do myNamespace[...] refer?

Error check looks straightforward. m( X ) is used to pass the namespace object to the module?

 

In the module file you then inject module's functions to the specified namespace by using provided X pointer. In final use case the user of the namespace asks the namespace to provide requested functions/classes by X.require which then retrieves missing required classes and adds them to the namespace.

 

Am I right? It seems rather clever system. Is there any wide used name for this kind of pattern?

Link to comment
Share on other sites

Since we are on the topic, can anyone see any issue why this example is not loading the sprite? The image shows up under network in developer tools, but shows pending. There are no errors from what I can see. Just trying a different method to organize the code and hit a snag with the very first test :P.
 
 
Index.html

<!DOCTYPE HTML><html lang="en"><head>  <title> Starlight </title>  <meta charset="UTF-8" />  <script type="text/javascript" src="phaser.min.js"></script>  <script type="text/javascript" src="menu.js"></script>  <style type="text/css">    body {      margin: 0 auto;    }    #container {      margin-top: 2em;      margin-left: auto;      margin-right: auto;      width: 800px;      height: 800px;    }  </style></head><body>  <div id="container">  <script type="text/javascript">    window.onload = function() {      var game = new Phaser.Game(800, 800, Phaser.AUTO, 'container',      { preload: preload, create: create, update: update });      function preload() {        menu = new Menu(game);        menu.preload();      }      function create() {        menu = new Menu(game);        menu.create();      }      function update() {        menu = new Menu(game);        menu.update();      }          };  </script>  </div></body></html>

 
menu.js

Menu = function(game) {  this.game = game;};Menu.prototype = {  preload: function() {    this.game.load.image('main-background', 'assets/menu/nebula-800x800.png');  },  create: function() {    this.game.add.sprite(800, 800, 'main-background');  },  update: function() {  },};

View example here

http://geared.net16.net/games/starlight/index.html

 

 

Link to comment
Share on other sites

@tumetsu: in the first line you quoted, the module name is looked-up in the 'loaded' object (which is just a cache kept for this purpose) and assigned to 'm'. if it exists, we've already loaded it and can just use it, otherwise we need to load it.

 

the myNamespace[...] look-ups are looking for a function of the given name in the namespace object - modules are defined by functions that are added to the namespace. see the first line of the module example: 'myNamespace.foobar = function(){ ..' - this is defining a module named foobar in the namespace object. so later if we look for the module with 'myNamespace['foobar']', we'll find it. if we don't find it then we'll get a javascript 'undefined' object back. if it doesn't find it, the code in question then assigns 'modules' to 'm' instead, which is just the name of the module - this is just a convenience for putting the name into the error message. we could easily have just done

m = myNamespace[i];if( !m )  throw new Error( "unknown module '" + module[i] + ''' passed to require()" );

instead. (sorry, that's all a bit harder to explain that it actually sounds. I hope any of that made sense!)

 

the rest of your thinking is correct. 'm(X)' calls the module function with 'X', the "global namespace object". the module function then adds its functionality, properties etc onto 'X', which can then be accessed by the client application.

 

I don't know if there is a name for this exact namespace/module pattern. (I'm sure there is, but I haven't heard it). there are lots of variations on namespaces and modules with javascript. because the language is so flexible it has led to a profusion of different but similar patterns. ("Learning Javscript Design Patterns" from O'Reilly press catalogues lots of them if you're interested).

Link to comment
Share on other sites

EDIT: I found this simple tutorial about how to split things to multiple code files: http://toastedware.com/?p=258 While it answered to how to split things, what confuses me a bit is how I should handle pasting them together. If I'm right, using multiple separate js-files will increase loading time of the game, so I'm not entirely convinced to just put full list of all of my classes to one long <script> tag list in the head of the html-document.

You're right about the loading time increase, and maybe I have a solution to you.

 

I don't know if you still need this answer but I tought it would be relevant, you can minify your code before deploying it, in this site: http://jscompress.com/

You can upload your files and the site gives you the resulting code, just paste that code in an .js file and import that resulting file in the <script> tag.

You can also put your files and phaser's files together doing this. If you plan to try it, I recommend you use phaser.min.js for it will take less time to minify.

And about the Brackets error, I have it here too, and he's only a talker xD Doesn't actually affect anything in your game.

 

Link to comment
Share on other sites

@jcs

Thanks for elaboration. I think I got it now :)

 

@CaueCR

Yeah, after posting this thread I found the minifying concept. About the Brackets error, I knew it wouldn't affect the game but I like to keep my error-log in check so that when something important comes up I notice it :) jcs' jshint conf-example fixed the problem for me.

Link to comment
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...
 Share

  • Recently Browsing   0 members

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