4 |
5 | Phaser Template
6 |
7 |
8 |
9 |
10 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Boot from 'states/Boot';
2 | import Preload from 'states/Preload';
3 | import GameTitle from 'states/GameTitle';
4 | import Main from 'states/Main';
5 | import GameOver from 'states/GameOver';
6 |
7 | class Game extends Phaser.Game {
8 |
9 | constructor() {
10 |
11 | super(window.innerWidth * window.devicePixelRatio, window.innerHeight * window.devicePixelRatio, Phaser.AUTO);
12 |
13 | this.state.add('Boot', Boot, false);
14 | this.state.add('Preload', Preload, false);
15 | this.state.add('GameTitle', GameTitle, false);
16 | this.state.add('Main', Main, false);
17 | this.state.add('GameOver', GameOver, false);
18 |
19 | this.state.start('Boot');
20 | }
21 |
22 | }
23 |
24 | new Game();
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "phaser-es6-boilerplate",
3 | "version": "1.0.2",
4 | "description": "Tiny flexible template for writing Phaser games in ES6/ES2015 with Babel.",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "start": "gulp",
8 | "production": "gulp --production"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/belohlavek/phaser-es6-boilerplate"
13 | },
14 | "author": "Daniel Belohlavek",
15 | "license": "MIT",
16 | "devDependencies": {
17 | "babelify": "^6.1.3",
18 | "browser-sync": "^2.8.0",
19 | "browserify": "^11.0.0",
20 | "del": "^1.2.0",
21 | "exorcist": "^0.4.0",
22 | "gulp": "^3.9.0",
23 | "gulp-buffer": "0.0.2",
24 | "gulp-if": "^1.2.5",
25 | "gulp-uglify": "^1.2.0",
26 | "gulp-util": "^3.0.6",
27 | "vinyl-source-stream": "^1.1.0",
28 | "yargs": "^3.16.1"
29 | },
30 | "dependencies": {
31 | "phaser": "^2.4.1"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Daniel Belohlavek
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/gulpfile.md:
--------------------------------------------------------------------------------
1 | # Modifying `gulpfile.js` :raised_hands:
2 |
3 | There are seven variables that you can modify in order to easily adapt the behaviour
4 | of the Gulp file to your own needs.
5 |
6 | ## Constants
7 |
8 | **`PHASER_PATH`** path to the Phaser build folder, change if using Bower or other package managers.
9 |
10 | Default: `./node_modules/phaser/build/`
11 |
12 | ***
13 |
14 | **`BUILD_PATH`** your build folder's path, change it if you wish to rename the default folder.
15 |
16 | Default: `./build/`
17 |
18 | ***
19 |
20 | **`SCRIPTS_PATH`** should be contained inside the build folder, used to store Javascript files.
21 |
22 | Default: `BUILD_PATH + '/scripts'`
23 |
24 | ***
25 |
26 | **`SOURCE_PATH`** your source code folder's path (the place where all your ES6 files are located).
27 |
28 | Default: `./src`
29 |
30 | ***
31 |
32 | **`STATIC_PATH`** your static files folder's path (the place where all your HTML and CSS is located).
33 |
34 | Default: `./static`
35 |
36 | ***
37 |
38 | **`ENTRY_FILE`** the main source file, by convention named `index.js`.
39 |
40 | Default: `SOURCE_PATH + '/index.js'`
41 |
42 | ***
43 |
44 | **`OUTPUT_FILE`** the name of the output transpiled file.
45 |
46 | Default: `game.js`
47 |
48 | ***
49 |
50 | *Any other modification must be done manually to the correct Task.*
--------------------------------------------------------------------------------
/static/service-worker.js:
--------------------------------------------------------------------------------
1 | importScripts('assets/js/cache-polyfill.js');
2 |
3 | var CACHE_VERSION = 'app-v1';
4 | var CACHE_FILES = [
5 | 'index.html'
6 | ];
7 |
8 | self.addEventListener('install', function (event) {
9 | event.waitUntil(
10 | caches.open(CACHE_VERSION)
11 | .then(function (cache) {
12 | console.log('Opened cache');
13 | return cache.addAll(CACHE_FILES);
14 | })
15 | );
16 | });
17 |
18 | self.addEventListener('activate', function (event) {
19 | event.waitUntil(
20 | caches.keys().then(function(keys){
21 | return Promise.all(keys.map(function(key, i){
22 | if(key !== CACHE_VERSION){
23 | return caches.delete(keys[i]);
24 | }
25 | }))
26 | })
27 | )
28 | });
29 |
30 | self.addEventListener('fetch', function (event) {
31 | event.respondWith(
32 | caches.match(event.request).then(function(res){
33 | if(res){
34 | return res;
35 | }
36 | requestBackend(event);
37 | })
38 | )
39 | });
40 |
41 | function requestBackend(event){
42 | var url = event.request.clone();
43 | return fetch(url).then(function(res){
44 | //if not a valid response send the error
45 | if(!res || res.status !== 200 || res.type !== 'basic'){
46 | return res;
47 | }
48 |
49 | var response = res.clone();
50 |
51 | caches.open(CACHE_VERSION).then(function(cache){
52 | cache.put(event.request, response);
53 | });
54 |
55 | return res;
56 | })
57 | }
--------------------------------------------------------------------------------
/static/assets/js/cache-polyfill.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2015 Google Inc. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | (function() {
19 | var nativeAddAll = Cache.prototype.addAll;
20 | var userAgent = navigator.userAgent.match(/(Firefox|Chrome)\/(\d+\.)/);
21 |
22 | // Has nice behavior of `var` which everyone hates
23 | if (userAgent) {
24 | var agent = userAgent[1];
25 | var version = parseInt(userAgent[2]);
26 | }
27 |
28 | if (
29 | nativeAddAll && (!userAgent ||
30 | (agent === 'Firefox' && version >= 46) ||
31 | (agent === 'Chrome' && version >= 50)
32 | )
33 | ) {
34 | return;
35 | }
36 |
37 | Cache.prototype.addAll = function addAll(requests) {
38 | var cache = this;
39 |
40 | // Since DOMExceptions are not constructable:
41 | function NetworkError(message) {
42 | this.name = 'NetworkError';
43 | this.code = 19;
44 | this.message = message;
45 | }
46 |
47 | NetworkError.prototype = Object.create(Error.prototype);
48 |
49 | return Promise.resolve().then(function() {
50 | if (arguments.length < 1) throw new TypeError();
51 |
52 | // Simulate sequence<(Request or USVString)> binding:
53 | var sequence = [];
54 |
55 | requests = requests.map(function(request) {
56 | if (request instanceof Request) {
57 | return request;
58 | }
59 | else {
60 | return String(request); // may throw TypeError
61 | }
62 | });
63 |
64 | return Promise.all(
65 | requests.map(function(request) {
66 | if (typeof request === 'string') {
67 | request = new Request(request);
68 | }
69 |
70 | var scheme = new URL(request.url).protocol;
71 |
72 | if (scheme !== 'http:' && scheme !== 'https:') {
73 | throw new NetworkError("Invalid scheme");
74 | }
75 |
76 | return fetch(request.clone());
77 | })
78 | );
79 | }).then(function(responses) {
80 | // If some of the responses has not OK-eish status,
81 | // then whole operation should reject
82 | if (responses.some(function(response) {
83 | return !response.ok;
84 | })) {
85 | throw new NetworkError('Incorrect response status');
86 | }
87 |
88 | // TODO: check that requests don't overwrite one another
89 | // (don't think this is possible to polyfill due to opaque responses)
90 | return Promise.all(
91 | responses.map(function(response, i) {
92 | return cache.put(requests[i], response);
93 | })
94 | );
95 | }).then(function() {
96 | return undefined;
97 | });
98 | };
99 |
100 | Cache.prototype.add = function add(request) {
101 | return this.addAll([request]);
102 | };
103 | }());
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This template is a modified version of this repository: https://github.com/belohlavek/phaser-es6-boilerplate
2 |
3 | It has been modified to include the following states:
4 |
5 | * Boot
6 | * Preload
7 | * GameTitle
8 | * Main
9 | * GameOver
10 |
11 | and is set up to auto resize to cover the entire available viewport. It also includes a service worker and manifest file for progressive web app support.
12 |
13 | Original documentation below:
14 |
15 | # Phaser ES6 Boilerplate
16 |
17 | This is a non-professional Phaser template for building standard games using the
18 | Phaser framework and ES6/2015.
19 |
20 | The original idea was to create a small project that contained a robust gulpfile,
21 | a basic example and *some* kind of folder structure.
22 |
23 | Codepen example: http://codepen.io/belohlavek/full/aORJVL
24 |
25 | ## Features
26 |
27 | ✔ Heavily commented, flexible Gulpfile (that means it uses [Gulp](http://gulpjs.com/)).
28 |
29 | ✔ [Browserify](https://github.com/substack/node-browserify) + [Babelify](https://github.com/babel/babelify) (Yes, it uses [Babel](https://babeljs.io/)).
30 |
31 | ✔ [Browsersync](http://www.browsersync.io/) = Livereload + Mobile debugging with [Weinre](http://people.apache.org/~pmuellr/weinre-docs/latest/).
32 |
33 | ✔ Example: Extending Phaser & modular development.
34 |
35 | ✔ Production ([UglifyJS](https://github.com/mishoo/UglifyJS2)) and Development ([Sourcemaps](https://developer.chrome.com/devtools/docs/javascript-debugging#source-maps)) builds.
36 |
37 | ✔ Did I say ES6? Well.. some ES7 too! ([See Experimental features](https://babeljs.io/docs/usage/experimental/)).
38 |
39 | ## Why?
40 |
41 | ES6 [is the future](http://www.ecma-international.org/publications/standards/Ecma-262.htm)!
42 |
43 | Anyways, I've been using ES6 for a while in other personal projects, and I currently prefer it over ES5 and Typescript.
44 | I found the new Class-based syntax to be a better fit for my developer needs. Unfortunately, the best way to access
45 | all the features of the new standard is by using a transpiler. This boilerplate is an attempt to reduce the time spent
46 | configurating a project and installing dependencies by providing a template that can work as an scaffold for any Phaser game.
47 |
48 | ## Usage
49 |
50 | You need [Node.js and npm](https://nodejs.org/). You should also have git installed, but it's not mandatory.
51 |
52 | Clone the repository (or download the ZIP file)
53 |
54 | `git clone https://github.com/belohlavek/phaser-es6-boilerplate.git`
55 |
56 | Install dependencies
57 |
58 | `npm install`
59 |
60 | Run a development build...
61 |
62 | `npm start`
63 |
64 | ...or a production build.
65 |
66 | `npm run production`
67 |
68 | Development builds will copy `phaser.min.js` together with `phaser.map` and `phaser.js`
69 | Your ES6 code will be transpiled into ES5 and concatenated into a single file.
70 | A sourcemap for your code will also be included (by default `game.map.js`).
71 |
72 | Production builds will only copy `phaser.min.js`. Your ES6 code will be transpiled and
73 | minified using UglifyJS.
74 |
75 | Any modification to the files inside the `./src` and `./static` folder will trigger a full page reload.
76 |
77 | If you modify the contents of other files, please manually restart the server.
78 |
79 | ### Modifying `gulpfile.js`
80 |
81 | See [gulpfile.md](https://github.com/belohlavek/phaser-es6-boilerplate/blob/master/gulpfile.md)
82 |
83 | ## Changelog (1.0.2)
84 |
85 | * Faster builds (no need to copy static files every time).
86 | * Live reload now works with static files too!
87 |
88 | ## Contributing
89 |
90 | Please report any bugs or add requests on [Github Issues](https://github.com/belohlavek/phaser-es6-boilerplate/issues).
91 |
92 | ## About me
93 |
94 | My name is Daniel Belohlavek: I'm from Buenos Aires, Argentina and I love to derp around and code
95 | silly snippets. You can follow me on Twitter [@dbhvk](http://twitter.com/dbhvk)
96 |
97 | ## License
98 |
99 | This project is released under the MIT License.
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var del = require('del');
2 | var gulp = require('gulp');
3 | var path = require('path');
4 | var argv = require('yargs').argv;
5 | var gutil = require('gulp-util');
6 | var source = require('vinyl-source-stream');
7 | var buffer = require('gulp-buffer');
8 | var uglify = require('gulp-uglify');
9 | var gulpif = require('gulp-if');
10 | var exorcist = require('exorcist');
11 | var babelify = require('babelify');
12 | var browserify = require('browserify');
13 | var browserSync = require('browser-sync');
14 |
15 | /**
16 | * Using different folders/file names? Change these constants:
17 | */
18 | var PHASER_PATH = './node_modules/phaser/build/';
19 | var BUILD_PATH = './build';
20 | var SCRIPTS_PATH = BUILD_PATH + '/scripts';
21 | var SOURCE_PATH = './src';
22 | var STATIC_PATH = './static';
23 | var ENTRY_FILE = SOURCE_PATH + '/index.js';
24 | var OUTPUT_FILE = 'game.js';
25 |
26 | var keepFiles = false;
27 |
28 | /**
29 | * Simple way to check for development/production mode.
30 | */
31 | function isProduction() {
32 | return argv.production;
33 | }
34 |
35 | /**
36 | * Logs the current build mode on the console.
37 | */
38 | function logBuildMode() {
39 |
40 | if (isProduction()) {
41 | gutil.log(gutil.colors.green('Running production build...'));
42 | } else {
43 | gutil.log(gutil.colors.yellow('Running development build...'));
44 | }
45 |
46 | }
47 |
48 | /**
49 | * Deletes all content inside the './build' folder.
50 | * If 'keepFiles' is true, no files will be deleted. This is a dirty workaround since we can't have
51 | * optional task dependencies :(
52 | * Note: keepFiles is set to true by gulp.watch (see serve()) and reseted here to avoid conflicts.
53 | */
54 | function cleanBuild() {
55 | if (!keepFiles) {
56 | del(['build/**/*.*']);
57 | } else {
58 | keepFiles = false;
59 | }
60 | }
61 |
62 | /**
63 | * Copies the content of the './static' folder into the '/build' folder.
64 | * Check out README.md for more info on the '/static' folder.
65 | */
66 | function copyStatic() {
67 | return gulp.src(STATIC_PATH + '/**/*')
68 | .pipe(gulp.dest(BUILD_PATH));
69 | }
70 |
71 | /**
72 | * Copies required Phaser files from the './node_modules/Phaser' folder into the './build/scripts' folder.
73 | * This way you can call 'npm update', get the lastest Phaser version and use it on your project with ease.
74 | */
75 | function copyPhaser() {
76 |
77 | var srcList = ['phaser.min.js'];
78 |
79 | if (!isProduction()) {
80 | srcList.push('phaser.map', 'phaser.js');
81 | }
82 |
83 | srcList = srcList.map(function(file) {
84 | return PHASER_PATH + file;
85 | });
86 |
87 | return gulp.src(srcList)
88 | .pipe(gulp.dest(SCRIPTS_PATH));
89 |
90 | }
91 |
92 | /**
93 | * Transforms ES2015 code into ES5 code.
94 | * Optionally: Creates a sourcemap file 'game.js.map' for debugging.
95 | *
96 | * In order to avoid copying Phaser and Static files on each build,
97 | * I've abstracted the build logic into a separate function. This way
98 | * two different tasks (build and fastBuild) can use the same logic
99 | * but have different task dependencies.
100 | */
101 | function build() {
102 |
103 | var sourcemapPath = SCRIPTS_PATH + '/' + OUTPUT_FILE + '.map';
104 | logBuildMode();
105 |
106 | return browserify({
107 | paths: [ path.join(__dirname, 'src') ],
108 | entries: ENTRY_FILE,
109 | debug: true
110 | })
111 | .transform(babelify)
112 | .bundle().on('error', function(error){
113 | gutil.log(gutil.colors.red('[Build Error]', error.message));
114 | this.emit('end');
115 | })
116 | .pipe(gulpif(!isProduction(), exorcist(sourcemapPath)))
117 | .pipe(source(OUTPUT_FILE))
118 | .pipe(buffer())
119 | .pipe(gulpif(isProduction(), uglify()))
120 | .pipe(gulp.dest(SCRIPTS_PATH));
121 |
122 | }
123 |
124 | /**
125 | * Starts the Browsersync server.
126 | * Watches for file changes in the 'src' folder.
127 | */
128 | function serve() {
129 |
130 | var options = {
131 | server: {
132 | baseDir: BUILD_PATH
133 | },
134 | open: false // Change it to true if you wish to allow Browsersync to open a browser window.
135 | };
136 |
137 | browserSync(options);
138 |
139 | // Watches for changes in files inside the './src' folder.
140 | gulp.watch(SOURCE_PATH + '/**/*.js', ['watch-js']);
141 |
142 | // Watches for changes in files inside the './static' folder. Also sets 'keepFiles' to true (see cleanBuild()).
143 | gulp.watch(STATIC_PATH + '/**/*', ['watch-static']).on('change', function() {
144 | keepFiles = true;
145 | });
146 |
147 | }
148 |
149 |
150 | gulp.task('cleanBuild', cleanBuild);
151 | gulp.task('copyStatic', ['cleanBuild'], copyStatic);
152 | gulp.task('copyPhaser', ['copyStatic'], copyPhaser);
153 | gulp.task('build', ['copyPhaser'], build);
154 | gulp.task('fastBuild', build);
155 | gulp.task('serve', ['build'], serve);
156 | gulp.task('watch-js', ['fastBuild'], browserSync.reload); // Rebuilds and reloads the project when executed.
157 | gulp.task('watch-static', ['copyPhaser'], browserSync.reload);
158 |
159 | /**
160 | * The tasks are executed in the following order:
161 | * 'cleanBuild' -> 'copyStatic' -> 'copyPhaser' -> 'build' -> 'serve'
162 | *
163 | * Read more about task dependencies in Gulp:
164 | * https://medium.com/@dave_lunny/task-dependencies-in-gulp-b885c1ab48f0
165 | */
166 | gulp.task('default', ['serve']);
167 |
--------------------------------------------------------------------------------