• 12
• 12
• 9
• 10
• 13

# Weird problem with my 2D Tilemap Lighting-algorithm

This topic is 1803 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hey there,

usually I'm not the one to ask a Forum to help me with my Code-problems, but I've been trying to make this piece of code work for almost 5 hours now and I just don't see what the problem could be.

First of all, what I'm trying to do is I'm trying to generate a lightmap to lay over my tilemap. The way I go about this is i have a closed and an open list. In each iteration, every member of the open list gets his neighbors lit accordingly and is then added to the closed list, while the neighbors are added to the open list. then i reiterate until the light value for the neighbors = 0, complete darkness.

However what happens is the algorithm doesn't stop at complete darkness. Instead, it goes on to light 4 times as much tiles as there are on the map. Laglarity ensues.

I'll add a screenshot and the code that is causing the problems. However if you need additional code, just tell me!

Hope you guys can help me, you're my last resort!

void insertIfNew(const LayerData<float>& layer, const std::vector<sf::Vector2i>& closed, const sf::Vector2i& position, std::vector<sf::Vector2i>* neighbors){
if(layer.isInBounds(position) && !findInVector(closed, position)){
neighbors->push_back(position);
}
}

std::vector<sf::Vector2i> closed;
std::vector<sf::Vector2i> open;
std::vector<sf::Vector2i> open_buf;

open.push_back(pos);

int counter = 0;

while(!open.empty()){
while(!open.empty()){
sf::Vector2i pos = open.back();
open.pop_back();
closed.push_back(pos);
counter++;

std::vector<sf::Vector2i> neighbors;
insertIfNew(*layerLight, closed, sf::Vector2i(pos.x, pos.y + 1), &neighbors);
insertIfNew(*layerLight, closed, sf::Vector2i(pos.x, pos.y - 1), &neighbors);
insertIfNew(*layerLight, closed, sf::Vector2i(pos.x + 1, pos.y), &neighbors);
insertIfNew(*layerLight, closed, sf::Vector2i(pos.x - 1, pos.y), &neighbors);

float new_light_value = capZero((*layerLight)(pos) - 0.1f);

for(int i = 0; i < neighbors.size(); i++){
if((*layerLight)(neighbors) < (*layerLight)(pos)){
(*layerLight)(neighbors) = new_light_value;
insertIfNew(*layerLight, closed, neighbors, &open_buf);
}
}
}
open = open_buf;
open_buf.clear();
}
std::cout << counter << " tiles processed!" << std::endl;
}


##### Share on other sites

It's hard to say without seeing the implementation for capZerp and LayerData (it looks like you have the () operator overloaded with a vector2i parameter?).

Is there a reason you're implementing your light like this? I would just use circle with a certain radius. Then iterate through all positions within the bounds of the circle, and set the light equal to some function of the distance to the center of the circle. A much simpler algorithm.

This would get you a circular light instead of a diamond-shaped one like you have. If you really want a diamond-shaped one you can just use a different function.

##### Share on other sites

After getting some sleep however, I was finally able to fix the problem.

The issue was that this line here:

if((*layerLight)(neighbors) < (*layerLight)(pos)){


which should have been this instead:

if((*layerLight)(neighbors) < new_light_value){


Even though I don't understand how this led to an almost infinite iteration, I'm now happy it works and that i can advance to other features :)

The reason I didn't want to go with your circular approach is that I have less control over what light level the tiles have. My idea was to have stone block more light than air... You may know the game Terraria. That's the game that inspired the lighting system.

Thanks again,

Xel