Well, this weekend I was able to implement basic terrain brushes in OP2Mapper 3. That is, a point and click way to place terrain and have the mapper do the edges for you, like most map editors.
(http://hacker.outpostuniverse.net/mapper/brushes.jpg)
As you can see it's pretty primitive right now, due to the way the OP2 transitions work.
My brush system works by dividing each tile into 4 pieces / corners. Each corner is assigned a value which corresponds to a certain brush / terrain type.
When the user places a tile, the mapper fills in the top, left, right, and bottom edges with transition pieces that match up (matching is determined by comparing pieces that touch on tile edges). It then fills in the other corners as well based on the edge pieces already placed. Example:
+--+--+
|ab|ef|
|cd|gh|
+--+--+
The numeric value assigned to piece 'b' must equal that of 'e', likewise 'd' must equal 'g' to match the two tiles left to right. If they don't match, a tile is selected on the left side that would match. If a match still isn't found, the mapper doesn't modify that tile (the mapper can't continue since it can't 'guess' what tile should go there, it has to use a list of definitions).
The problem is, in the tileset there are various transition pieces that work, but have to match up correctly with each other to look right (for example, two top to bottom grey->orange transitions. One has more orange than the other. Placed side by side they wouldn't look right). Thus I need to find out a reasonable way to do this (I want to keep the quarters system because it's simple to implement and use). Perhaps by using some sort of exclusion list, i.e. Tile A cannot appear next to Tile B.
Programming a more complex system (i.e. something that divides a tile into 1/16ths) isn't hard to do. The problem lies in the definition of the tile pieces themselves; that is, it would place a lot more work on the person writing the definitions / the tileset designer.
Currently, it stores the terrain type definitions in a "terrains.ini" file, with a format like so:
;Header section describing the terrains. The names are just used by humans, the mapper doesn't know or care about them.
[TerrainInfo]
;Number of terrain types
NumTerrains=2
0=Lava Flow
1=Rocky Terrain
;Now come the tile definitions. They have a format:
;tileID=nw,ne,sw,se
;where nw/ne/sw/se are the terrain IDs (0 or 1 as defined above) assigned to each corner of the tile
;There are sections for each tileset name, as you can see
[well0001]
0=1,1,1,1
;so on...
[well0006]
;This set contains some transition pieces
6=1,0,1,0
;This would specify that the left half of the tile is rocky terrain, the right half is lava terrain.
Adding more pieces (16ths as in the example before) would make it even more complex. Even when creating datasets for only about 30 transition pieces, it was a nerve-wracking experience, with lots of mistakes and backtracking.
I have plans to change the file format as well (I kinda like INI with the sections and all, but there are a few features I want to add, such as C/C++ #include type statements, maybe defines / symbolic constants like ROCKY=1, etc. Also, the built in windows INI reading functions are _very_ slow).
Kudos goes to Sirbomber for encouraging me to look at the code of another map editor (where I got the quarters idea from).
If you have any creative ideas on how I can solve the matching problem without making a lot of work / mess for both myself / the person editing terrains.ini, let me know. Same goes for any suggestions / wanted features on the terrain editor.
-- op2hacker
I'd prefer a system with 1/16s. We will need the accuracy.
one tile might look like this:
+----+
|abcd|
|efgh|
|ijkl|
|mnop|
+----+
We could leave out f,g,j,k , because they are not at the edge.
Now, when trying to find a tile that fits at the right edge, e.g.
+----+
|qrst|
|u v|
|w x|
|yzzz|
+----+
d must equal q, h must equal u and so on.
And here comes my idea:
store 4 lists in the ini-file, one for every edge, e.g.
[LEFT]
....
[TOP]
....
[RIGHT]
....
[BOTTOM]
....
And in more detail (with random values):
[LEFT]
0,0,0,0=2,3,4,5,...
1,1,0,0=10,16,33,37,40,84,...
1,1,1,0=15,32,39,56,62,...
...
following the scheme "Terrain types at this edge = list of tiles that have them".
This way the mapper won't have to search for the right tile. - The mapper knows that a tile with a certain left edge (e.g. 1,1,0,0) has to be found, thus looks at the list (which is sorted and probably in array form, internally), then picks one of 10,16,33,37,40,84.
There's still lots of work to be done to create those lists. I could help with that.
Well, I worked on this recently and the 16-tile system (well, really 12 since the middle tiles don't matter) is working pretty nicely.
A lot more accuracy is possible (but again, it's only as accurate as the terrain definitions in the ini file).
I also changed the way data is entered into terrains.ini, and I think this method makes it a lot more reasonable for people to type in (i.e. faster and less error-prone).
Rather than dividing a tile into a grid like I did before, I now use 6 pieces of information to determine the 12 cells in a tile:
[tileset name]
tile_id=terrain1,terrain2,percentN,percentS,percentW,percentE
terrain1 and terrain2 are terrain type ID's, simple enough.
The percent[N/S/W/E] are simply ratios of terrain1 to the total terrain on the given edge expressed as a percent, starting from the top left corner going to the bottom right. So, for example, if you have a tile which is a vertical grey/black transition, with grey on the left side of the tile, black on the right, and assuming it is exactly 50/50 (split right down the center of the tile vertically), you would have the following definition (assuming it is tile ID 0, black is terrain type 0, grey is terrain type 2):
To recap, the definition literally means:
There are two terrains in the tile, grey (2) and black (0). On the north and south edges, starting from the left corner, the first 50% is grey, the rest is black. On the west side, it is entirely grey (100% terrain1). On the east side, it is entirely black (0% terrain1).
I know some of you are saying that there is some problem. What if you wanted to say that the RIGHT part of the north edge is terrain1? Well, for that I just use negative percent values. The negative just forces the engine to start at the bottom/right corner of an edge when evaluating the percent data. For 0 and 100 it doesn't make sense (since interpreting in this manner, 100 is the 'negative' of zero in this case, if you get my drift).
There are 5 magnitudes possible for the percents: 0, 25, 50, 75, and 100 (since internally tiles are divided into 1/16ths, minus the middle 4 pieces).
Hopefully all of this makes sense. It took me a while to come up with it but it makes defining tile data so much easier.
Let me know any suggestions/comments you have.
After looking at the tiles some more and reading your 18 Oct post about the 1/16 code, that seems like a good start, but what about divorcing the sides from eachother?
What I mean is, you'll actually end up with a 1/8 system.
--------------
| e f |
|h d |
|g c |
| a b |
--------------
So you look at each side, but only that side and not the neighboring side of that corner.
So your ambiguous sample (1/2 black and white) would look something like
black = (c, d, e, f), white = (a, b, h, g).
Again, you could use a bit code to impliment this and swap bytes to search for matches. The tile above looking for a right hand match would swap (c,d) for (g,h). Then look for a tile that has a (g, h) as well as whatever attributes already exist at the right hand tile.