Torch fullscreen effect

55 views
Skip to first unread message

Julien Reiss

unread,
Oct 20, 2016, 10:22:15 AM10/20/16
to melonJS - A lightweight HTML5 game engine
Hello melonJS group,

first of all thanks for all the work done on melonJS. Exactly what i was looking for, great job guys! I've been able to build a simple platformer with all the docs, and for now i've been able to solve all my gameplay related issue with the help of the group, so thanks also to the contributers :)

I am now facing a rendering problem, and would like to know if it's possible to do what i'm trying to do, or even if it's a good idea...
I would like to render a torch effect in my platformer. The idea is to have the whole screen black (or gray if using an alpha value, depending on the needs) and to have a circle following the character and showing the level as normal. I guess it's a classic in the dungeon games. So the technical idea i have is to obtain a sort of alpha layer fullscreen that would show the surrounding of the player, and hide the rest of the screen.

I've been thinking about different ways of doing it, without having a proper solution :
- create a class that extends me.Renderable, draw a rectangle in black, and draw the circle around the player. To achieve that, i think i need to be able to draw the circle in a sort of substracting mode, but i cannot find any solution to do anything as such in the renderer. Is that possible in a way ?
- create a class that extends me.Renderable, draw an image with the circle and the borders included, and try to fill the rest of the layer in black. similar to the previous solution, but it would mean composing the the layer manually, drawing 4 rectangles of black on each side of the picture...
- make a gigantic image with the circle on it, and draw it on the entire screen; pretty sure it's the worst thing to do in terms of performance...
- create a special tile map in the level, that would represent the alpha layer, and make it follow the player position. For that the map would have to tile screen-space wise, not sure it's easy to do...

Or is there an easier solution to do this torch effect?

What about performance of such an effect? i would like to make sure that it won't mean refreshing the entire screen at every frame!

Thanks for the help and for the good work!

Pete Baron

unread,
Oct 22, 2016, 6:58:44 PM10/22/16
to melonJS - A lightweight HTML5 game engine
I'm new to melonJS but I've been poking around inside a bit, and it looks to me like you could hook this up into Viewport.draw as a new effect alongside the fading and flashing effects.

You would need to make a dark layer with an alpha blended hole in the middle, and adjust its offset so the hole is over the player. (Make the layer larger than the screen so at the map edges when the player goes near the screen edge, the dark area extends all the way to the other screen edge).  I can't advise on the efficiency of the different ways of doing this, but I suspect that using a large .PNG source will probably come out exactly the same as creating a drawing object programmatically.  The only really fast solution is if you know you will have webgl support and then you could write a very simple shader to do it.

aaron.g...@gmail.com

unread,
Oct 22, 2016, 7:16:39 PM10/22/16
to melonJS - A lightweight HTML5 game engine
Saw this the other day, forgot to reply, sorry about that. If you want a radial light view, you can do it with a mask. Should be easy enough to implement: http://stackoverflow.com/questions/6271419/how-to-fill-the-opposite-shape-on-canvas. Similar to what the answer mentions there, follow the mask canvas bit.

If you find it's too slow via profiling, try using a png instead. I feel like the png logic would be way more complicated, as you would need it either big enough with black space to cover the screen regardless of where the whole is. Or you need to tile black images accordingly, which has more mathematically complications.

melonJS

unread,
Oct 23, 2016, 10:57:52 PM10/23/16
to melonJS - A lightweight HTML5 game engine, aaron.g...@gmail.com
global composition / blend mode is definitely the way to go, but on top of using clipping, you could also use an image (or even an animated one) with dithering/alpha on the edge, that would provide a more realistic final rendering.

check the MDN doc, they are quite clear actually: 

else a couple of useful example i quickly found :

also, as a reminder, you can have access to the canvas context, through the renderer object passed as argument to your draw function :

let us know about your progress ! :)

Julien Reiss

unread,
Oct 24, 2016, 12:03:18 PM10/24/16
to melonJS - A lightweight HTML5 game engine
Hello again,

thanks for all your replies! I made some tests on the different proposals listed here.
1st test was, use a png mask, and display it on top. For this, i had to make a  mask of 2048 x 2048px to be able to cover my whole screen. The rendering works, so at least i have a first working prototype of what i wanted to achieve ! Result can be seen here :
http://tof.canardpc.com/view/16a4ac92-ec25-4543-85b0-420930d62171.jpg

As expected it is a bit of a performance hit, but it is still playable. The drawbacks are that the image is somewhat big, and it's resolution dependent, so changing resolution would mean change the resource, which could grow even bigger...

I also had a look at the composing possibilities. I'm trying to get rid of any ressource for now, and draw the mask elements in code. By digging through the different composition possibilities, i think i should use one called "destination-in", which from what i see would keep the thing i draw on in the shape i'm drawing with; i saw that here :
http://www.w3schools.com/tags/playcanvas.asp?filename=playcanvas_globalcompop&preval=destination-in

so my idea was render a circle on top of the scene, and manage in way to have a black clear color that would give my effect. Bad news here, i can't get anything working...
Similar to what i use to draw the png, i'm using the following code in an item derivating from a Renderable :

draw: function (renderer) {
        var previousGco = renderer.getContext().globalCompositeOperation;
        renderer.getContext().globalCompositeOperation = "destination-in";
        renderer.fillArc(this.target_x - 128 + 16, this.target_y - 128 + 16, 128, 0, 2*Math.PI);
        renderer.getContext().globalCompositeOperation = previousGco;
}

The result is that i get a slower game, with no visual difference. There rendering part of the circle seems correct, using a normal composition effect shows a white circle. Something which is weird, displaying the debug overlay with the quadtree display show up a circle around the target and with a weird bug on a part of the quad tree display :
http://tof.canardpc.com/view/79a09c37-6663-45a8-814c-15093cd5665c.jpg

So there has to be something i'm missing here with the composing; Is anything being reset after the draw call of my class happens? I tried to dig into the source code and noticed that the prepareSurface() code sets the composite operation, but i doubt this is a conflict in my case. Or could i be missing something like a full repaint of the canvas ?

Anyway, the composing possibilities looks interesting, it made me want to make a flame effect somewhere with the "lighter" composing effect, similar to what the particles seem to do. But i don't master the thing yet :p

Thanks!
Reply all
Reply to author
Forward
0 new messages