Write better camera for Phaser — Part 1

Write a more advance camera for Phaser HTML5 game framework.


Update: Part 2 is now available.

I’ve been working with Phaser for a while now and I feel comfortable with the framework. Its API is pretty decent and simple, very easy to learn and performs well on mobile devices.

It was smooth and happy for me.

However, recently I am making an action/JRPG game. I wish to utilise camera movement/zooming in order to create better effect and experience. That’s when I realised…

Phaser Camera does not have zoom functionality!!!

NO ZOOM? It’s a freaking camera ☹

So I googled for some work around (yeah, I am that lazy) but none of the implementations looks cool to me. Their codes look just…messy and complicated. I just thought, why does it have to be complicated? So I decided to make my hands do some dirty work.

My way is simple: make a group and throw what ever I wanna see on the camera in it and scale it when I wanna zoom the camera.

You may ask: why not scale the world? I just don’t feel comfortable with doing whatever to the world at all.

Don’t you see what humanity have done to this world?

So this is what I came up with:

class Camera extends Phaser.Group {
constructor() {
...
this.scale.setTo(1);
...
}
zoomTo(scale) {
this.scale.setTo(scale)
}
}
Aha, isn’t that easy?
Yes it is.
Does it work?
Not so fast.

When zooms out and pans, the camera pans outside of the group.

That is because as default, the camera bounds is set to the size of the world, when the group scales, the bounds should also be scaled and repositioned.

constructor() {
...
this.bounds = Phaser.Rectangle.clone(game.world.bounds);
...
}
zoomTo(scale) {
var bounds = this.bounds;
var cameraBounds = game.camera.bounds;
cameraBounds.x = bounds.width * (1 - scale) / 2;
cameraBounds.y = bounds.height * (1 - scale) / 2;
cameraBounds.width = bounds.width * scale;
cameraBounds.height = bounds.height * scale;
...
}

Finally, I added the ability to zoom slowly, because people like it smooth.

zoomTo(scale, duration) {
...
if (!duration) {
...
} else {
game.add.tween(cameraBounds).to({
x : bounds.width * (1 - scale) / 2,
y : bounds.height * (1 - scale) / 2,
width : bounds.width * scale,
height : bounds.height * scale
}, duration).start();
return game.add.tween(this.scale).to({
x: scale, y: scale
}, duration).start();
}
}

And then I had…

What’s next?

Update: Part 2 is now available.

With this camera, I added smooth follow with controllable panning speed and want to add some other functionalities including: swipe to pan and parallax. In the following posts, I would cover those as well as on screen gamepad (with joystick) and physical gamepad connection with HTML5 Gamepad API.

Follow me on Twitter and check out my blog for interesting topics.

If you are seeking for a freelancer on game and web development, please feel free to contact me at anhnt.fami@gmail.com.

Like what you read? Give Nguyen Tuan Anh a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.