LOS (probably) solved
Well, the answer to my problem seems to come from an unexpected place: threading! I'll try to explain briefly:
The profiling seems to show that my bottleneck is Line Of Sight calculation - it's called a lot, specially if there's a lot of monsters/lightsources on the level, and it made the game quite slow.
My first attempt was try other algorithms instead of my custom-made one: but they were either not accurate enough, or slower. I just couldn't get it done! Yesterday, I implemented a variation of Bresenham's algorithm, to have a ray-casting system -- too slow.
Fortunately, the start of a solution came from Guild and PGuild author Antoine, in a rec.games.roguelike.development discussion: when he generates a field of view (FOV) in his game, he caches it. Then, if another FOV has to be generated at the same place (if a monster walks into it, for example) it's retrieved from the dictionary instead of recalculated. If anything that can change FOV happens - like a door opening or closing - he clears the cache of the level. A brilliant idea, methinks!
So, doing just that improved the game slightly - not enough, but nice, specially when (for example) a monster carried a light source around. The first change I made to it was make it so when a door opens/closes it doesn't clear the whole cache - only those tiles that the door can "see". Overall, and very specially on big levels, this made an improvement. But I wanted more caching.
But I still thought - hell, many times you just sit there looking at the screen, and that pause of one or two seconds could be used for so much calculating, instead of doing it all between player turns! So I decided to try threading, and so far it seems like another nice boost to game responsiveness.
Basically, when the player enters a level, a new daemon thread is created, a "cacher". This little thread starts generating FOVs of every single freakin' tile of the level map, and caching them all. I haven't noticed slowdown while it's running, and the effect is quite noticeable, specially in monster-packed levels. I don't know if memory usage might be an issue, but so far - and with reasonably large maps - it hasn't at all.
So, for now, and with a grain of salt, since problems might still arise, I'm happy. The game is still a little slower than I'd like when there's 20+ monsters active at the same time, but it's definitely faster than it was before. I will leave LOS for a while and see how it goes, then come back if it still seems slow or this solution has obvious flaws that I haven't seen yet. Next step - slightly smarter monsters.

1 Comments:
Good solution. I had to do something like that for indexing a search engine in a web app.
For python there is an alternative to full threads:
Fibranet is a nice, cooperative threading solution for Python. It gives the advantage of threading, without the overhead of the full-task switch. You do have to call 'yield' in order to 'switch tasks', so you'd find points in the LOS algorithm to add these yield points.
The documentation is lacking, but I do have some samples that show use of the threading and interprocess communication features of Fibranet.
This would be similar to what stackless python provides. I like the advantage of it using a standard python distribution.
Post a Comment
<< Home