home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the 3D Game Programming Gurus / gurus.iso / Articles / TileGraphics / Tilegraphics.txt
Encoding:
Text File  |  1999-05-15  |  25.8 KB  |  554 lines

  1. You have to call him!!!!
  2.  
  3. ===================
  4.   Tile  Graphics
  5.   Techniques 1.0
  6.     April 1996
  7. -------------------
  8.  By Jason McIntosh
  9.  
  10. Tile Graphics Techniques 1.0 is copyright 1996 Jason McIntosh.  All rights 
  11. reserved.  Freely distributable if unmodified and in its entirety.
  12. ===============================================================================
  13.  
  14.  
  15.  
  16. To contact the author via email (until June/July 1996):
  17.     stugbond@acs.eku.edu
  18. This is a friend's account.  He let me use it for this text and any responses
  19. I might (hopefully) get.  I should have my own account in August 1996, and I 
  20. will release an update at that time.
  21.  
  22. Though this text is not shareware, if you find it worthy of a donation, I will
  23. gladly accept any amount of money you offer (since I am a starving programmer
  24. looking for an employer).
  25.     1427 Fairlane Dr.
  26.     Richmond, KY 40475
  27.     USA
  28. This is my mother's address, since it is effectively permanent.
  29.  
  30.  
  31.  
  32. What's This Document (Not) About?
  33. ------------------------------------------------------------------------------
  34. I wrote a CRPG for my Amiga and got about 85% finished when I bought my PC and
  35. dropped the Amiga project to learn PC programming.  The point is that while 
  36. that game was/is really cool, I have learned and developed much since then.  
  37. Here's my (partial) full disclosure :)
  38.  
  39. This document will cover graphics in the style of Ultima 6 (presumably Ultima 
  40. 7 as well, but I have never played it-- read on).  I will also discuss many 
  41. of the same techniques that Greg Taylor covered in his Tile-Based Games FAQ.  
  42. That is one reason that I have composed this document, because I found the 
  43. information in Greg's FAQ to be somewhat disappointing.  I hope to present 
  44. some ideas that will advance those he overviewed.  Granted, he covered lots of
  45. things I won't cover here (roof tiles, hidden map areas, palette shifting),
  46. but there are so many fundamentals that could be implemented in a better way, 
  47. I had to put out an alternate solution.  Oh yeah, it is presumed that the 
  48. reader has a solid understanding of C programming.
  49.  
  50. While Mr. Taylor tended to emphasize the 640K barrier, I think that everyone
  51. should get a 32-bit, protected mode compiler.  Let's face it, the small
  52. overhead of running a DOS extender with your protected mode program is
  53. negligible in the face of the benefits gained.  I feel it's a fair assertion
  54. to assume that people who play games have at least 4 megs in their machine.
  55. Catering to the lowest common denominator (i.e., 286/640K) is a good thing as
  56. long as that denominator isn't too low.  I think nowadays, a 486-33/4meg is
  57. a decent denominator.  The hassles of EMS and conventional memory simply
  58. disappear when protected mode is used.  I've never been more frustrated by
  59. this situation than when I couldn't get Ultima 7 to run on my snappy Pentium
  60. because I had to create a boot disk and still couldn't free the conventional 
  61. memory required (without purchasing a commercial memory manager).  I own U7, 
  62. but I've never played it.  That kind of annoyance can be avoided by simply 
  63. using a "modern" compiler, with the added bonus that most of the time, it will 
  64. run in the increasingly popular environment, Windows 95.  (Sorry to be ranting 
  65. but that's another reason I'm writing this document :)
  66.  
  67. Note:  I am assuming that you are interested in CRPGs since they are the most
  68. common game genre to employ this sort of graphics.  Of course, the techniques
  69. can be applied to any game or genre (ie, a strategy game).
  70.  
  71.  
  72.  
  73. Vocabulary
  74. -------------------------------------------------------------------------------
  75. For the uninitiated, here's a list of some terms I use and their meanings
  76. relative to my conceptions of them.
  77.  
  78. Clipping.  This is limiting the plotting of a tile to within an arbitrary 
  79.     boundary (the screen edge, for example).  If the tile's graphic imagery
  80.     crosses this boundary, it is "clipped" or trimmed so that only the area
  81.     within the boundary gets drawn.
  82.  
  83. Masking.  When a tile is draw to the screen with masking, all pixels of a
  84.     predetermined color are not plotted so that the tile will only cover
  85.     the background where the shape of the graphic dictates.  No big, blank
  86.     boxes around the graphic imagery.
  87.  
  88. NPC.  Stands for Non-Player Character, or anyone that the player cannot
  89.     directly control.
  90.  
  91. Object.  I refer to these in this document not in the sense of OOP, but as
  92.     an independently defined data structure that describes something in your
  93.     game universe (a person, an item, or a map entity).
  94.  
  95. Tile.  Also called an icon, a bob, a sprite.  It is, simply, an arbitrarily
  96.     sized bitmap (though commonly 16x16 pixels).
  97.  
  98.  
  99.  
  100. Plotting Tiles
  101. -------------------------------------------------------------------------------
  102. The first task to creating a tile-based game is plotting the landscape and its
  103. inhabitants.  Well, I will assume that you have several routines already: 
  104. A)  Plot a 16x16 tile, without masking (which is faster than with masking).
  105. B)    Plot an arbitrarily sized tile, with masking.
  106. C)    Either of the above routines with clipping (though this is optional).
  107.  
  108. I won't waste time getting detailed about how to plot tiles, as there are many
  109. good tutorials available on the subject (get XLib and don't worry about the
  110. nuts and bolts of it).
  111.  
  112.  
  113.  
  114. Maps and the Lay of the Land
  115. -------------------------------------------------------------------------------
  116. Greg Taylor mentions multiple layered maps.  He's absolutely right: you will
  117. need multiple layers to get any kind of complex graphics in your world.  But,
  118. he didn't take the idea far enough.
  119.  
  120. Let's look at a typical way of implementing a map: arrays.  Good ole arrays.
  121. When we all programmed in BASIC and arrays were all we had, sure, use them
  122. for your maps.  Simply declare map[100][100] and there you have it.  Want
  123. multiple layers?  Okay, map[3][100][100].  There!
  124.  
  125. Well, here's what I suggest.  Keep the first declaration.  But what we want to
  126. achieve is massive flexibility.  We don't want to be limited to 3 layers or
  127. waste memory when we need less.  (Side note: efficiency is _always_ of utmost 
  128. concern!  I don't care if your target platform has 32 terabytes of memory,
  129. always optimize for space and speed!)  So how do we get unlimited layers while
  130. using only as much memory as required at any given moment?
  131.  
  132. About the time you take Pascal in your CS cirriculum, they'll teach you about 
  133. a thing called a linked-list.  Perhaps already you can guess what I'm about to
  134. explain...
  135.  
  136. If we define our _entire_ map as map[100][100], then for each element in that
  137. array, we define a list header.  Yep, each element is a linked-list.  You
  138. might be thinking, "But what about space optimization?  Won't 10,000 linked
  139. lists be wasted memory?"  Below we'll talk about ways to access the map
  140. incrementally, which will solve this huge array problem.  As it stands, the
  141. answer to your question is still "No."
  142.  
  143. Remember that we had map[3][100][100], which (at minimum) is 30,000 bytes.
  144. Granted, a linked list header may be 8 bytes itself which means map[100][100]
  145. is 80,000 bytes.  Yes, it's bigger, but even without special techniques for
  146. accessing only part of the map at once, the payoff in flexibility and graphic
  147. enhancement makes it worth the size.  This is another reason for using a
  148. protected mode compiler-- when you absolutely have to, you can have these huge
  149. structures without worry of hitting any stupid 640K limit.
  150.  
  151. Okay, so you accept what I've said so far?  Okay, then, on to the map
  152. representation.  How do we use these linked lists to achieve multiple layers?
  153. This will require some sort of map "object" definition.
  154.  
  155. struct map_tile {
  156.     struct map_tile        *next;         // pointer to next in list
  157.     struct tile_gfx        *tile;        // pointer to graphic imagery object
  158.     char                type;       // keep reading...
  159.     char                bitflags;
  160. };
  161.  
  162. For example:
  163.  
  164. map[0][0] 
  165.     LIST_HEADER -> map_tile -> map_tile -> NULL
  166. map[1][0]
  167.     LIST_HEADER -> map_tile -> NULL
  168.  
  169. ...and so on.  Using this setup, the first map_tile is the bottom-most layer
  170. in your map.  Each successive layer simply adds another map_tile to that
  171. specific map position (ie, map element, ie, list).  This way, you could stack
  172. twenty tiles on one map position, while having only two on a tile nearby-- with
  173. no memory wasted on empty spaces!  That is the big payoff for this technique.
  174.  
  175. I would advise that you follow some conventions.
  176. A)  The first map_tile in a list should be a ground layer (ie, grass, sand).
  177.     It should also be a constant 16x16 tile that should be plotted without
  178.     masking.
  179. B)    All map_tiles after the first can be variant sized (up to 32x32) and should
  180.     be plotted with masking.  These successive layers will be trees, rocks,
  181.     walls, people, monsters, swords, treasures, and anything else.
  182.  
  183. If you're wondering how I intend to handle a 32x32 tile in a 16x16 tile world,
  184. keep reading.  Let's get the basics down first.  In fact, let's drop this for
  185. the moment and discuss some fundamental ideas about representing NPCs and items
  186. for a game.
  187.  
  188.  
  189.  
  190. The Flesh of a Soul
  191. -------------------------------------------------------------------------------
  192. I should explain that I delineate objects from their graphics.  That is, there
  193. are separate structures for objects and for their graphic imagery.  For
  194. example:
  195.  
  196. struct npc_object {
  197.     struct npc_object    *next;    // keep a pointer handy for later
  198.     struct tile_gfx        *tile;    // pointer to the graphic imagery for this guy
  199.     struct attributes    atts;   // str, dex, hp, inventory, etc.
  200.     char                x_loc;    // location on map
  201.     char                y_loc;  // may need to be an unsigned short if the map
  202.                                 // is bigger than 255x255 squares
  203. };
  204.  
  205. struct tile_gfx {
  206.     struct tile_gfx        *next;      // always
  207.     char                *imagery; // pointer to the actual bitmap data
  208.     char                x_size;   // size in pixels
  209.     char                y_size;
  210.     char                x_offset; // for handling those 32x32 tiles
  211.     char                y_offset;
  212.     char                 bitflags; // 8 bitflags (ie, masked?, animated?, etc)
  213.     char                align;       // align to dword boundary
  214. };
  215.  
  216. So when a person or monster is plotted to the screen, the tile information for
  217. each character can be totally different and referenced through the NPC
  218. structure.  Likewise for items.  Remember that these graphics will be drawn 
  219. with masking so that the map background can still show through.
  220.  
  221. With this in mind, we commence with map specifics.
  222.  
  223.  
  224.  
  225. Plotting Map Layers
  226. -------------------------------------------------------------------------------
  227. struct linked_list map[100][100];
  228.  
  229. This is our map definition.  We have a separate linked list holding all NPCs
  230. that are active and their relevant information.
  231.  
  232. In Ultima 6, if a character went in a doorway, the character appeared under
  233. the archway.  The characters were further obscured by tall signs, and the like.
  234. This is a very cool and realistic effect.  (Though I haven't done benchmarks
  235. on any of the mapping techniques here, I suspect that what I'm building up to
  236. will require a fair amount of horsepower.  Hopefully our common denominator
  237. 486-33 will suffice.)
  238.  
  239. To achieve this obscuring effect, I would flag each map_tile as either "under"
  240. or "over" (thus, the need for the bitflags field in the map_tile structure).
  241. The bottom layer (ground) will definitely be "under" since all tiles get
  242. plotted over these regardless.  Things like trees, walls and open doorways
  243. should be "over" since the player could potentially appear obscured by such
  244. objects.  For best efficiency, sort all these tile lists so that "under" tiles
  245. come before "over" tiles.
  246.  
  247. Here's how the plotting algorithm should work:
  248.  
  249. A)    Plot all ground tiles (ie, the first tile in each list).
  250. B)    Plot all tiles flagged "under."
  251. C)    Plot all NPCs and items.
  252. D)    Plot all tiles flagged "over."
  253.  
  254. The plotting should go from upper-left to lower-right to appear correct.
  255.  
  256.  
  257.  
  258. The 32 Pixel Question
  259. -------------------------------------------------------------------------------
  260. Now that the basic map structure and function is understood (it is, isn't it?),
  261. we can get to the 32x32 tile question.  Since all tiles have a 16x16 "base"
  262. anything over this size will simply be plotted with an offset.  The offset
  263. should force the lower-right corner of the tile to align with the 16x16 pixel
  264. base.
  265.  
  266.     +--+
  267.     |  |
  268.     |  |
  269.     +--+ <-- there's the "base" point
  270.     
  271.   +----+
  272.   | +--|
  273.   | |  |
  274.   | |  |
  275.   +----+ <-- the larger tile aligns to this point
  276.  
  277. A tile that is 20x17 would have an x_offset of -4, y_offset of -1.  This is
  278. calculated with (16 - x_size), (16 - y_size).  If a tile is smaller than
  279. 16x16 (a knife, for example), then it will have a positive offset.  Look:
  280. a 7x10 tile has +8 x_offset, +6 y_offset.
  281.  
  282. That is, unless you want to center small tiles in the 16x16 pixel space.  
  283. That's easy enough.
  284.  
  285. So now we see how a larger tile can obscure those in adjacent locations.  A
  286. very tall tree would do this.  This ain't Ultima 4 anymore!  Let's get out of
  287. the 80's technology and at least catch up to early 90's.
  288.  
  289. With this outline, hopefully you can exploit the possibilities yourself.
  290. Imagine the flexibility over the "old" array technique.  Instead of drawing
  291. millions of tiles for each piece of scenery like a plain wall, another wall
  292. with a torch on it, etc, you simply draw the plain wall, draw the torch,
  293. then stack the picture tile on the wall tile.  You can reuse the torch for
  294. different wall types without drawing a new wall with a torch on it.  Again, 
  295. this saves storage space by having fewer graphics but with more variety.
  296.  
  297.  
  298.  
  299. Material Objects and Possessions
  300. -------------------------------------------------------------------------------
  301. Handling item objects, if you want Ultima-level technology, requires that each
  302. object be defined in a detailed way and managed much like NPCs-- with a linked
  303. list.  This is a little more complicated, but the enrichment of the game
  304. environment is incredible.  In my Amiga implementation, for example, I defined
  305. objects that can be moved, carried, used, contain other objects, etc, just
  306. like Ultima 6.  This allows your universes to really come to life.
  307.  
  308. All you really have to do is have a main item list, call it all_items.  This
  309. list will hold each and every item that exists in your world from a bedroll
  310. to a candle to a ration of food.  It's handling this list safely and cleanly
  311. that presents the major problem.  And if you have a solid knowledge of lists
  312. this is not much of a problem.  I suggest that you build a list library of
  313. common functions (ie, insertion, deletion, creation, destruction) or find
  314. a library that already exists and works reliably.  Then apply these concepts.
  315.  
  316. But now, let us aside to something else of relevance to our all_items linked
  317. list.
  318.  
  319.  
  320.  
  321. Accessing the World Map Incrementally
  322. -------------------------------------------------------------------------------
  323. Since I've mentioned Greg Taylor's FAQ previously, I will come to it again.
  324. He suggests holding the entire map on disk and "paging" in only the areas
  325. that are close by.  That's exactly what I suggest.  The only hairy part is the 
  326. nature of my maps.  They are linked lists and this makes for a complication 
  327. when accessing them bits at a time.
  328.  
  329. The main barrier, then, is the storage format.  How do we store a map when
  330. it's a huge array of linked lists and link nodes?  Well, there are many
  331. possibilities.  One is to encode the data with "identifier" bytes.  There are
  332. several variations of this.
  333.  
  334. For each map location (map[x][y]), we write to disk the number of nodes in
  335. each list at that location (minimum 1, because we have to have a ground
  336. tile).  This is very simple.  To retrieve it is the tricky part.
  337.  
  338. A)    Read one byte.  If it is zero, then we have no more nodes for the current
  339.     x:y position.  If it is non-zero, we have to read that many nodes from
  340.     disk, building the list on the fly.
  341.     a)    Keep reading nodes until the Nth node is finally read.
  342. B)     Repeat step A) until the entire section of map we want is read into memory.
  343.  
  344. In code:
  345.  
  346. char            c, i, x, y;
  347. struct map_tile *mt;
  348.  
  349. x = current_x_position; // these will probably be assigned by a loop
  350. y = current_y_position;
  351. while (1) { // loop infinitely, so be careful!
  352.     c = fgetc(filehandle); // read our encoding byte
  353.     if (feof(filehandle)) break; // end the loop, we are out of data
  354.     // you'll also check to see if you've read all neccessary data and
  355.     // use break to exit the loop
  356.     for (i=0; i<c; i++) { // read as many nodes as encoded
  357.         mt = newnode(); // remember to do failure checks and handle errors!
  358.         fread(mt, sizeof(struct map_tile), 1, filehandle);
  359.         addnode(map[x][y], mt); // put the new node in the map lists
  360.     }
  361.     // continue reading nodes until all map data is in memory
  362. }
  363.  
  364. This code fragment leaves out quite a bit, like list details and deciding
  365. what map coordinate range you need to read.  At least you get to see the
  366. principles in action.  There is _lots_ of linked list juggling.  You must be 
  367. very, very careful about memory leaks and such when programming this.  Take 
  368. your time, comment your code, and _know what you're doing_!  With this sort
  369. of code, you need to plan out exactly what to do.  Some more than others, but
  370. everyone needs a plan.
  371.  
  372. Another method would require that you add two new fields to the map_tile
  373. structure:
  374.  
  375. struct map_tile {
  376.     struct map_tile        *next;
  377.     struct tile_gfx        *tile;
  378.     char                type;       
  379.     char                bitflags;
  380.     char                x_loc;        // store each tile's location here
  381.     char                y_loc;
  382. };
  383.  
  384. Now, when you read a tile, it has the location information in it.  You simply
  385. insert the read node into the according list in memory.  I like the first
  386. method better, though, because it uses less disk space since the encoding
  387. only requires one byte, especially for maps > 255x255 that will need a short 
  388. for index reference.  I leave the final decision with you, because there are
  389. better ways to implement this, I'm sure.
  390.  
  391. Now that we can access the map at arbitrary points from disk, how do we decide
  392. what to store in memory and when to load more?  As Greg states, look at the
  393. current map "chunk" as a set of 9 small areas, theoretical boundaries
  394. actually...
  395.  
  396.     +--+--+--+
  397.     |  |  |  |
  398.     +--+--+--+
  399.     |  |  |  |   The player is always located in the center area
  400.     +--+--+--+
  401.     |  |  |  |
  402.     +--+--+--+
  403.     
  404. Each small area might represent a 10x10 map chunk.  As the player moves across
  405. the middle boundaries, the map data is shifted (scrolled) and whatever areas 
  406. are "blank" afterward will be the ones we load from disk.  Refer to Greg's FAQ 
  407. for more explanation, if you need it.  Hopefully, it is self-evident.
  408.  
  409. I will only say that you must remember to deallocate all nodes no longer
  410. needed.  This cannot be over-stated.  You will find many, many bugs lurking
  411. in this section of your program if you are not an alert programmer.  I learned
  412. this through tedious hours of memory leak chasing.  Tedious hours.
  413.  
  414.  
  415.  
  416. And What of Our Possessions
  417. -------------------------------------------------------------------------------
  418. We come back to our discussion of the all_items linked list.  Since your
  419. world may be exceedingly large (my project included over 400 items at 85%
  420. completion), you will not want to keep this whole list all the time.  If
  421. memory allows, sure, keep it in memory for speed.  If not, then access it
  422. from disk when needed.  Elaboration follows.
  423.  
  424. Like the huge map, which only comes into memory in chunks, we only need parts
  425. of the all_items list in memory at any one time.  Two reasons: 1) it is far
  426. less space consuming than keeping 1000 items in memory all the time, 2) it
  427. is much quicker when performing operations on the items (ie, searches, etc).
  428.  
  429. Point 2) is particularly of interest since we will be dealing with those items
  430. closest to the player the most often.  Doesn't it make sense to keep only the
  431. necessary items in another list, a "local" list?  Of course it does.
  432.  
  433. Each time the player wants to manipulate an item (say, picking up a sword), the
  434. program will have to find the item in question by searching the list.  Then it
  435. will have to perform some operation(s) on it (ie, place the sword in the
  436. players possession).  This is not to mention the fact that each graphic update
  437. will require searching the list of items to determine which are visible and
  438. which are not.  Now this makes perfect sense, right?
  439.  
  440. So we establish a secondary linked list: local_items.  This list will grow and
  441. shrink as the player moves through the landscape.  Items will get moved to and
  442. from this list and the all_items list.  all_items will hold items not currently
  443. used.  I would recommend holding all_items in memory when possible for speed
  444. issues and issues of altering the game state-- that is, as related to saved
  445. games.
  446.  
  447. You see, if you want to save a game in progress, all object lists must be 
  448. written to disk.  But if you are constantly writing over the all_items list,
  449. and the computer crashes, that game state is ruined because part of all_items
  450. was in memory, and not all of it was on disk since item in local_items are
  451. literally removed from all_items.  Follow?
  452.  
  453. The solution is to simply store all_items, for game use, in a temporary copy
  454. of the initial game state.  That way, all previous information is preserved
  455. and you safely work with a copy.  But to avoid all this hocus, keep the
  456. lists in memory at all times, only updating the disk image when a game is
  457. saved.  I hope all that soaked in.  If not, re-read it in a couple days.
  458.  
  459.  
  460.  
  461. Straying From the Path
  462. -------------------------------------------------------------------------------
  463. I seem to have gone off on a few tangents here.  But I think that they are all
  464. an integral part of the big picture.  Now I would like to address some of the
  465. problems from Greg's FAQ that this framework fixes (I'm not picking on him,
  466. but I am hopefully building on his information), with direct references to his
  467. work.
  468.  
  469. III: Walkability
  470.     To create a map space that cannot be crossed by the player, simply use the
  471. bitflags to denote a barrier object.  This can be either a map_tile, a 
  472. npc_object, or an item_object.  If any one of these appears in the location
  473. that the player is about to move into, then movement is restricted.  Simple
  474. and clean, and no need to make any limitations on the map or objects.
  475.     In fact, I divide barriers into several classes.  One is a total barrier.
  476. Another only restricts movement-- but not things like arrows or spells flying
  477. across them.  Another only restricts arrows and such, but not movement (for
  478. magical sanctuaries).  This can all be achieved by using those simple bitflags 
  479. in each object structure.
  480.     For those of you who want to see code...
  481.  
  482. #define flag_BARRIER      (1)    // this blocks movement and missiles
  483. #define flag_MOVEBARRIER (1<<1) // block movement only
  484. #define flag_MISSLEBAR   (1<<2) // block missiles only
  485.  
  486.     Then, wherever your code handles movement...
  487.     
  488. if (map[x][y].bitflags & flag_BARRIER) // this checks for the bitflag
  489.     player_cant_move();
  490.  
  491.     Of course, accessing the map data will involve checking each object in the
  492. x,y location list in question for these flags, but you get the idea.
  493.  
  494. VI: the OBJECT layer
  495.     Greg has no autonomous objects.  His maps hold object information, much
  496. like Ultima 4 probably did.  With my system, there is no such restriction and
  497. no limitations.  You can stack gobs of objects and hordes of people, too,
  498. since they all exist independent of the map data.
  499.  
  500.  
  501.  
  502. So Close,  Yet So Far
  503. -------------------------------------------------------------------------------
  504. I could go on typing about different areas of CRPG making for hours, but I
  505. want to limit this document to tile graphics related problems.  I should
  506. probably work all of this up into a book and include a demo and tons of
  507. source code, but who would publish it? :)   Potential future installments...
  508.  
  509. Using event flags to trigger changes in the game world (ie, when a quest is
  510. completed or a decisive action made), the writing of "data compilers" to 
  511. create attributes for your objects in a script file (as I did with my Amiga 
  512. project), creating a map/object/graphics editor, implementing a system of 
  513. spells and using "reagents" to create them, character creation routines, NPC 
  514. speech system, NPC artificial intelligence-- especially combat where NPCs 
  515. intelligently arm themselves based on circumstances and resources at hand (ie, 
  516. close range weaponry, spells, abilities, etc), animating objects.  The list 
  517. goes on.  I have experience programming all of these things, and I plan to put 
  518. that experience to use and create a CRPG for the PC.  I am in college, so it 
  519. will come slowly, but one will emerge.  Why don't you explore these subjects
  520. with me, and let's create some good games.
  521.  
  522. If there is sufficient interest, I might write up more technique documents.
  523. That all remains to be seen.  Give me your feedback.  I want to discuss these
  524. things with people, because nobody seems to want to.  I suspect they fear that
  525. people will rip-off their ideas.  Let me state a fact, everyone:  technical
  526. achievement does not make a great game.  If everything I said here you can do
  527. better, you are at no particular advantage of making a better game than me.
  528. The quality lies in content.  So quit worrying about someone stealing your
  529. techniques and algorithms, because even if they did, that doesn't mean they
  530. will undermine your success as a game designer.  
  531.  
  532. SPEAK UP!  I would love to hear alternate/better solutions to these 
  533. programming puzzles.
  534.  
  535.  
  536.  
  537. And Now I'm Off, Dear Patsy
  538. -------------------------------------------------------------------------------
  539. Please spread this to any technical forum and medium (unmodified, of course)
  540. that you see fit.  I don't have access to any commercial nets, so uploading
  541. there would be appreciated.  Spread me on the internet as well.
  542.  
  543. Happy creating!
  544.  
  545. Jason McIntosh
  546. stugbond@acs.eku.edu
  547.  
  548. Greets to Ed Mackey and Roy Millican (both Amiga guys who probably won't ever
  549. see this).  
  550.  
  551. And hello-nice-to-meet-you to Mark Feldman: where's PCGPE 2?  I'm a willing
  552. contributor.  :)
  553.  
  554. It's after 4am!  I've got to go to bed!