Efficient Line of Sight Algorithm

Started by
15 comments, last by Steadtler 11 years, 12 months ago
I will concede, though, that if you are:

- In a regular 2D grid (op: check)
- Using only perfectly grid-aligned obstacles (op: bzzzt, nope, tanks are not grid-aligned)
- Populating a majority of the grid cells with obstacles (op: bzzzt, nope)
- Casting fewer LOS checks than obstacles by an order of magnitude (op: bzzzt, nope)

You might be able to win out with a line marching algorithm. But outside of that contrived scenario, spatial partitioning and ray casting will almost certainly be faster, and will most certainly be more robust and flexible. If you do geometry coalescing so that a single long rectangular wall is one rect instead of an obstacle in each grid cell, you get even better gains using ray casting, and as soon as you no longer have perfectly-grid aligned obstacles you can forget getting 100% accurate results from a line march algorithm.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Advertisement
Don't know if anyone has mentioned it yet .. the fastest way to determine line of sight is to precalculate it.

Three most important rules in game programming - precalculate, precalculate and precalculate. smile.png

If you are using a smallish grid like that you can easily generate a PVS (potentially visible set) of what other cells are potentially visible from each cell. This greatly cuts down on the checks you need to do.

e.g. if enemy 1 is in cell 20, 24 and your pvs tells you that the cell your player is in 90.34 is not visible from there due to a wall in the way, that's it, you know it's not in sight. You only end up needing to do realtime checks for dynamic objects that might get in the way.

Don't know if anyone has mentioned it yet .. the fastest way to determine line of sight is to precalculate it.

Three most important rules in game programming - precalculate, precalculate and precalculate. smile.png

If you are using a smallish grid like that you can easily generate a PVS (potentially visible set) of what other cells are potentially visible from each cell. This greatly cuts down on the checks you need to do.

e.g. if enemy 1 is in cell 20, 24 and your pvs tells you that the cell your player is in 90.34 is not visible from there due to a wall in the way, that's it, you know it's not in sight. You only end up needing to do realtime checks for dynamic objects that might get in the way.


while i agree for more complex scenarios, pre-calculating line of sight would be beneficial. In the scenario the OP has described, i find it doubtful he'll need to pre-calculate the line of sight for any serious performance gains. as well, creating a grid based PVS with objects that arn't locked to the grid, their's the small possibility that valid line of sight's could be missed with this method.
Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

Don't know if anyone has mentioned it yet .. the fastest way to determine line of sight is to precalculate it.

Three most important rules in game programming - precalculate, precalculate and precalculate. smile.png

If you are using a smallish grid like that you can easily generate a PVS (potentially visible set) of what other cells are potentially visible from each cell. This greatly cuts down on the checks you need to do.

e.g. if enemy 1 is in cell 20, 24 and your pvs tells you that the cell your player is in 90.34 is not visible from there due to a wall in the way, that's it, you know it's not in sight. You only end up needing to do realtime checks for dynamic objects that might get in the way.

sorry, but my simplistic mind is a bit confused here... to 'pre-calc' LOS for a 10 x 10 grid would necessitate storing a 10x10 table for EACH location (100 locations)... or am I missing something here? Perhaps I am overly paranoid about memory usage. Of course, there are a variety of ways to start pruning this memory usage down, for instance eliminating redundant pairs: if loc (1,1) can see loc (5,3) then no need to also store the fact that (5,3) can also see loc (1,1) - that alone will reduce memory usage by half.

Did I misunderstand the whole pre-calc thing or what?
Yeah, sorry that's posting when tired lol.

Sure to do it you have to partition space into something reasonable memory wise. Whether you can use your grid directly depends how big your maps are. Your screen there looks to be about 20x20 so let's use that for an example:

20x20 = 400 bits per grid square for a naive PVS = 50 bytes

then 50 bytes x 400 grid squares = 20000 bytes, so under 20K, so not that memory hungry.

That's very naive though .. you can also cut this by half if your PVS is reciprocal (i.e. if you can't see 40,40 from 20, 20, then you also know that you can't see 20, 20 from 40,40)

You could also use RLE if memory really was a problem (although the cost of decompressing this probably wouldn't be worth it unless you have a complex environment lol).

Then other ways is to use different partitioning for your space. If for example you used a 10x10 grid for the PVS instead of 20x20, that quarters the memory size. Or use a 2d BSP tree maybe, not sure. Grid sounds more tempting, if you keep it small.

As to how to handle the case of tanks being in different 'parts' of the gridsquare, and the visibility being 1 in some parts and 0 in others, just mark it as invisible ONLY when there are no parts of the grid squares that are visible to each other.

Then if it is marked as potentially visible, do a runtime check. For enemy AI often you can afford to be lazy about this, and there's no reason you need to do vis checks every frame. You could also store 3 (or 4) states in the PVS, instead of just 2 - i.e. definitely not visible, maybe visible, definitely visible, that way you only have to do runtime checks in say 2% of the grid squares.

Given that your current grid is only using 20K, I'd be tempted to just increase the resolution of the PVS grid by about 5x and then just go with the definitely visible / definitely invisible approach, and forego the accuracy.

For a BSP tree you may be able to be more exact than this.

You don't even need to use a BSP tree .. you could use something as simple as AA bounding boxes and probably still get a decent result, the only limit is your imagination! smile.png

And this is pretty much one of the simplest situations for using a PVS. There are some really good solutions in 3d for far more complex environments (see quake stuff using BSP and PVS, or portal engines, etc etc). If you do some googling you should get some good ideas.
Forgot to mention, you can also precalculate your A* pathfinding too. smile.png But it won't take account of dynamic obstacles, you'd need to cope with that separately.

This is in fact my first game and first C++ program.[/quote]

Sorry, just read this .. in this case I'd stick to the simple stuff as dealing with the special cases in visibility determination can be quite tricky. But feel free to have a google as it's really interesting stuff and the kind of thing that most professional games use, as they have to determine visibility (mainly for deciding what to draw) really quickly, on really complex environments.

Awesome effort for your first go! :D
You seem to be in 2d. If you just build a simplified representation of your space (navmesh, or since you seem to be grid-based a quadtree) should make your line of sight checks negligible. There is no reason you shouldnt be able to do hundreds of those every frame.

Also, looking at your original code up there, it seems you're working in polar coordinates (angle/distance). Believe my experience when I say its evil. Work with vector algrebra.

This topic is closed to new replies.

Advertisement