How can you create a modular, maintainable, and standardized code project (especially in messy JS land)? One great way is to use a generator to make an outline for you. In this article we will cover the project's generator and how its pieces interact with one another. Check out the official generator documentation for an alternate, up-to-date explanation.
Install Node, NPM, and our generator with NVM.
1 2 3 4 5 6 7 8 9 10 11 12 curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash # Install NVM export NVM_DIR="/home/james/.nvm" # This loads nvm in current terminal [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm in current terminal command -v nvm # if installation worked, "nvm" will be printed nvm install node # Install Node & NPM nvm use default # use NVM's node - just in case a system installation already exists nvm alias default node # make a reference to this node version in the ~/.bashrc nvm which current # location of the current version of node - should have ".nvm" in the name # Install global NPM packages - these will not need to go into the local node_modules folder of your project npm -g install yo # Framework for generators, helps devs quickly build high quality web apps npm -g install generator-phaser-plus # Phaser.io project generator npm -g install cordova # Compile JS apps to hybrid mobile apps
1 2 3 mkdir birdu && cd $_ # Make a folder and enter into it yo phaser-plus # Generate! npm install # Once done with prompts, install dependencies
The generator will ask for your game's name ("Birdu"), a description ("Best game ever made"), desired physics system (Arcade Only), and a dev preference (Babel & ECMASCript modules). For physics, Phaser supports Arcade, Ninja, and P2. In that order they increase in customizability, but decrease in performance. Your physics system will vary based upon your goals and desired gameplay. Birdu is simple. It treats all the birds as rectanges and collision is a simple (and fast) AABB. As you level up in development skill, you may need a different physics engine.
The "develop preference" question refers to how you choose to manage JS dependencies in your project. CommonJS uses "require" to import and use discrete JS modules, while the 2015 ECMAScript paradigm uses "import" (and Babel to make your code backwards compatible). ECMA is newer and built-in to the language, so we'll be using that.
Anyways, the generator takes your answers, inserts the title & description text in the desired places, downloads & integrates your physics engine (it's modular), and starts the long process of downloading all your node dependencies to the node_modules folder. The final output will look something like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 ├── gulpfile.js #Gulp code responsible for building project │ │ │ ├── lib #Specific module configuration │ │ └── bundler.js #Browserify/Watchify support module │ │ │ ├── tasks #Gulp execution tasks/commands │ │ ├── dev.js #Dev build process │ │ └── dist.js #Distribution/Production build process │ │ │ ├── config.js #Config - Specify folder/file locations, module behaviors, etc │ └── index.js #Tie it all together! │ ├── node_modules #Project dependencies │ └── ... #Seriously lots of dependencies │ ├── src #This is our game code! │ │ │ ├── objects #Main player, JumpingEnemy, Logo are all game objects. This is where bulk of the code will live │ │ └── ... │ │ │ ├── states #Different screens/displays of the game │ │ ├── Boot.js │ │ ├── Preload.js #Some example states are included in the initial generation │ │ └── Game.js │ │ │ ├── app.js #Called from index.html to create, start, and adds states to Phaser's 'game' object │ ├── assets.js #JSON describing how to preload assets from the 'static/assets' directory │ └── states.js #List of all game states. Auto-updated if using generator to create states (covered soon) │ ├── static #Static files that do not directly interact with game code. Examples: Game assets, web app assets, web pages, and more │ │ │ ├── assets #Game assets: images, music, JSON, etc │ │ └── ... │ │ │ └── index.html #HTML that our game will live in! It will be copied to the build output. │ ├── .babelrc #Babel (compiles code to old JS versions) options ├── .editorconfig #EditorConfig (maintains styles between disparate editors & IDEs) options ├── .eslintrc.yml #ESLint (catches JS errors, enforces JS style, runs in Gulp) options ├── .gitattributes #Special instructions for using & customizing Git. I've never had to use it ├── .gitignore #Specifies files you don't want to check into your remote Git repository ├── .yo-rc.json #Our generator's Yeoman config. Allows generator to remember customization info from prompts, and use it in future ├── package.json #NPM customization. Choose dev & production dependencies, specify NPM package meta info, writes scripts, and more └── README.md #Describe to consumers how to use and grok your software. A quick-start guide.
The code block above is the quick reference guide to the generator output, but some things could use a bit more explanation.
This houses all of our node project dependencies.
These dependencies are configured in 'package.json', and can be installed by running
Some people think you should check in dependencies to your VCS in case they get yanked off of NPM, but this is a relatively rare occurrence.
By default, .gitignore is set to not commit your dependencies.
If you choose to commit it, you will massively inflate your VCS files, compounding each time any dependency updates.
In the rare case something goes down, the NPM community will quickly add a mirror or replacement.
You guessed it, here's where the source code lives.
The 'states' folder contains States: in-game screens/displays. In order of usage, Birdu will contain Boot, Preload, Menu, Settings, Stats, Game, and GameOver. Each state has a clearly defined purpose (Boot and Preload load assets into RAM while displaying "Loading…" animations) and may contain a variety of objects.
An object lives in the 'objects' folder, and is a self-contained module to be used in States. An object could be as simple as an image, or as complicated as your game's player with its rich handling of user interactions, varied animations, complex game logic, etc. Objects allow us to factor out code unrelated to State execution into self-contained, modular components, thus keeping our game maintainable.
The "app.js" file starts up the Phaser game. If you want to change the game's size, initialize to a state other than Boot, or do anything fancy (unrelated to game logic) before start-up, this would be the place to do it.
"assets.js" is a really nice little file. My first version of Birdu did not use this generator, and thus did not have an assets.js file. Every asset had a corresponding line of preloading code, and also specified exact pixel values for character spritesheets. It was error-prone, difficult to maintain, and inefficent (compared to texture atlases, which I learned about after using this generator).
This directory has the "assets" folder where images, sounds, fonts, etc belong, which are loaded using the "assets.js" file from above. You can make a new sub-directory for each asset type, and specify its relative URL from "assets.js", allowing you to keep your assets organized.
The other file, "index.html", is the HTML page that our game will live on. If you don't want the game to take up the full screen, you can use this page to stylize the HTML page's background. You can also include external scripts, CSS, or modify the game's initialization call.
The other files don't have a parent directory, and thus will generally be used by other programs that expect them to be at the top level of your project. BabelRC, editorconfig, eslintrc, yo-rc, and the git stuff are generally used by the plugins that come integrated with this project. You may want to update the eslint file to fit your preferrences, and the gitignore file as your project advances, but the others probably won't require much customization. You should describe your project in the README, giving readers (and future you), an overview on what you intend to do and how.
Package.json manages your node environment.
Use it to list out all dependencies: development (like Babel) and production/deployment (like Phaser).
To add a new dependency use
npm install DEP_NAME --save for deployment dependencies or
--save-dev for dev dependencies.
It can also contain meta-data like author's name and email, which is useful if you intend to publish on NPM.
Most importantly, you can add one-line scripts in the "scripts" section, which can be ran via
1 npm run-script myScript
This makes it easy to simplify a multi-step build, test, or deployment operation all into one bash call. It comes with a "dist" command and a few other scripts for building the project, try running them to see what they do.
In addition to the main generator, which creates the entire file structure discussed above, there are some sub-generators made for more specifc tasks.
These sub-generators are used for quick scaffolding while developing (instead of setup at the beginning, like the main generator).
You can use yeoman sub-generators by appending
: sub-gen-name to the end of the original generator call.
So our new generator calls look like this
1 2 yo phaser-plus: object yo-phaser-plus: state
A prompt will be displayed asking what type of object you want to extend: Sprite, Group, TileSprite, etc. There are many options availble, and this saves you from having to memorize the initialization code for each type. After the prompt a new JS object will be created in the "objects" sub-directory.
This is a bit simpler, as there is only one type of State. After it is auto-created in the "states" sub-directory, the game file importing all the states will be updated for the new creation.
And that's it! You are now a phaser-plus expert. As the project is updated, some aspects of this tutorial may come out of date - so be sure to check the official documentation. In the next step, we will be making a Menu screen and discussing how to get started with Phaser.