Cudabear

Phaser + Illuminated.js interface library

Recommended Posts

Hi everyone,

I noticed Phaser doesn't really have lighting effects, making it difficult to add that extra layer of polish onto your game.  With some research I found illuminated.js, which has the capability for making pretty solid lighting effects using 2D canvas.  Problem is, this is a low-level library that draws directly to the canvas, meaning the effects you create can't be managed with Phaser's sprite system.
 

To solve this problem I've created a library to interface betwen illuminated.js and Phaser, allowing you to create illuminated lamp objects that are wrapped as Phaser sprites, allowing you to manage them as such.

Currently the project has it's first release, so be aware there might be bugs and missing optimizations.  Look in the build folder for a minified version, if you so desire.  The whole file is pretty small so it's not really necessary.  Check it out here.

 

Right now, this is how you use phaser-illuminated.js:

//defined global game object (the phaser game instance)
game;

create: function(){
  //initialize the library.  This adds the necessary functions to all Phaser classes.
  game.plugins.add(Phaser.Plugin.PhaserIlluminated);
  
  //illuminated objects are added via this addition to the game.add instance.
  //these functions return Phaser.Sprite objects that can be used as such
  //config object is the same as illuminated lamps take, to customize all parameters
  //you can use myLamp1.getLamp() to get the illuminated lamp object
  myLamp1 = game.add.illuminated.lamp(200, 200 /*,{ illuminated lamp config object }*/);
  
  //add an opaque object.  parameters are (x, y, width, height).
  //this is not a phaser.sprite object because it's not actually drawn,
  //except by the lamp.
  //It's an illuminated.polygonObject instance
  myObj = game.add.illuminated.rectangleObject(420, 210, 40, 30);
  
  //lighting is done on a per-lamp basis, so each lamp sprite has a lighting object under it
  //that you can create and add PolygonObjects to.
  myObjs = [myObj];
  myLamp2.createLighting(myObjs);
  
  //darkmask is a sprite but takes up the entire game screen, IE WxH.
  //it cookie-cutters out existing lamp implementations.
  //it needs a reference to all lamp sprites, but these can be added later
  myLamps = [myLamp];
  myMask = game.add.illuminated.darkMask(myLamps/*, color*/);
  
  //myMask.addLampSprite(myLamp2); <-- alternative to adding at construction time
}

update: function(){    
  //all illuminated Sprite objects have this refresh function, which redraws them
  //this will need to be called each time a lamp moves, or changes a parameter
  //if the lamp is not changed, don't call this because it's pretty expensive.
  myLamp.refresh();
  myMask.refresh();
}

render: function(){}

All illuminated objects are rendered on cached bitmap data so as long as you don't refresh them too often the performance should be as good as normal sprites.  Refreshing them is pretty expensive, because they're several layers of bitmapdata deep to get all the drawing done.  Looking to improve this in future iterations.

I also plan to add some utility functions in the future, like the ability to auto-generate Opaque objects from tilemaps  

Let me know if you have any feedback or would like to contribute.

Thanks!

~Cudabear

Share this post


Link to post
Share on other sites

Hey, everyone!
 

I was able to add utility function for parsing tile maps and creating OpaqueObjects where solid tiles exist.  You use it like this:

 

sightBlockers = phaserIlluminated.createOpaqueObjectsFromSolidTiles(collisionLayer);

Where collisionLayer is the layer you want to pars for solid tiles, and sightBlockers is the returned array of illuminated OpaqueObjects.

 

Here's an example of the plugin in action so far:

 

 

BEFORE:

DFJDzx4.gif

 

 

AFTER:

xghxZk1.gif

 

 

The effects are added in about 10 minutes, using less than 10 lines of code!  The main points are I added a DarkMask, a lamp connected to the position of the sprite, and used the utility function to  create the lighting based on the tilemap's solid tiles.

Any other ideas for useful functions?  I'm going to add another utilty function for creating OpaqueObjects from sprite's bounding box, both individual sprites and groups.  After that though, I'm not sure what could be useful.

~Cudabear

Share this post


Link to post
Share on other sites

@Cudabear Could you size the impact on the performances? It looks awesome, wonder if it's viable in a real game.

The only case that it really gets slow (and I mean really gets slow) is when you have a lamp with lighting that's moving every frame and needs the refresh() called every frame as well.  Drawing the lighting is super expensive, and I'm looking for a way to improve it... it'll be hard to without modifying what's inside illuminated.js.  In my personal experience, 5 or so lamps with lighting handled this way produced frame drops.  

Stationary lamps or lamps without lighting, however, are very quick.  Keep in mind, these are drawn on bitmapdata that's used as textures for sprites, so they're only drawn once and then moved around like normal sprites.  Realistically, once the overhead is complete, lamps without lighting are as fast as regular sprites.

It should be noted the gif above with one lamp and lighting updates on it (on a tilemap with around 3,000 opaque object tiles) didn't produce any frame drops, though I didn't test on weaker devices.

Share this post


Link to post
Share on other sites

Just read about this thread in the current newsletter. Sounds really interesting.

 

Getting the whole thing to work with SpriteIlluminator should not be too complicated - as long as you render on WebGL. The dynamic lighting requires a specialized shader.

We've already done it with PixiJS - at least in a small demo...

 

If anybody is interested we are happy to help to get the project started. 

Share this post


Link to post
Share on other sites

Just read about this thread in the current newsletter. Sounds really interesting.

 

Getting the whole thing to work with SpriteIlluminator should not be too complicated - as long as you render on WebGL. The dynamic lighting requires a specialized shader.

We've already done it with PixiJS - at least in a small demo...

 

If anybody is interested we are happy to help to get the project started. 

 

I'd be very interested, as my game requires something similar to this: http://gamemechanicexplorer.com/#raycasting-4 and this: http://www.goodboydigital.com/pixijs/examples/20/. I see they've already implemented something similar to what I'm looking for in Phaser 3, but that's still a long way from release (see the "depth" demo here: http://labs.phaser.io/phaser3/v08/src/). Here's another very good example: http://mattdesl.github.io/kami-demos/release/normals-pixel.html. So basically, dynamic lighting, shadows and normal mapping in 2D would be excellent. I've been so frustrated with trying to get various non-Phaser-related libraries to work in Phaser that I've almost given up and switched to Unity or something else, but I'd much rather stick with Phaser since I have a good amount of development time already into the game and a large codebase built in it. The problem is that one of the core game mechanics in this game will rely on light and shadows (normal mapping is secondary, but would be great for adding polish to the look and feel of the effects). Looking at the Pixi demos, I had erroneously assumed that this would be do-able in Phaser when I began development of my game, only to discover later that Phaser uses Pixi 2, and the normal mapping feature is only available in Pixi 3. That error has put me in a bad situation.

 

While Phaser 3 already has the ability to do everything I need, its release is still about 6 months away (according to Rich's most recent estimate, spring 2016), and I don't want to put further development of my game on hold until then, let alone the fact that the entire codebase would need to be rewritten for Phaser 3 anyway. Ugh. I really hope enough of us are interested in a feature like this to get a plugin working in Phaser 2. I'll contribute whatever I can to help get started.

Share this post


Link to post
Share on other sites

To Clowerweb and AndreasLeow,

The SpriteIlluminator stuff is a bit out of my comfort zone, so I'm not entirely sure how to integrate it with the PhaserIlluminated plugin.  I do know PhaserIlluminated works just fine WebGL already (though it is really just using Canvas2D on the backend, drawn onto a bitmap data) so there shouldn't be any potential conflicts.
 

Right now, the main problem with the plugin is performance.  To be honest, I don't think Illuminated.js was ever really built for real-time dynamic lighting.  As I've said before, the performance hits come in when you've got more than a handful of lights moving around a map full of opaque objects.  In games with lighting systems, this is more than a typical use case.  Maybe we'd have to rewrite some of Illuminated.js for increased performance?

As for additional new features, there's been nothing that struck me other than auto-generating opaque objects based on the solid tiles of a tilemap layer.  I'm open for suggestions on new features to add, though.

Share this post


Link to post
Share on other sites

Awesome work!

Im trying to create a moving circular shadow however it doesn't seem that the diskObject can be moved? Just adjusting the center or x and y values does not seem to have any effect. Is moving opaque objects possible?

Share this post


Link to post
Share on other sites

Hi Kyle,

Sorry for the delayed response.

Are you calling .refresh() on your lamps that have that lighting?  This should update the opaque object's drawn position.  Ideally, only do this when the position changes, as it's quite expensive.  I'd like to make this operation cheaper, but that's something I've yet to figure out.
 

Share this post


Link to post
Share on other sites

Hey Wahooiy,

Looking at your example, things seem to be working.  The main problem I see is your player's light source is no longer respected after lighting the lamp.  When you remake the DarkMask, are you sure you're readding the player's original lamp to it again?

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.