Create your first Phaser game. Part 0 - Getting Ready
- Tutorial

Table of contents
0 . Preparation for work [ Вы тут]
1 . Introduction
2 . Resource loading
3 . Creation of the game world
4 . ( wip ) Groups
5 . ( wip ) The world of physics
6 . ( wip ) Management
7 . ( wip ) Adding Goals
8 . ( wip ) Final touches
This series of articles will teach you the basics and “good tone” of Phaser gaming framework . For this course, I will try to explain to you the main ideas and possibilities of the framework, and also show how to use it competently in conjunction with TypeScript and Webpack .
The main course of training is taken from the official manual , but this is not a literal translation, but an adaptation of the manual, with rewritten examples from ES5 to TypeScript and a changed project structure. I also revealed some topics in more detail.
I think it's worth making a reservation that at the time of this writing, I am using Phaser v2.6.2 and TypeScript v2.2.1 .
You will find the source code for all lessons in this repository . Please note that tags mark the stages of a project’s development at the end of a specific article, for example:
part-0- project status at the time of the current articlepart-1- at the time of article # 1 Introduction
and so on.
In a nutshell about Phaser
Phaser is an open source ( MIT ), cross-browser HTML5 framework for creating browser games using WebGL and Canvas . Unlike other frameworks, Phaser primarily targets mobile platforms and is optimized for them.
Instruments
First of all, you need to clone the repository with the project yourself:
git clone https://github.com/SuperPaintman/phaser-typescript-tutorial.gitAnd install Node.js to run the collector and other NPM scripts.
Project structure
Before moving directly to the framework itself, consider the structure of the future application.
As the basis for our project, I took this Phaser TypeScript template , which uses Webpack as a collector.
Let's look at its main files (attention to comments):
webpack.config.js
Configuration for the Webpack collector . Depending on the environment variable, it NODE_ENVwill build a build for development, or an optimized build for production.
'use strict';
/** Requires */const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const ImageminPlugin = require('imagemin-webpack-plugin').default;
const p = require('./package.json');
/** Constants */const IS_PRODUCTION = process.env.NODE_ENV === 'production';
const assetsPath = path.join(__dirname, 'assets/'); // папка с ресурсами игрыconst stylesPath = path.join(__dirname, 'styles/'); // папка с css стилями// Путь до папки с собранными билдами phaser. Из-за того, что phaser собирается// по-старинке, его (а также его зависимости) придётся подключать как// глобальный объект.const phaserRoot = path.join(__dirname, 'node_modules/phaser/build/custom/');
// Пути до библиотек phaser'аconst phaserPath = path.join(phaserRoot, 'phaser-split.js');
const pixiPath = path.join(phaserRoot, 'pixi.js');
const p2Path = path.join(phaserRoot, 'p2.js');
// Папка, в которую у будет собран наш билдconst outputPath = path.join(__dirname, 'dist');
// Путь до шаблона `index.html` файлеconst templatePath = path.join(__dirname, 'templates/index.ejs');
/** Helpers *//**
* Проверяет, содержит ли массив данный элемент
* @param {T[]} array
* @param {T} searchElement
*
* @return {boolean}
*/functionincludes(array, searchElement) {
return !!~array.indexOf(searchElement);
}
/**
* Создает правила для `expose-loader`, который добавляет модуль к глобальному
* объекту window по переданному имени
* @param {string} modulePath
* @param {string} name]
*
* @return {Object}
*/functionexposeRules(modulePath, name) {
return {
test: (path) => modulePath === path,
loader: 'expose-loader',
options: name
};
}
/**
* Удаляет из массива все элементы равные `null`
* @param {T[]} array
*
* @return {T[]}
*/functionfilterNull(array) {
return array.filter((item) => item !== null);
}
/**
* Вызывает функцию `fn`, если `isIt` равет `true`, в противном случае будет
* вызвана функция `fail`.
*
* @param {boolean} isIt
* @param {function} fn
* @param {function} fail
*
* @return {any}
*/functiononly(isIt, fn, fail) {
if (!isIt) {
return fail !== undefined ? fail() : null;
}
return fn();
}
/**
* Хелпер на основе `only`. Вызывает первую функцию, если
* `NODE_ENV` === 'production', т.е. если сборка производится для продакшена.
* @param {function} fn
* @param {function} fail
*
* @return {any}
*/const onlyProd = (fn, fail) => only(IS_PRODUCTION, fn, fail);
/**
* Хелпер на основе `only`. Вызывает первую функцию, если
* `NODE_ENV` !== 'production', т.е. если сборка производится для разработки.
* @param {function} fn
* @param {function} fail
*
* @return {any}
*/const onlyDev = (fn, fail) => only(!IS_PRODUCTION, fn, fail);
module.exports = {
entry: {
main: path.join(__dirname, 'src/index.ts')
},
output: {
path: outputPath,
// На продакшене также добавим к именам файлов их хещ, чтобы обойти// проблему с кешированием версий
filename: `js/[name]${onlyProd(() => '.[chunkhash]', () => '')}.js`,
chunkFilename: `js/[name]${onlyProd(() => '.[chunkhash]', () => '')}.chunk.js`,
sourceMapFilename: '[file].map',
publicPath: '/'
},
devtool: onlyDev(() =>'source-map', () => ''), // Отключим sourcemap'ы на проде.
resolve: {
extensions: ['.ts', '.js'],
alias: {
pixi: pixiPath, // сделаем возможным подключить 'pixi' библиотеку как обычный NPM пакет
phaser: phaserPath, // сделаем возможным подключить 'phaser' библиотеку как обычный NPM пакет
p2: p2Path, // сделаем возможным подключить 'p2' библиотеку как обычный NPM пакет
assets: assetsPath, // алиас до папки `assets/`
styles: stylesPath // алиас до папки `styles/`
}
},
plugins: filterNull([
/** DefinePlugin */// Глобальные переменные, будт полезны для отключения каких-либо функций на// проде, или напротив включения оптимизаторов и пр.new webpack.DefinePlugin({
IS_PRODUCTION: JSON.stringify(IS_PRODUCTION),
VERSION: JSON.stringify(p.version)
}),
/** JavaScript */// Минимизирует JS для продовой сборки
onlyProd(() =>new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
comments: false
})),
/** Clean */// Удалит `dist` папку перед каждой сборкойnew CleanWebpackPlugin([outputPath]),
/** TypeScript */new CheckerPlugin(),
/** Images */// Оптимизирует изображения и svg'хи
onlyProd(() =>new ImageminPlugin({
test: /\.(jpe?g|png|gif|svg)$/
})),
/** Template */// Данный плагин автоматически сгенерирует для нас `index.html` файл// на основе `templatePath`, а также сам вставит в этот шаблон все// сгенерированные скрипты и стилиnew HtmlWebpackPlugin({
title: 'Phaser TypeScript boilerplate project',
template: templatePath
}),
/** CSS */// Экспортирует CSS import'ы в отдельный `.css` файл (по-умолчанию Webpack// вставляет CSS прямо в JS файлы).new ExtractTextPlugin({
filename: `css/[name]${onlyProd(() => '.[chunkhash]', () => '')}.css`
}),
/** Chunks */// Разобьем нашу сборку на несколько файлов (т.к. вендорные файлы и файлы// самого phaser'а вряд ли будут меняться в процессе разработки, нет нужды// заставлять наших клиентов тянуть каждый раз эти данные заново. Чанки как// раз помогут в этом, браузер сможет доставать из кеша файлы, которые не// поменялись):// * Чанк для прочих модулейnew webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: (module) => /node_modules/.test(module.resource)
}),
// * Чанк для phaser модулей (p2, PIXI, phaser)new webpack.optimize.CommonsChunkPlugin({
name: 'phaser',
minChunks: (module) => includes([p2Path, pixiPath, phaserPath], module.resource)
}),
// * Чанк для инициализационных функций webpack'аnew webpack.optimize.CommonsChunkPlugin({
name: 'commons'
})
]),
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 8080,
inline: true,
watchOptions: {
aggregateTimeout: 300,
poll: true,
ignored: /node_modules/
}
},
module: {
rules: [
/** Assets */// Скопирует файлы из asset'ов
{
test: (path) => path.indexOf(assetsPath) === 0,
loader: 'file-loader',
options: {
name: `[path][name]${onlyProd(() => '.[sha256:hash]', () => '')}.[ext]`
}
},
/** CSS */
{
test: /\.styl$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
'stylus-loader'
]
})
},
/** JavaScript */
exposeRules(pixiPath, 'PIXI'), // добавит `PIXI` модуль в глобальный объект `window`
exposeRules(p2Path, 'p2'), // добавит `p2` модуль в глобальный объект `window`
exposeRules(phaserPath, 'Phaser'), // добавит `Phaser` модуль в глобальный объект `window`
{
test: /\.ts$/,
exclude: /node_modules/,
loader: 'awesome-typescript-loader'
}
]
}
};assets/
In this directory we will add all the resources of our application: images, music, JSON and more.
styles/style.styl
It will contain CSS styles (using the Stylus preprocessor ) for our page. In this series, this will be enough:
body
margin: 0pxtemplates/index.ejs
EJS template for the game page ( Webpack itself will add to it the loading of all scripts and styles):
<!DOCTYPE html><html><head><metacharset="UTF-8"><title><%=htmlWebpackPlugin.options.title %></title></head><body></body></html>tsconfig.json
Config for TypeScript :
{
"compilerOptions": {
"target": "es5", // Для большей поддержки браузерами"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"removeComments": false,
"noImplicitAny": false,
"pretty": true
},
"files": [
// Нужно указать откуда тайпинги Phaser'а явно, т.к. в данной папке// содержатся несколько разных их версий, которые будут конфликтовать между// собой."./node_modules/phaser/typescript/box2d.d.ts",
"./node_modules/phaser/typescript/p2.d.ts",
"./node_modules/phaser/typescript/phaser.comments.d.ts",
"./node_modules/phaser/typescript/pixi.comments.d.ts"
],
"include": [
// А так-же укажем откуда брать тайпинги по glob'у"./src/**/*.ts",
"./node_modules/@types/**/*.ts"
]
}src/typings.d.ts
In this file, we must declare all global variables that we created in webpack.DefinePlugin:
declare const IS_PRODUCTION: boolean;
declare const VERSION: string;src/index.ts
This is the main file of our application, it will be the input exact into it:
'use strict';On this basis, we will create a platformer.
Github Repo : https://github.com/SuperPaintman/phaser-typescript-tutorial
To the content