Wednesday, October 21, 2009

Vision - II

More adventures with keeping track of where things are.

Redid LOS algorithm with doubles instead of ints, which doesn't actually affect much of anything, other than where I do my casting to make the compiler stop warning me about it. Ah well, it only took five minutes.

My other hilarious problem came about when I got into circular definition funtimes.
I want the Character class to be aware of the Map class, so it can have a pointer to the Map it's on, so it can get Tiles on the Map as part of its visibility subroutine. Fine, I declare Characters after Tiles.
I want the Tile class to be aware of the Character class so it can have a pointer to the Character standing on the Tile, so it can tell Characters wanting to move onto the Tile whether the position is occupied or otherwise. Doable, just declare the existence of the Character class before implementing the class; as long as I only need pointers to it, it works out okay.
I also want to draw the single topmost object on the Tile, in the order of Character, Item, floor. This lets me cut down on managing drawing the player, drawing the tile, drawing enemies if they're in sight etc. and just draw what's on any given tile. This also keeps me from drawing several tiles over another, which is ugly because the non-colored space on each letter is transparent, so you can see the floor through the player. (Why not leave the black background on each Image and just draw Tiles then Items then Characters? Because then the 3D engine would look odd, silly)
PROBLEM: the draw() routine for the Character class has yet to be defined, seeing as we've yet to implement it, having only declared its existence. Can't I just declare the Character class before the Tile class? No, because then I'd run into similar issues within Character's implementation, only many more times over, seeing as how heavily several functions in Character rely on the Map class, which has a 2D array (vector) of Tiles, and Map also uses Tiles' functions. [From here on out, when I say array, assume I mean vector. I don't explicity say vector because of the Math and Physics associations they have, and I rather like those things too]
So, not too horrible, as it's only one function, and it's a function that most of the classes so far have, along with a member of the Image class (which holds several SDL_Surface*s and deals with scaling and recoloring them, very handy). So I figure, I can inherit both of those from a new base class that just has an Image and a basic draw() routine, and use virtual functions to handle the Images differently depending on the class. Turns out that you can't declare a class's base class without also implementing the class; so I was back where I started. Then an ingenious idea hit, use polymorphism. This would've been fantastic, if Visual Studio didn't forget how to use virtual functions for no apparent reason (either that or I'm doing it wrong but no I'm not shutup), and the base class pointer to a character didn't only use the base class draw function.
So, in an act of spaghettification that I wasn't particularly looking forward to, I declared the Tile::draw() function and then implemented it after the Character implementation. In the separate character.h file. Oh goody.

On further reflection (i.e., typing this entry, a.k.a. the entire reason I'm writing this down in the first place), the polymorphic approach should work, and I can't think of why it doesn't. Trying it again - I first re-read my references and run the debugger at the point at which I call the polymorphic draw() - I try making the base class' virtual draw() a fully virtual function, so it doesn't ever to execute. Turns out that it uses the base draw, even though the Character class redefines draw and has a virtual pointer to it, because the redefinition takes place after the point at which the base->draw() call occurs. So in short, it's an extension of trying to use Characters' draw function without declaring it, only without the compiler errors.
Has no one else needed to do something like this? Oh well, back to the spaghetti. On the plus side, ugly code is better than code that doesn't work, so at least I've got that going for me...

So what did all that have to do with vision?
Not altogether too much, but it does let me do some cool things. For starters, differentiating between visible or out-of-sight tiles is doable without needing to store visibility data on the tiles themselves, which would be useless data most of the time, given the probably small percentage of tiles on a given Map that would be visible at any given time. Secondly, it removes the need to keep track of what has been drawn on what tiles already; it's implicitly assumed that each tile is only drawn once (and would draw the same thing each time it's drawn). Thirdly, keeping track of which enemy is on a given tile greatly simplifies finding which enemy you just attacked, or which ally you just healed, etc.

No comments:

Post a Comment