Video: https://www.youtube.com/watch?v=klDeljOKDjU
O tym jak przez kolejne 10 dni pisałem grę z użyciem Phaser.js. Fabuła gry opiera się na anime Dragon Ball. Grafikę do gry robiłem własnoręcznie, o czym możecie się przekonać wchodząc na www.dragonballplay.com, gdzie znajduje się wersja v1.0 tego projektu. Codziennie poświęcałem 5-6 godzin po pracy, aby od 1 do 10 września stworzyć pełnoprawną grę internetową.
2. 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."
6. 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
8. "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 !
16. 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.
17. 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
18. 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
19. Why not in modules?
• Throw an error: "PIXI is not defined"
• webpack will have big file to manage
• Do I really need it?
20. 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.
21.
22. Day II: Design (vol. 1)
157 LOC (126↑)
• Add states: MenuState - select character
// Add state to set
this.game.state.add(name, handler)
// Activate passed state
this.game.state.start(name)
01.
02.
03.
04.
23. 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 cache
this.load.image(key, path)
// Fetch from cache image and put to Canvas
this.add.image(x, y, key)
01.
02.
03.
04.
24. 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 Canvas
this.add.button(x, y, key, handler)
01.
02.
25. The first big problem
• Sharing objects between states?
Ideas?
• Global variables?
• Never!
• Create custom game properties!
26.
27. 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.
28. 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 cache
this.load.json(key, path)
// Return parsed object
object = this.cache.getJSON(key)
01.
02.
03.
04.
29. Create the first sprite - character
// Add sprite to game
this.add.sprite(x, y, key)
Add dragon balls
• Create group object for them, for better collision management
01.
02.
31. Navigation vol. 1
if (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.
32. Navigation vol. 2
// Update velocity of player
player.velocity.x -= 5
Remember to clear velocity before that process!
// Reset velocity
player.velocity.x = 0
01.
02.
“01.
02.
33. 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.
34. 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 balls
this.physics.arcade.enable(balls)
// Start collide between player and group of balls
this.physics.arcade.collide(player, balls, handler)
01.
02.
01.
02.
03.
04.
35.
36. 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 state
this.time.events.add(time, handler, context)
01.
02.
37.
38.
39.
40.
41. 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.
42.
43. Day VI: Display bars
858 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
44.
45. Day VII: Player collision
1028 LOC (170↑)
• Support mouse events on MenuState
// Support mouse over
button.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.
46.
47.
48.
49.
50. Day VIII: Create Artificial
Intelligence
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
51.
52.
53.
54.
55. Day IX: Easter egg
1533 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
56.
57.
58.
59. Day X: Last day
1732 LOC (199↑)
• Rename SearchingState to CollectingState
• Choose randomly 1 map from 3 on CollectingState
• Add collision with 2 tiles: 1 and 3
// Upgrade collision
map.setCollision([1, 3])
• Converting all images to PNG - why is it a bad idea for backgrounds?
• Create states: PlayerPresentationState , EnemyPresentationState ,
WinnerState
01.
02.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71. 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
76. 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
77. 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