Auto-Tiling on 2D map.

So as some of you know, I have been working on a top down 2D game, and finally (with the help of some great resources!) managed to get some procedural terrain generation happening.
For those who don’t know, I will just sum it up, by showing you a video of where the game is up to right now.

8k8oLnWopMw

As you can see, there is no auto-tiling/tile transitions. And despite spending hours upon hours googling for resources on how to go about creating an auto-tile system, I still find myself sitting in my chair, scratching my head as to how I can implement an auto-tiling system efficiently.

These are the best resources based on what other people have said, and from what I have seen myself:
http://www.gamedev.net/page/resources/_/technical/game-programming/tilemap-based-game-techniques-handling-terrai-r934
http://www.saltgames.com/2010/a-bitwise-method-for-applying-tilemaps/

Now I don’t know if it’s because I have the flu, have had very bad sleep, haven’t been eating properly, am stressed from work, am sore from the gym and have been dedicating just about every moment of my minimal free time to programming research and work…but I read those links, and for some reason I can’t seem to fully understand them, I kind of understand, but without some kind of source code example, I find myself thinking “huh?”

I just feel stupid that I can’t seem to understand how to implement this when so many other people eagerly point out that link and the other links as being the best resources, then saying they’ve implemented the system within 2 hours.
I’ve been trying to understand it for 2 days and haven’t gotten anywhere, it’s frustrating and disheartening that I can’t even understand something that is apparently so simple :frowning:

I really don’t even know what to ask, the only way I could understand it is to see source code, or pseudocode.

Could anybody please explain the implementation side of thigns better than those articles, or post example code or pseudocode?

Your help will be greatly appreciated, and I think when I understand it, I will be writing a tutorial for others to understand it too.

If you want to create the transistions of terrain you have 3 option i know about:

  • Create an texture for every possible transistion, and place them at borders.
  • Create an texture programmaticly for every possible transistion using noise at startup, and place them at borders.
  • Change your terrain genaration, so an tile has an value for all terrain types, and then just mix all textures when you need to draw.

If you have an preference i can try to explain it more.
What exactly is the problem, where are you currently at?

These are currently the ways I am thinking of doing it:

  • After I generate my byte[][] (0 - deep water, 1 - midwater, 2, shallowater, 3 wetsand etc) I do yet another iteration through the byte array within the terrain generation class, and do the neighbour checking before re-assigning values to the byte[][] (I would probably have to change the byte[][] back to int[][] to compensate for number of tiles, and that would limit the size of map generation, however it is capable of doing 540,000,000 tiles, so I don’t think that will be an issue :P)
    If a player digs a tile out of the map later, then the WorldRenderer will change the number at that array cell to cator for the tile change.

  • In my WorldRenderer class (where I actually draw the tiles based on the byte at the current iteration through the byte[][]), I could call upon the auto-tile generation for every tile within the viewport, realtime. However I am worried this will cause performance issues, I won’t know until I try.

My problem is that I don’t know how to actually write the auto-tile method, I don’t know if I should write a whole new class with it’s own methods or create a method within my WorldRenderer class, or within my terraingeneration class. I just seem to be brain dead lol.

I attempted to do some kind of for loop earlier within the WorldRenderer, but it would make a horrible mess of my code, as there would be if, if else, statements everywhere.

Perhaps I just need to sleep on it, try and come back to it when I am not feeling crappy :stuck_out_tongue:

Can you show your terrain assignment code then?
It would be much easyer to help.

Well, I think that instead of modifying your original array, you could make a new one that tells which tiles around it are need to be auto-tiled. After rendering how you are right now, go through it a second time, and then render the correct auto-tile by checking the tiles in the positions around it.

I wrote some code that, in my head, works: http://pastebin.java-gaming.org/4de8a8a7162

I haven’t tested it, and it doesn’t do everything so it might not work.

Certainly. This is my current code to render through the portion of the map that is within the viewport:
x0 = bottom left of viewport
x1 = bottom right of viewport
y0 = top left of viewport
y1 = top right of viewport

for(int x = x0; x < x1; x++){ 
			 xpos = x - 4;
			 
			for(int y = y0; y < y1; y++){
				ypos = y - 4;
				
					switch(map[x][y]){
						case 0:		
						batch.draw(deepwater, xpos, ypos, scalex, scaley);
						break;
						
						case 1:
						batch.draw(water, xpos, ypos, scalex, scaley);
						break;				
	
						case 2:
						batch.draw(shallowwater, xpos, ypos, scalex, scaley);
						break;
	
						case 3:
						batch.draw(wetsand, xpos, ypos, scalex, scaley);
						break;
	
						case 4:
						batch.draw(sand, xpos, ypos, scalex, scaley);
						break;
	
						case 5:
						batch.draw(grass, xpos, ypos, scalex, scaley);
						break;
	
						case 6:
						batch.draw(darkgrass, xpos, ypos, scalex, scaley);					
						break;
	
						case 7:
						batch.draw(lowmountain, xpos, ypos, scalex, scaley);
						break;
	
						case 8:
						batch.draw(highmountain, xpos, ypos, scalex, scaley);
						break;
					
						case 9:
						batch.draw(mountainpeak, xpos, ypos, scalex, scaley);
						break;
				}
			}
		}

As for where I am up to. Based on what I had read in those links, I wanted to work out a method which does as those links say, so it adds up values of surrounding tiles to create a tile ID of sorts which would be then used to reference a specific sprite, then use that sprite ID when I do a batch.draw in the render() method.

I have a bit more clarity this morning, I think yesterday my mind was off with the fairies and getting slammed with an internal hammer at the same time, so i’ll get cracking soon enough and see what I can come up with.

Also Geemili, I will thoroughly check out your code a bit more later.
I read through this morning and I was impressed by the amount of effort you have gone through to help me, I appreciate that, because that is exactly the help I was after :slight_smile:

I guess this part is where i’m stuck at:

[quote]The transition information for a single terrain type need only use 8-bits of data (4 bits for the edges and 4 bits for the corners) which fits conveniently into a single byte
[/quote]
While I understand the concept, and it’s an excellent one, I just don’t know how to store the information in a single byte.
I think it’s just because I don’t understand how to use/create bitwise operations.
Now I know how to use bitwise operations, the operators are straight forward…
If I did 01000001 | 00011000 it would equal 01011001
If I did 01000001 & 01011000 it would equal 01000000
If I did 01010101 ^ 10101010 it would equal 11111111
The ~ operator I haven’t looked into too much, seemed a bit more complicated and not applicable.

…However I still don’t know how to store the information :frowning:

There is a post here which goes through the technique vaguely, but due to my lack of knowledge of bitwise operations, i’m scratching my head.

I am writing down how I think it should be done now, and trying to put the process into play. Hopefully I end up with a good result by the end of the day! :slight_smile:

http://forums.tigsource.com/index.php?topic=21237.0

I used the bitwise method when testing out how Terraria handled its tiles.

WARNING: Ignore terrible art!

I use this method when creating the tile:


   private final int UP = 1;
	private final int RIGHT = 2;
	private final int DOWN = 4;
	private final int LEFT = 8;
	
	private final int UP_LEFT = 1;
	private final int UP_RIGHT = 2;
	private final int DOWN_RIGHT = 4;
	private final int DOWN_LEFT = 8;

   public int getTileFrame(){
      // What tile transition we should have.
		int result = 0;
           
      // If tile above, if tile down, etc.
		if(up)		result += UP;
		if(right)	result += RIGHT;
		if(down)	result += DOWN;
		if(left)	result += LEFT;
		
      // This checks for diagonals
		if(result == UP + RIGHT + DOWN + LEFT){
			if(upLeft)		result += UP_LEFT;
			if(upRight)		result += UP_RIGHT;
			if(downRight)	result += DOWN_RIGHT;
			if(downLeft)	result += DOWN_LEFT;
		}
		return result;
	}

And then I use that result and get a tile from this image:

In the example that I gave you, I used bitwise operations. The ‘&’ operator is a bitwise operator that takes the bits and does this:


dec: 2 & 3 = 2
binary: 10 & 11 = 10

So, you can store multiple values in a number, up to 8 booleans in a byte.

However, in Java, it isn’t quite so simple. Bytes in Java range from -127 to 128 (inclusive), so it is more difficult* to store 8 booleans in a byte, but possible by writing the numbers in hexadecimal instead of decimal.

So, instead of this:


byte aByte = (byte) 255;

You would have to use this:


byte aByte = (byte) 0xff; 

But thats only if you want to use only a single byte. Otherwise, you can just use the code in my example.

*In C++/C there are primitives called ubytes, which stands for unsigned byte. Unsigned bytes differ from signed bytes because they range from 0 to 255 (inclusive), or basically don’t have negatives. Java does not have unsigned numbers.

You guys are awesome!

I haven’t yet implemented anything just yet, but I can see how it all should work (I guess I don’t just want to copy/paste your code without really fully understanding what is happening first).

I like your method LongArmX as it’s nice and short and sweet, that is what I am aiming for.
It’s simplified and makes perfect sense. I don’t think it takes into account any tile precendence like Geemili has in his code, but still a great simple example :slight_smile:
The result would refer to a specific tile ID which could then be used to determine what sprite to draw when I do the batch.draw method.

Now that I understand bitwise operators, I can now see where you have used them Geemili, for example:

if(transitionTile[x][y] & 1==1)

So in this case if the transitionTile[ x ][ y ] was equal to 8 the following would occur because of the & bitwise operator

1000 (8 )
0001 (1 )
---- == //If the 2 numbers match
0000 (0 )

false (0 )

???

Where as if transitionTile[ x ][ y ] was equal to 8, it would stop at this line of code:

if(transitionTile[x][y] & 8==8)

1000 (8 )
1000 (8 )
---- == (if the 2 numbers match)
1000 (8 )

true (1 )

So it’s saying if 1000 and 1000 match one another, then the result is 8.

Am I correct? Or am I way off? :frowning:

Nope, you are spot on.

Be careful, because 1xxx & 1000 will still == 1000, no matter what the x’s are, so it is not a test for matching the entire number.
However, it is a perfect test of if that first bit matches the first bit of the second number. It is a bitwise operation.

I would love to learn how to do it just using a single byte, the more optimization techniques I know, the better! Especially if I plan to have this working on Android and IOS devices too :slight_smile:

So I have modified the code you provided before, just so I can understand what you mean here:
http://pastebin.java-gaming.org/e8aa1028e63

I am not really sure that is correct (in fact, I don’t think it is, which shows I don’t fully understand where I would use the hexidecimal value in the code you provided.

Also, next few days i’m back at work again, busy busy busy. So we shall see how much progress I actually make. I will try not to post again until I have gotten some example of auto-tiling working.

I put my code into eclipse and fixed some things up to see if it would work, and as it turns out, it is not possible to store all the information in one byte in Java. The smallest type of number you could use is a short, but I’m not sure how much it would affect performance.

Also, for convenience you could do want Longarmx did, and instead of typing numbers, make them into variables. Example code: http://www.java-gaming.org/?action=pastebin&id=682

The code example also adds a function that ANDs the transitionTile and the position then checks if they are equal.

I have never done this before, but I was wondering if you could use texture splatting to mix two tiles together. For example, you have a grass tile and a sand tile next to each other. Take the tiles, splat the textures together to form a new grassy sand texture, assign the texture to a tile in between the sand and grass and there you go, you don’t have to actually make the textures yourself, the game makes them for you so you can have lots of combinations. Again, I have no idea how this really works so I don’t know if its expensive and slow. Just thought I’d share my 2¢!

Huzzah! It is a miracle!

I tried to do auto-tiling my own way, to see if my brain actually works, and despite going bald as a result of tearing hairs out, I have the very very very earliest version of auto-tiling working!

Right now the way I have done it is very clunky, it was a prototype of prototypes. The more efficient stuff starts now, and when it’s working, images will soon follow :slight_smile:

Can you give us a hint as to how you did it? I’m interested to see what you came up with!

When I have a more finished working version, I will show the code, just in case anybody has any suggestions for improvement :slight_smile:

For now, I will describe the steps the program takes:

  1. Inside of the Render() method, I call on a method called drawBaseTiles(); which does an x and y FOR loop through the tiles in the viewport (and a little just outside the viewport to prevent “popping” tiles), rendering tiles based on the byte value at the current array index using a switch statement to decide what tile to render.
  2. After the base method runs, I run yet another method to draw the transition tiles called drawTransitionTile();
  3. drawTransitionTile() performs the same loops through the tiles currently on the viewport that the drawBaseTiles(); method does, only does not use a switch statement, it just calls upon another method within the loop called selectSprite(x, y);
  4. selectSprite(x, y); initializes a “result” variable with the result of another method called getTileType(x,y);
  5. getTileType(x, y); first calls upon another method, which is called checkNeighbours(x, y); which serves to turn some boolean values to true depending on if the neighbouring tiles equal the current tile or not.
  6. After setting up, up_right, right, down_right, down, down_left, left, up_left to true/false (default value is false) the method finishes and the checkNeighbours(x,y); method continues with some conditional statements which basically say “if true, result += … (1, 2, 4, 8, 16, 32, 64 or 128)”. The method then returns that value back to selectSprite(x,y);
  7. selectSprite(x,y); then uses the returned value to choose from a list of sprites with the use of a switch statement with a whole bunch of cases (if I used if statements, I imagine it could be painful to read).
  8. Once a case matches, it does a batch.draw() of a specific sprite.

I haven’t yet incorporated precedence rendering just yet, but it’s in my head, and I don’t think it will be very hard to do, but like everything, it always seems easy until you go to do it :stuck_out_tongue:

Now it may not be the most effective way of doing things, but I did a big clean up of my code today to make it more organised, putting pieces of code into methods, separating code, leaving large title-like comments in the code such as:




//////////////////////////////////////////////////////////////////////////////////////
//////////////================WORLDRENDERER METHODS=================//////////////////
//////////////////////////////////////////////////////////////////////////////////////



…to help break up the code and make it FAR easier to read.

UPDATE:
At the moment, I have 2 textureAtlas’s now, and I think it is causing some stutter. The framerate remains steady 61-60, but the time for each frame itself is sporatically slow.
Because of this, I’ve quickly looked at using spriteCache in my code too. I’m not sure if I have to use it in combination with spritebatch just yet, but that is research for another day.
But, progress was made today, I knew it would happen, just had to be patient with myself. I’ll make a new post with source code link and maybe a video when I get it sorted :slight_smile:

Here is a video showing off progress so far, it is mainly about the auto-tiling, but i’ve put some zoom functionality in there and fixed up mouse coordinates (needed to do a bit of research to convert them to world coordinates, rather than screen coordinates).
Note that the zoom functionality most likely won’t be used in the final game, it’s just used to show off the terrain. Manual zooming plays no part in actual gameplay, therefore will only be used for testing. Automatic zooming based on height may play a part however. Either that, or the higher the player is, the further he will be able to move his mouse away from his player.
I also decided to see how it’d perform on my Galaxy S3 phone, so had to work out gesture controls etc for it to work properly, and it works fine just to show off.

I have quite a lot of Auto-tile textures to do, so at the moment, my main goal was to get auto-tiling working, and to understand the process of getting it to work.
Later on, I will work on the 250+ 32x32 textures and animations :stuck_out_tongue:
Thanks to the input some of you guys have given me, it gave me a bit more of an insight. I ended up doing my auto-tiling differently to what was suggested, and i’ll see if I can somehow post the code on here to show you guys what i’ve done.

For the time being though, here is a video! :slight_smile:

nYEB2TrtViE

On a side note, I have discovered that having an alcoholic drink when you can’t focus actually helps you focus, I guess it cuts out all the annoying crap from your mind and lets you focus on one thing at a time. I guess this is why Russians are some of the best programmers in the world, they don’t drink Coffee, they drink Vodka at work, them clever cookies! :smiley: