WarsawJS: My 10 days with Phaser.js
-
Upload
piotr-kowalski -
Category
Technology
-
view
669 -
download
0
Transcript of WarsawJS: My 10 days with Phaser.js
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