Who am I?
Kierownik Działu Aplikacji Webowych
Cyfrowy Polsat, Warsaw
JavaScript Ninja. Mac lover. Pebble evangelist.
Organizer WarsawJS
"Kto chce szuka sposobu, kto nie chce szuka powodu."
piecioshka.pl/blog github.com/piecioshka
twitter.com/piecioshka soundcloud.com/piecioshka
Where am I?
Advantages of Phaser.js
• Big community
• A lot of lines of code (a lot of JSDocs)
• Good quality of code (components)
• Separation of layers in API, e.g. states and
keyboards
• Cool phaser.io/docs
"State idea"
• The gameplay is based on state switching , e.g.
choose language, select character from menu,
fight, defeat or win
• State definition - class with 4 methods: preload ,
create , update , render and optionally init
• Only one state is active !
create method
• Runs ones while generating the state
• In that method I create all objects that are
occurring in a game state
update method
• Phaser.Game#raf via
requestAnimationFrame or setTimeout
• 38881: Phaser.Game#update
• The core game loop
Day I: Here we go!31↑
Use ECMAScript 6.
webpack and Babel.js take care of compiling
to ECMAScript 5 (for browser).“
webpack.config.jsmodule.exports = { resolve: { extensions: ['.es6.js', '.js', ''] }, entry: './app/scripts/main', output: { filename: 'bundle.js', path: './app/dist' }, module: { loaders: [{ test: /\.es6\.js/, exclude: /node_modules/, loader: 'babel?stage=0' }] }}
01.02.03.04.05.06.07.08.09.10.11.12.13.
Advantages of ECMAScript 6
• Modules - no global variables
• Importing - require only dependency
• Smooth syntax of class definition with cool inheritance
• Default parameters and Arrow function
// Destructuring assignment
let [x, y] = ['abc', 100]
// x = 'abc', y = 100
01.
02.
03.
HTML (index.html)No more HTML files, because everything is in the Canvas.
1. Create container for game: <div id="game"></div>
2. Add library file: scripts/vendor/phaser.js
3. Add our game file: dist/bundle.js
Phaser.js v2.4.3
Type Files
Normal 2.8M phaser.js
726K phaser.min.js
Only need to 2,2M phaser-arcade-physics.js
754K phaser-arcade-physics.map
567K phaser-arcade-physics.min.js
Why not in modules?
• Throw an error: "PIXI is not defined"
• webpack will have big file to manage
• Do I really need it?
Write first lines of code
• Create a game object// Create game object
this.game = new Phaser.Game(800, 400, Phaser.Canvas, 'game)
• One for all game
• Available from the each of game state
01.
02.
Day II: Design (vol. 1)157 LOC (126↑)
• Add states: MenuState - select character
// Add state to setthis.game.state.add(name, handler)// Activate passed statethis.game.state.start(name)
01.02.03.04.
Day II: Design (vol. 2)
• assets - directory contains everything except code,
e.g. graphics , sound
• Display first in game background - simple image with game
dimension and position in point 0,0
// Load image file and put it to cachethis.load.image(key, path)// Fetch from cache image and put to Canvasthis.add.image(x, y, key)
01.02.03.04.
Day II: Design (vol. 3)
• scripts/models/ directory with characters definition, e.g. Son Goku
• Add states: FightState , SearchingState (screen with collected balls)
• scripts/configuration.js - file in isolated game configuration
• Create instance of player class
• Add some buttons
// Add button to Canvasthis.add.button(x, y, key, handler)
01.02.
The first big problem
• Sharing objects between states?
Ideas?
• Global variables?
• Never!
• Create custom game properties!
Day III: We are moving!258 LOC (101↑)
• Create map with Tiled - cool tool for create game maps
this.load.tilemap(key, path, data, format)// data: if path was passed, equals null// format: Phaser.Tilemap.TILED_JSON
• Add tileset to map (our spritesheet)
this.load.spritesheet(key, path, width, height)// width: tile width// height: tile height
• Create layer on map and extend it to the whole game area
01.02.03.
01.02.03.
Balls positions
• Definition of positions dragon balls in separate files, for why?
• backend can generate that files
• separate configuration from business logic
• Loading JSON file
// Fetch file and put response into cachethis.load.json(key, path)// Return parsed objectobject = this.cache.getJSON(key)
01.02.03.04.
Create the first sprite - character// Add sprite to gamethis.add.sprite(x, y, key)
Add dragon balls• Create group object for them, for better collision management
01.02.
Simple message• Create message
// Add labelmessage = this.add.text(x, y, text)
• Animation: fadeIn
message.alpha = 0this.add.tween(message).to(config, time, type, true)// config: { alpha: 1 }// time: Phaser.Timer.SECOND// type: Phaser.Easing.Linear.None
01.02.
01.02.03.04.05.
Navigation vol. 1if (keyboard.isDown(Phaser.Keyboard.LEFT) { player.x -= 5}
Warning!If we would like to use collision detection,
we should update player.velocity.x not only player.x .
01.02.03.
Navigation vol. 2// Update velocity of playerplayer.velocity.x -= 5
Remember to clear velocity before that process!
// Reset velocityplayer.velocity.x = 0
01.02.
“01.02.
Collision - a very broad subject
• Player
// Enable arcade mode for our player
this.physics.arcade.enable(player)
• Map
map.setCollisionByIndex(1) // Start counting from 1
layer = map.createLayer(name)
this.physics.arcade.collide(player, layer)
Player will be collide with tile with index = 0 from now!
01.
02.
01.
02.
03.
Collected items - dragon balls
• Group of balls should have a body
balls = this.add.group()balls.enableBody = true
• Group should have defined a physics
// Add body to group of ballsthis.physics.arcade.enable(balls)// Start collide between player and group of ballsthis.physics.arcade.collide(player, balls, handler)
01.02.
01.02.03.04.
Day IV: Time from clock
384 LOC (126↑)
• Create states: ShenronState , GameOverState ,
TrainingState
• Handle keyboard on MenuState
• Create countdown - measure time to GameOver
// Clock with reference to statethis.time.events.add(time, handler, context)
01.02.
Day V: Music!710 LOC (326↑)
• Create fake spritesheets for characters
• Add logo and sound
this.load.audio(key, path)sound = this.add.audio(key)sound.play()
• Create enemies on FightState
• Resize hitbox during fight
• Create state MealState - regeneration state, HP will be reset
01.02.03.
Day VI: Display bars858 LOC (148↑)
• Display player labels (HP and EXP),
and player avatars on FightState
• Disable sound globally (saved state in localStorage )
• Add everywhere we can DragonBallPlay logo
Day VII: Player collision1028 LOC (170↑)
• Support mouse events on MenuState
// Support mouse overbutton.events.onInputOver.add(handler, context)
• Check players collision
isOverlap() => { return this.physics.arcade.overlap(player, enemy)}
• Decrease HP of enemy when player hits him
01.02.
01.02.03.
Day VIII: Create ArtificialIntelligence
1270 LOC (242↑)
• Create screen which create only message
• Display game control before main part of game
• Rename FightState to VersusState - better name
• FightState is base class with children VersusState and
TrainingState
• First idea for AI - create list of enemy moves
Day IX: Easter egg1533 LOC (263↑)
• Fixed AI - choose random move from predefined list
• Create Utilities module with static methods
• Create state: LanguageState
• Detach all text to isolated JSON files
• Create DefinitionTyped.js
• Revert default player parameters on GameOverState
• Create Easter Egg : new character available on MenuState
Day X: Last day1732 LOC (199↑)
• Rename SearchingState to CollectingState
• Choose randomly 1 map from 3 on CollectingState
• Add collision with 2 tiles: 1 and 3
// Upgrade collisionmap.setCollision([1, 3])
• Converting all images to PNG - why is it a bad idea for backgrounds?
• Create states: PlayerPresentationState , EnemyPresentationState ,
WinnerState
01.02.
Future plans
• Block players moves when someone dies on VersusState
• Add countdown on TrainingState
• Display app version somewhere with small font size
• Extend display time for MessageState
• Fixed players collision, that they can't enter on themselves
• Support shortcuts
• Fixed Konami code
• Support Gamepad API
• Support Notification API
• Draw characters and create simple favicon
What I learned?
• Draw something when you are finish implementation
• Keyboard handler doesn't have to be in update method
• Each of state has his own clock , which is destroyed
when state is destroyed
My mistakes
• Duplicate code
Phaser.State#rnd.integerInRange(min, max)
instead of:
Utilities.random(min, max)
• I missed the manager to keep the storyline, so I decided to...
buy a couple of books about Phaser.js
Donation
patreon.com/photonstorm
(Richard Davey @photonstorm)
Links• Slides: http://piecioshka.github.io/warsawjs-presentation-my-10-days-with-phaser-js
• My games:
• https://github.com/piecioshka/www.dragonballplay.com [COMPLETE]
• https://github.com/javascript-ninjas/game-fastest-joby [COMPLETE]
• https://github.com/piecioshka/ss15-dumplings [COMPLETE]
• https://github.com/piecioshka/game-electrode [WIP]
• https://github.com/piecioshka/game-snooker [WIP]
• ECMAScript 7: https://babeljs.io/docs/usage/experimental
• Special editor: http://phasereditor.boniatillo.com
• Font: http://www.dafont.com/saiyan-sans.font