Jump to content

Masking to simulate light area


titmael
 Share

Recommended Posts

Hi,

 

I'm making a cave game and I want to limit the hero view around him. This limit must dynamically change - for example if his torch shrink over time.

 

Here is an image illustrating what I want to do (not from my game).

 

New_Cave_Lighting.png

 

I need this mask to be over everything (except my UI of course) and follow the player.

 

Thanks ;)

Link to comment
Share on other sites

It's not quite addressing the same problem (or rather, it's addressing a more complex variation of your problem) but this example shows how you can use blending modes to simulate light and shadows. Basically, you draw your light cone on a BitmapData in white on a black background, then set its blend mode to multiply and overlay it on your game world (but below the UI).

Link to comment
Share on other sites

Hi titmael,

 

in the last Phaser Newsletter (Issue 5) was a nice link to a Game Mechanic Explorer.

There is a section about Lights, where you can find some similar examples of the effect you desire.

 

Hope that has helped :-]

 

 God damnit, I knew that Game Mechanic Explorer but forgot the link. Thx !

Link to comment
Share on other sites

What a very nice effect !

 

9294662014053014h1237.png

 

For anyone trying to do the same be carreful about 2 things :

  • WebGL requires an image which size is a power of 2 for width and height (here it's the bitmapData)
  • There is a size limit to WebGL image and it's pretty low, so I add to trick this part because I have a huge world and a camera following my player
create: function(){    this.shadowTexture = this.game.add.bitmapData(this.game.width, this.game.height);    // Create an object that will use the bitmap as a texture    this.lightSprite = this.game.add.image(this.game.camera.x, this.game.camera.y, this.shadowTexture);    // Set the blend mode to MULTIPLY. This will darken the colors of    // everything below this sprite.    this.lightSprite.blendMode = Phaser.blendModes.MULTIPLY;},update: function(){    this.lightSprite.reset(this.game.camera.x, this.game.camera.y);    this.updateShadowTexture();},updateShadowTexture: function(){    // Draw shadow    this.shadowTexture.context.fillStyle = 'rgb(10, 10, 10)';    this.shadowTexture.context.fillRect(0, 0, this.game.width, this.game.height);    var radius = 100 + this.game.rnd.integerInRange(1,10),        heroX = this.hero.x - this.game.camera.x,        heroY = this.hero.y - this.game.camera.y;       // Draw circle of light with a soft edge    var gradient =        this.shadowTexture.context.createRadialGradient(            heroX, heroY, 100 * 0.75,            heroX, heroY, radius);    gradient.addColorStop(0, 'rgba(255, 255, 255, 1.0)');    gradient.addColorStop(1, 'rgba(255, 255, 255, 0.0)');    this.shadowTexture.context.beginPath();    this.shadowTexture.context.fillStyle = gradient;    this.shadowTexture.context.arc(heroX, heroY, radius, 0, Math.PI*2, false);    this.shadowTexture.context.fill();    // This just tells the engine it should update the texture cache    this.shadowTexture.dirty = true;}
Link to comment
Share on other sites

Hi @titmael,

 

Do you have any idea on how to make the light collide with the tilemap's obstacles?  For example, if a character is standing underneath a ceiling, the light circle will not go past the ceiling and show the player what is on the other side.

Link to comment
Share on other sites

Hi @titmael,

 

Do you have any idea on how to make the light collide with the tilemap's obstacles?  For example, if a character is standing underneath a ceiling, the light circle will not go past the ceiling and show the player what is on the other side.

 

I don't but if you got a solution I'm interested, could be a very nice effect !

Link to comment
Share on other sites

  • 1 year later...

Any example without WebGL? Only Canvas? :)

I really really need to know this as well. Phaser encourages a "webGL with a canvas fallback" development and thats why we chose phaser. Hoping someone knows how to implement a good,elegant canvas fallback for lights.

Link to comment
Share on other sites

  • 2 weeks later...
  • 4 months later...

 

 

For anyone trying to do the same be carreful about 2 things :

  • WebGL requires an image which size is a power of 2 for width and height (here it's the bitmapData)
  • There is a size limit to WebGL image and it's pretty low, so I add to trick this part because I have a huge world and a camera following my player
create: function(){    this.shadowTexture = this.game.add.bitmapData(this.game.width, this.game.height);    // Create an object that will use the bitmap as a texture    this.lightSprite = this.game.add.image(this.game.camera.x, this.game.camera.y, this.shadowTexture);    // Set the blend mode to MULTIPLY. This will darken the colors of    // everything below this sprite.    this.lightSprite.blendMode = Phaser.blendModes.MULTIPLY;},update: function(){    this.lightSprite.reset(this.game.camera.x, this.game.camera.y);    this.updateShadowTexture();},updateShadowTexture: function(){    // Draw shadow    this.shadowTexture.context.fillStyle = 'rgb(10, 10, 10)';    this.shadowTexture.context.fillRect(0, 0, this.game.width, this.game.height);    var radius = 100 + this.game.rnd.integerInRange(1,10),        heroX = this.hero.x - this.game.camera.x,        heroY = this.hero.y - this.game.camera.y;       // Draw circle of light with a soft edge    var gradient =        this.shadowTexture.context.createRadialGradient(            heroX, heroY, 100 * 0.75,            heroX, heroY, radius);    gradient.addColorStop(0, 'rgba(255, 255, 255, 1.0)');    gradient.addColorStop(1, 'rgba(255, 255, 255, 0.0)');    this.shadowTexture.context.beginPath();    this.shadowTexture.context.fillStyle = gradient;    this.shadowTexture.context.arc(heroX, heroY, radius, 0, Math.PI*2, false);    this.shadowTexture.context.fill();    // This just tells the engine it should update the texture cache    this.shadowTexture.dirty = true;}

 

Thanks for this - very neat got it working with minor tweaks.

 

Not sure if it's the changes in phaser since the original post or the specifics of my game size but I had to do the following:

1)  where it says this.game.width/height I had to replace with this.game.world.width/height - it was only shadowing half my map

2)  for my game I removed the camera adjustment to the initial computation of heroX/heroY (just heroX = this.player.X)

 

For fun stuff with the gradient - adjust the fraction part in the 100 * .75 to make the shadows come in sooner or later and adjust the 1.0 in the first rgb color stop to decrease amount of light quality (candle say vs a flashlight)

 

Thanks again - pretty much gave me what I was looking for.

Link to comment
Share on other sites

I'm no expert in such things... but wouldn't regenerating the texture be a big performance hit since the updated texture has to get pushed to the graphics card every frame?

 

Rather than redraw the image every frame, why not reposition it so it's over your player?

    let offsetX = player.x - camera.x;    let offsetY = player.y - camera.y;    this.lightMask.cameraOffset.x = offsetX - game.width;    this.lightMask.cameraOffset.y = offsetY - game.height;

In my game my light mask is 2x the size of the game so no "clear" spots show. Everything else (MULTIPLY blend mode, etc) is basically the same.

Link to comment
Share on other sites

  • 1 year later...

@titmael

Hi, 

I was just curious about how are your other tiles hidden. Because when I try to do the same things, it fills everything with black except my tile map which I loaded. So basically everything is hidden except the tiles and I don't know why?

Help would be appreciated!

Thank you!

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...