Jesse Harlin PRO
I am a developer, musician and usergroup leader living and working in Oklahoma, US.
I like writing Javascript
I like writing Music
I like Amanda
I help run OKCJS
I help run Thunderplains
I help run Techlahoma
But really....
Isn't Jesse really into Impact.js ?
Hode up
"I mean.. he even made a level generator plugin.."
"and a node port?"
"Whoa, that was nearly 2 years ago?"
"Isn't there like a bazillion other
FANTABULOUS
Js Game frameworks?"
Yeah, its overwhelming.
I even did a talk about that a few years back too....
Akihabara Irenic Aves bdge CakeJS Canvex CasualJS ChesterGL ClanFX Cocos2D Collie Crafty cssgameengine Diggy Effect Games Flax FlixelJS Float Engine friGame FrozenJS
GameJs
gameQuery
GammaJS
Geom
gTile
The GMP Javascript Game Engine
Hydra
Hydrax
ingenioJS
Impact
Isogenic Engine
j5g3
The Javascript 2D Game Engine
Javascript Gamelib
Jaws
jGen
Jomoho JS
jsGameSoup
js-verge
LimeJS
MelonJS
Mibbu
PixieEngine
Play My Code
PlayCanvas
PlayN
PropulsionJS
Turbulenz
The Render Engine
Rocket Engine
Rosewood
Sarien.net interpreter
Solpeo Gaming Platform
SpellScript
Tom's Halls
UltimateJS
Unity3D
vegalib
xc.js
Not a bazillion.. but scores. Theres about 60 on the most up to date wiki I know.
"Oh yeah?
Can't I just do this all 'game stuff' with
vanilla.js ???"
Go nuts.
But here are a few reasons you might use Phaser anyways...
Open Source
Built atop PIXI
Sprites, Groups, Animation worked out
Good Mobile (exportation, device scaling)
Plugin System
Particle System
Pluggable Physics Engine
Chainable Tweening
but most importantly....
DOES NOT
SUCK
DOES NOT
SUCK
There is also an alternative flavor of documentation called
"Phaser Chains"
It is also available as a plugin in some editors
like Brackets
Fundamentally Phaser is a State System
First, one creates a
Game Object
that essentially acts as a
State Manager
var game;
game = new Phaser.Game(700, 786, Phaser.AUTO, 'some_div_id_on_your_dom');
//width, height, renderer, and the target div!
The game object holds the various subsystems needed to load assets, state, and generally make stuff happen.
The list to the left are all methods and objects accessible in the created game.
The StateManager controls the game's state.
add -GameObjectFactory
debug - Utils.Debug
device - Device
input - Input
make - GameObjectCreator
particles - Particles
physics - Physics
renderer - PIXI
scale - ScaleManager
stage - Stage
sound - SoundManager
state - StateManager
tweens - TweenManager
world - World
game
var someState = {
init: function(){
// I fire before preload.
// Best place to handle ad hoc routing, redirection
},
preload: function (){
// I fire before the state actually loads
// Great place to load assets!
},
create: function () {
// I fire when the state is initially created, after Preload
// Set up the scene here!
},
update: function () {
// I fire 60 times a second
// This is the bread and butter state where game logic lives
},
paused: function() {
// I fire when the state gets paused ..Hooray!
},
render: function() {
// I fire as fast as the screen draws, AFTER everything has drawn.
// You can put post processing here.
},
shutdown: function() {
//I fire when the state is 'shut down' - You are going to a new state.
}
};
//game is a reference to a created Phaser Game
game.state.add('some-state-name', someState);
game.state.start('some-state-name');
A Typical Phaser State
(a good starting point to understanding the subsystems)
Physics Modes
Arcade
P2
Ninja
High speed AABB collision
Fastest
Rectangles only,
no rotation
Allows
Rotation
Full Body Physics
Springs,
polygons, etc
Allows for slopes
Good for
advanced
tile support
Arcade Physics
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', {
preload: preload,
create: create,
update: update,
render: render
});
function preload() {
game.load.image('dude', '../assets/sprites/amanda.jpg');
game.load.image('ball', '../assets/sprites/okcjs_icon.png');
}
var image;
function create() {
game.physics.startSystem(Phaser.Physics.ARCADE);
cursors = game.input.keyboard.createCursorKeys();
// This creates a simple sprite that is using our loaded image and
// displays it on-screen
// and assign it to a variable
ball = game.add.sprite(400, 200, 'ball');
knocker = game.add.sprite(400, 200, 'dude');
game.physics.enable([knocker, ball], Phaser.Physics.ARCADE);
knocker.body.immovable = true;
// This gets it moving
ball.body.velocity.setTo(200, 200);
// This makes the game world bounce-able
ball.body.collideWorldBounds = true;
// This sets the image bounce energy for the horizontal
// and vertical vectors (as an x,y point). "1" is 100% energy return
ball.body.bounce.setTo(1, 1);
}
// Move the knocker with the arrow keys
function update() {
// Enable physics between the knocker and the ball
game.physics.arcade.collide(knocker, ball);
if (cursors.up.isDown) {
knocker.body.velocity.y = -300;
} else if (cursors.down.isDown) {
knocker.body.velocity.y = 300;
} else if (cursors.left.isDown) {
knocker.body.velocity.x = -300;
} else if (cursors.right.isDown) {
knocker.body.velocity.x = 300;
} else {
knocker.body.velocity.setTo(0, 0);
}
}
function render() {
//debug helper
game.debug.spriteInfo(ball, 32, 32);
}
Ninja Physics
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update});
function preload() {
game.load.tilemap('map', '../assets/tilemaps/maps/ninja-tilemap.json', null, Phaser.Tilemap.TILED_JSON);
game.load.image('ball', '../assets/sprites/billymays_head.png');
game.load.image('sky', '../assets/skies/sky.png');
game.load.image('kenney', '../assets/tilemaps/tiles/kenney.png');
}
var sprite1;
var cursors;
var map;
var layer;
var tiles;
function create() {
var sky = game.add.image(0, 0, 'sky');
sky.fixedToCamera = true;
// Activate the Ninja physics system
game.physics.startSystem(Phaser.Physics.NINJA);
map = game.add.tilemap('map');
map.addTilesetImage('kenney');
layer = map.createLayer('Tile Layer 1');
layer.resizeWorld();
var slopeMap = { '32': 1, '77': 1, '95': 2, '36': 3, '137': 3, '140': 2 };
tiles = game.physics.ninja.convertTilemap(map, layer, slopeMap);
sprite1 = game.add.sprite(50, 50, 'ball');
game.physics.ninja.enableCircle(sprite1, sprite1.width / 2);
// A little more bounce
sprite1.body.bounce = 0.5;
game.camera.follow(sprite1);
cursors = game.input.keyboard.createCursorKeys();
}
function update() {
for (var i = 0; i < tiles.length; i++)
{
sprite1.body.circle.collideCircleVsTile(tiles[i].tile);
}
if (cursors.left.isDown)
{
sprite1.body.moveLeft(20);
}
else if (cursors.right.isDown)
{
sprite1.body.moveRight(20);
}
if (cursors.up.isDown)
{
sprite1.body.moveUp(20);
}
else if (cursors.down.isDown)
{
sprite1.body.moveUp(20);
}
}
P2 Physics
Oh yeah and they also added BOX 2D, but you gotta buy it
and
Tilemaps
Use Shoebox !
And Tiled!
{ "height":75,
"layers":[
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0], //but this has like, a bazillion numbers
"height":75,
"name":"Tile Layer 1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":75,
"x":0,
"y":0
}],
"nextobjectid":1,
"orientation":"orthogonal",
"properties":
{
},
"renderorder":"right-down",
"tileheight":16,
"tilesets":[
{
"firstgid":1,
"image":"..\/..\/phasertest\/public\/space_desert_tileset.png",
"imageheight":64,
"imagewidth":272,
"margin":0,
"name":"space_desert_tileset",
"properties":
{
},
"spacing":0,
"tileheight":16,
"tilewidth":16
}],
"tilewidth":16,
"version":1,
"width":75
}
Tilemap!!!
Tilemap.json
Tileset.png
+
and
NO
YES
Tweening has a pretty cool fluent interface
Phaser Tween Manager
tween = game.add.tween(sprite)
tween.to( { x: 400, y: 100 }, 2000, "Sine");
tween.to( { alpha: 0.5 }, 500);
tween.to( { x: 600, y: 300 }, 2000, "Cubic.easeInOut");
tween.to( { alpha: 1, x: 300, y: 500 }, 2000);
tween.to( { x: 400, y: 300, angle: 180 }, 2000);
tween.to( { x: 300, y: 200, angle: 320 }, 2000, "Sine.easeInOut");
tween.to( { x: 100, y: 300, angle: 0 }, 2000);
tween.loop();
tween.start();
tweenLogo.to({
x: screenCenterX,
y: screenCenterY,
angle: 360
}, 1000)
.to({
angle: 2000
}, 1000)
.start()
.onComplete.add(function () {
twinkle.play();
logoEmitter.x = screenCenterX;
logoEmitter.y = screenCenterY;
logoEmitter.start(true, 2500, null, 25);
okcjsIcon.kill();
game.time.events.add(2500, function () {
game.state.start('win');
})
});
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', {
preload: preload,
create: create
});
function preload() {
game.load.image('sky', '../assets/skies/sky.png');
game.load.image('amanda', '../assets/sprites/amanda.jpg');
}
function create() {
game.add.sprite(0, 0, 'sky');
var item;
for (var i = 0; i < 6; i++) {
item = game.add.image(i * 150, -128, 'amanda', i);
item.anchor.setTo(0.5, 0.5);
// Add a simple bounce tween to each character's position.
game.add.tween(item)
.to({
y: 290
}, 2400, Phaser.Easing.Bounce.Out, true, 1000 + 400 * i, false);
// Add another rotation tween to the same character.
game.add.tween(item)
.to({
angle: 360
}, 2400, Phaser.Easing.Cubic.In, true, 1000 + 400 * i, false);
}
}
Tween all the Amandas.
Thats not all
Splines
Linear
Bezier
Catmull Rom
and
Emitters
What are particles??
no, but seriously they work well for magic...
...and Smoke and Bubbles and Sparks and Fire and Jetpacks and Popcorn and Dust and Confetti and Comets and Lightning and Lasers and Swarms of Insects Coins Going Everywhere and like a Bazillion other Cool Things
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', {
preload: preload,
create: create,
render: render
});
var emitter;
function preload() {
game.load.image('corona', '../assets/sprites/billymays_head.png');
}
function create() {
game.stage.backgroundColor = '#000000';
emitter = game.add.emitter(game.world.centerX, 500, 200);
emitter.makeParticles('corona');
emitter.setRotation(0, 0);
emitter.setAlpha(0.3, 0.8);
emitter.setScale(0.5, 1);
emitter.gravity = -200;
// false means don't explode all the sprites at once, but instead release at a rate of one particle per 100ms
// The 5000 value is the lifespan of each particle before it's killed
emitter.start(false, 5000, 100);
}
function render() {
game.debug.text(emitter.total, 32, 32);
}
You can combine tweening with particles to do really cool stuff...
You can combine particles with physics
You can attach particles to sprites.
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', {
preload: preload,
create: create,
update: update
});
var sprite, particle, emitter;
function preload() {
game.load.image('fire', '../assets/sprites/flameparticle.png');
game.load.image('okcjs', '../assets/sprites/billymays_head.png')
}
function create() {
game.physics.startSystem(Phaser.Physics.ARCADE);
// create the sprite
sprite = game.add.sprite(game.width / 2, game.height / 2, 'okcjs');
// create the physics body -before- attaching an emitter to the sprite
game.physics.arcade.enableBody(sprite);
sprite.body.collideWorldBounds = true;
sprite.anchor.setTo(0.5, 0.5);
//create an emitter
emitter = game.add.emitter(0, 0, 3000);
emitter.makeParticles('fire');
// Attach the emitter to the sprite
sprite.addChild(emitter);
//position the emitter relative to the sprite's anchor location
emitter.y = 0;
emitter.x = -16;
// setup options for the emitter
emitter.setAlpha(0.5, 0.9, 1500, Phaser.Easing.Out);
emitter.setScale(0.5, 1, 0.5, 1, 750, Phaser.Easing.Out);
emitter.gravity = 10;
emitter.lifespan = 750;
emitter.maxParticleSpeed = new Phaser.Point(-100, 50);
emitter.minParticleSpeed = new Phaser.Point(-200, -50);
}
function update() {
sprite.rotation = game.physics.arcade.angleToPointer(sprite);
if (game.input.activePointer.isDown) {
game.physics.arcade.accelerateToPointer(sprite);
sprite.body.drag.setTo(0, 0);
// emit a single particle every frame that the mouse is down
emitter.emitParticle();
} else {
sprite.body.acceleration.set(0, 0);
sprite.body.drag.setTo(25, 25);
}
}
Filters/Shaders
WebGl is pretty straightforward. You take the shader, and make a filter with Phaser.Filter, then assign it to a sprite.
function create() {
fragmentSrc = "" //This would be a big shader.
filter = new Phaser.Filter(game, null, fragmentSrc);
filter.setResolution(800, 600);
sprite = game.add.sprite();
sprite.width = 800;
sprite.height = 600;
sprite.filters = [ filter ];
}
function update() {
filter.update();
}
and call the filters update method in update()
The filters are an array of strings representing the lines of the GL code, the look like this:
var fragmentSrc = [
"precision mediump float;",
"uniform float time;",
"uniform vec2 resolution;",
"uniform vec2 mouse;",
"float length2(vec2 p) { return dot(p, p); }",
"float noise(vec2 p){",
"return fract(sin(fract(sin(p.x) * (43.13311)) + p.y) * 31.0011);",
"}",
"float worley(vec2 p) {",
"float d = 1e30;",
"for (int xo = -1; xo <= 1; ++xo) {",
"for (int yo = -1; yo <= 1; ++yo) {",
"vec2 tp = floor(p) + vec2(xo, yo);",
"d = min(d, length2(p - tp - vec2(noise(tp))));",
"}",
"}",
"return 3.0*exp(-4.0*abs(2.0*d - 1.0));",
"}",
"float fworley(vec2 p) {",
"return sqrt(sqrt(sqrt(",
"1.1 * // light",
"worley(p*5. + .3 + time*.0525) *",
"sqrt(worley(p * 50. + 0.3 + time * -0.15)) *",
"sqrt(sqrt(worley(p * -10. + 9.3))))));",
"}",
"void main() {",
"vec2 uv = gl_FragCoord.xy / resolution.xy;",
"float t = fworley(uv * resolution.xy / 1500.0);",
"t *= exp(-length2(abs(0.7*uv - 1.0)));",
"gl_FragColor = vec4(t * vec3(0.1, 1.5*t, 1.2*t + pow(t, 0.5-t)), 1.0);",
"}"
];
And here is where I show you WebGL eyecandy
This gonna be good.
Oh handy!
Oh shiny!
OOOOohhhhhhhhhhhhh sparkle.
My favorite!
Sploosh!
This is built entirely in primitives.
The early 00's called and want their screensaver back.
(So I didn't write that webGL stuff)
(yet)
hot off the press in version 2.4
released JUST YESTERDAY
More
Slides!
By Jesse Harlin
A Talk given to the Oklahoma City Javascript Usergroup March 2015
I am a developer, musician and usergroup leader living and working in Oklahoma, US.