[Help]2D tile map lighting

Wow, thats really helpful thanks!, with the everything posted here I should be able to take a good swing at getting this working. But I’m off to bed as I’m tired…
I’ll make sure to post up progress later this week. :slight_smile:

Sorry, I slept on that code and realised that it would not work for line gradients of greater than 1, because it would miss out bits of the line checking. A method I have used in the past is to, if the gradient is greater than 1, do 1/gradient and step by y++ rather than x++.

But this makes a huge mess of code, surely someone can think of a better way?

Determing visibility between a light and a tile is pretty easy, just raycast between them and check if there´s something in between. The problem here is performance. Doubling the radius of a light quadrouples the area the light covers, and therefore the number of raycasts. However, the raycasts also get a LOT more expensive since the extra raycasts needed are twice as long. In the end this scales VERY badly with larger lights, but if you only have a handful of lights with a radius of around 10 tiles or so you should be able to get realtime frame rates pretty easily.

I encountered the exact same problem when I was doing fog of war with “shadows” from walls. I ended up uploading a “wall map” to a texture and then doing the raycasts in a shader on the GPU for each tile. I got antialiased shadows thanks to free texture interpolation of the wall map, very simple code and almost no CPU cost at all since it´s handled by the GPU. Performance of lights with a radius of 10 tiles: around 50 000 lights at 60 FPS on relatively low end computers. Increasing the light size still has a very high cost though…

Are there any good raycasting tutorials?

Raycasting is the fancy name for what I described, all you need is an algorithm to draw a line. You could finish the one I started, make your own, or google the ‘Bresenham algorithm’ for more information on how to calculate lines efficiently

Take into mind what theagentd said, about the lights scaling badly. But be sure you only update the lights every frame if you absolutely need to. If the lighting isn’t going to change, You only need to calculate lighting when the level starts.If you can place your own blocks or lights, you only need to update that affects that area when you place a block/torch.

Fair enough, would the bit earlier about " if the gradient is greater than 1, do 1/gradient and step by y++ rather than x++." - would that work?
or are there better ways to do it?

EDIT: Also, why is it that your code doesn’t work above gradients of 1?

My code won’t work correctly for gradients above 1 because if you have a gradient below one, you need to increment the x value several times to see a change in the integer value of y. For a gradient greater than one, for every x increment, there have been several changes in the y value. So you will skip some values using my code, as it only ever implements x stepping.

I accidentally just forgot to write the second half of the code… :’(

By doing 1/gradient, and incrementing by y, you are essentially flipping the standard straight line equation from y=mx to x=y/m (or x=[1/m]y)by dividing both sides by m. you would need to change a few of the calculations, for it to work properly for y stepping, but it would definitely work.

The Bresenham algorithm is supposedly one of the most efficient ways of doing it, because it keeps clear of using double values and uses ints instead. I haven’t looked into how the Bresenham algorithm works, but if I were a beginner, I would use whatever made sense to me the most, because copying and pasting code when you don’t understand it and couldn’t rewrite it yourself is usually a bad habit to get into.

Yeah, as much as I want things to work… I also want to learn HOW they work… so I know it’s worth something :slight_smile:

Well, if you want the basic premise for my code, so you can modify it to work for you/rewrite it, this is the basic idea i used:

  1. Calculate the gradient and set one of the ends of the ray to be the graph origin.
    2a. Stepping through the x coordinates, use the equation y=mx (where m is the gradient) to find the corresponding y value.
    2b. take the x value and the calculated y value and check to see whether that tile is blocked
    2c. If the tile is blocked, it is not possible to light the final tile
    2c. If you have reached the final tile, it is possible for the light to travel this path
  2. Repeat steps 2 until all tiles in the possible area have been checked.

I hope this has helped you, good luck :wink:

That sounds simple, but it looks a bit more of a pain in the arse in practice… :stuck_out_tongue: Anyway, thanks for all the help, after I’ve changed my map system from an array of buffered images… I’ll have a go at it, then post my results

First attempt didn’t work -

public static boolean tileVisible(int x1, int x2, int y1, int y2, map m){
        
        int deltax = x2 - x1;
        int deltay = y2 - y1;
        int y = y1;
        int ynum = deltax/2;
        for(int x = x1; x <= x2; x++){
            if(m.Map[(int)(x-m.mapPosX)/m.TILE_SIZE_X][(y-m.mapPosY)/m.TILE_SIZE_Y].lightBlock){
                return false;
            }
            ynum+= deltay;
            if(ynum >= deltax){
                ynum -= deltax;
                y++;        
            }
        }
        return true;
    }

I assume you were reading from here:
http://www.gamedev.net/page/resources/_/technical/game-programming/line-drawing-algorithm-explained-r1275

Basically, like the one I showed, what you have coded there only works for 1/8th of the possible lines, you need to scroll down a bit on the page to learn what to change for the others. It is very similar to the first one, but just has a few signs changed and the like.

Also, would you mind explaining why you are accessing map tiles in that array, by minusing and dividing and casting?

Well, because the tile map moves, you need to make it relative to the tile map rather than the canvas surely?
EDIT: Also, shouldn’t that code at the bottom work then?

wait… are your x1, x2, y1, y2 coordinates referring to 2 individual pixels or 2 individual tiles?

If you use the bresenham on tile coordinates rather than pixels, you will need to do far fewer calculations, so it will be much faster. Sorry if I was unclear :wink:

For logic in tile based games, most calculations, such as pathfinding, lighting, etc. will use the tile as the smallest unit for calculation.

You’ve adapted the short bit of code from the middle of the page, the stuff at the very bottom should work, yes.

Right well currently it’s working on pixels… so yeah… I guess I should change that

To use it for tiles would it be exactly the same, but I just have to supply it with tile numbers instead of pixels then at the end check for tile numbers instead of the mess of code I currently have?

yep. You would access the array just by going

m.Map[x][y]

I hope it works out :wink:

hmm… I’ve changed it to that and it’s now not working… the joys of bug fixing, here I come!
EDIT: Derp, just didn’t change what I was printing to system xD may be why…

Well, I’ve got no errors, however my program just sits there on load… I think that it may be a little slow…

It should definitely not be so slow that your code doesn’t run… You should not even notice a low frame rate with only one light…

What actually happens? Does any lighting show up at all?