[DM-dev] ancient ramblings of man
Brought to you by:
acdalton,
henningsen
From: Stephan B. <st...@wa...> - 2001-04-28 21:52:01
|
Morning, y'all, This is just some rambling. Nothing terribly important, as I sort out my own thoughts on the subject... I think I've basically got most of the hierarchical stuff down. Here's a sample usage of the current API: RandomDungeon top( 60, 60, "dungeon" ); // init's a random dungeon. DungeonElement *de = new Room(); de->setName( "roomX" ); de->move( 27, 17 ); de->add( new Wall( 0,0,6 ) ); de->add( new Wall( 0,0,4, DungeonElement::Vertical, "wall2" ) ); top.add( de ); top.toCerr(); // prints to cerr. class 'RandomDungeon' does not yet exist, but is a hypothetical DungeonElement subclass which initializes some random dungeon parameters at instantiation. I'm not at all happy with what I've done with save/load, so I'm going back to the drawing board on that. It's gotten too complex to be manageable, so I'm gonna rewrite that from scratch. The problem lies not so much in the conversion from hierarchical data to a flat board or data format (like the ini-style file approach), but in the reversing of that. If we can't read back our own output format, I see that as a problem. If we restricted outselves to a flat data structure the load/save would be simpler, but the whole thing would not be nearly as extendable or easy to use. Right now the runtime flexibility is really good, but the method of loading and saving those states sucks, largely because the data format has to be flat, while the structure is not. I can envision and approach like this, but back-parsing it'd be a real bitch: dungeon{ name=My Favorite Dungeon; randomSeed = 42; room { name=Dwarvish Beer Hall; width=5; height=7; x=17; y=19; wall { name=1; x=0; y=1; length=7; orientation=1; // vertical door { name=1; point=3; // where on the wall it is. }; // wall }; // room }; // room }; // dungeon Writing into that format is no problem. Reading that format back is the problem. The parser wouldn't be much fun to write, mainly because it'd have to do so much syntax checking. Plus it'd be limited to a hard-coded set of class types (the tops of the classname{} blocks - the properties within them would still be _completely_ dynamic). We could use a classloader to completely get around that problem, but the only classloader code I know of is GPL (Peter doesn't want GPL in code), and I don't think it'll work under Windows. Actually, in Perl I could parse it with little problem, I think, but in C... gimme a week, maybe. I wonder how much work it would be to port the Perl-Compatible Regular Expressions support from the PHP code... THAT would be useful. I don't know if PHP's license allows stealing code from it. I'll have to look into that. Anyway... Note that in the above sample hierarchy, all children use parent-relative X/Y values. These are converted at render-time to the rendering object (the DMGrid, which I have not yet built, but is on my list). This is MUCH simpler to maintain, and allows moving of whole branches of objects without having to deal with child positions relative to the new target. For example, we could copy the wall{} block from above into another room, or the top-level dungeon, and it'd still be a valid object at the same position, relative to the new parent. Imagine having to move all your walls every time you wanted to move a room! I think I'm going to skip the load/save for tonight and move on to the rendering. That sounds like more fun right now. I imagine this of consisting of a DMGrid object, with a very simple API: DMGrid( int w, int h ) void set( int x, int y, int val ) int get( int x, int y ) and other such stuff. Most of this will simply be swiped from the current DM object. The special one will be: void render( DungeonElement &de ) This will call de.renderTo( *this ), which is defined in DungeonElement, as: void renderTo( DMGrid &gr, int xoffset=0, int yoffset=0 ); This gets recursively called on all children of this DungeonElement object, adjusting the x/y offset as we climb down the tree. That x/y is where the children consider to be their 0/0 starting point for all rendering operations. The DMGrid will allow these rendering operations to go outside it's bounds - it will simply ignore such requests. This allows us to have elements which "run off" the DMGrid, like a lake (hey, how about a RiverCrawler object, to make underground lakes and streams?). Thus the above C++ code could simply add this code to render the whole dungeon to the console, for example: DMGrid gr( top ); // will get his size from top's size. top.renderTo( gr ); cerr << gr; // dump output to the console And adding new terrain types will not affect this code at all, like: de = new LavaPit( 2,2 ); // DungeonElement subclass room->add( de, 3, 4 ); // 3,4 == position But, see, theres' the catch: this flexibility dies when we can't load these new classes dynamically from our saved data. Our parser would have to know about type "lavapit". We could get around that 100% with XML and a classloader, but I don't know of any XML libs which are widely available on Windows and Unix, either. This is exactly the approach QUB uses to dynamically determine data types from XML data and instantiating the correct classes, searching for them as DLLs if needed. We don't NEED XML to do it, but we need some format which we can parse. Of course, we can write our own parser, aber das dauert eine Menge Zeit. And we'd still need a classloader to make it extenable without having to update the parser with each class. Oh, Hey, Pete! I just realized: with this rendering approach, QUB can offer view-as-the-crawlers-create rendering simply by subclassing GMGrid() and catching all the set()'s so I can update the pixmaps. Cool. Anyway... See y'all! ----- Stephan Beal - st...@wa... http://qub.sourceforge.net - http://stephan.rootonfire.org http://dungeonmaker.sourceforge.net "Now I'm not normally the kind of person who likes to trespass, but sometimes you just find yourself over the line." -- Bob Dylan |