Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Auto-Tiling on 2D map.  (Read 3811 times)
0 Members and 1 Guest are viewing this topic.
Offline Otreum

Junior Member


Medals: 6



« Posted 2013-08-14 14:30:41 »

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.
<a href="http://www.youtube.com/v/8k8oLnWopMw?version=3&amp;hl=en_US&amp;start=" target="_blank">http://www.youtube.com/v/8k8oLnWopMw?version=3&amp;hl=en_US&amp;start=</a>

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/
http://www.codeproject.com/Articles/106884/Implementing-Auto-tiling-Functionality-in-a-Tile-M

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 Sad

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.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #1 - Posted 2013-08-14 15:01:07 »

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?
Offline Otreum

Junior Member


Medals: 6



« Reply #2 - Posted 2013-08-14 15:23:58 »

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 Tongue)
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 Tongue
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #3 - Posted 2013-08-14 16:05:01 »

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

Senior Member


Medals: 9
Projects: 1
Exp: 2 years


No Games Finished


« Reply #4 - Posted 2013-08-14 16:16:48 »

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.
Offline Otreum

Junior Member


Medals: 6



« Reply #5 - Posted 2013-08-15 01:20:09 »

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

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

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
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 Smiley
Offline Otreum

Junior Member


Medals: 6



« Reply #6 - Posted 2013-08-15 04:10:50 »

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

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 Sad

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! Smiley

http://forums.tigsource.com/index.php?topic=21237.0
Offline Longarmx
« Reply #7 - Posted 2013-08-15 05:01:17 »

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:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
   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:


Offline Geemili

Senior Member


Medals: 9
Projects: 1
Exp: 2 years


No Games Finished


« Reply #8 - Posted 2013-08-15 05:16:40 »

In the example that I gave you, I used bitwise operations. The '&' operator is a bitwise operator that takes the bits and does this:
1  
2  
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:
1  
byte aByte = (byte) 255;


You would have to use this:
1  
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.
Offline Otreum

Junior Member


Medals: 6



« Reply #9 - Posted 2013-08-15 05:55:03 »

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 Smiley
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:
1  
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 )

Huh

Where as if transitionTile[ x ][ y ] was equal to 8, it would stop at this line of code:
1  
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? Sad
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Geemili

Senior Member


Medals: 9
Projects: 1
Exp: 2 years


No Games Finished


« Reply #10 - Posted 2013-08-15 06:13:52 »

Nope, you are spot on.
Offline BurntPizza
« Reply #11 - Posted 2013-08-15 06:34:17 »

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

Am I correct? Or am I way off? Sad

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.
Offline Otreum

Junior Member


Medals: 6



« Reply #12 - Posted 2013-08-15 13:55:14 »

In the example that I gave you, I used bitwise operations. The '&' operator is a bitwise operator that takes the bits and does this:
1  
2  
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:
1  
byte aByte = (byte) 255;


You would have to use this:
1  
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.


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 Smiley

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.
Offline Geemili

Senior Member


Medals: 9
Projects: 1
Exp: 2 years


No Games Finished


« Reply #13 - Posted 2013-08-15 15:31:37 »

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.
Offline opiop65

JGO Kernel


Medals: 153
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #14 - Posted 2013-08-15 15:41:57 »

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ยข!

Offline Otreum

Junior Member


Medals: 6



« Reply #15 - Posted 2013-08-17 12:08:41 »

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 Smiley
Offline opiop65

JGO Kernel


Medals: 153
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #16 - Posted 2013-08-17 12:42:12 »

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

Offline Otreum

Junior Member


Medals: 6



« Reply #17 - Posted 2013-08-17 13:23:28 »

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

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);
4. 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.
5. 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);
6. 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).
7. 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 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:
1  
2  
3  
//////////////////////////////////////////////////////////////////////////////////////
//////////////================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 Smiley
Offline Otreum

Junior Member


Medals: 6



« Reply #18 - Posted 2013-08-25 11:41:01 »

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 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! Smiley
<a href="http://www.youtube.com/v/nYEB2TrtViE?version=3&amp;hl=en_US&amp;start=" target="_blank">http://www.youtube.com/v/nYEB2TrtViE?version=3&amp;hl=en_US&amp;start=</a>

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! Cheesy
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Riven (19 views)
2014-07-29 18:09:19

Riven (13 views)
2014-07-29 18:08:52

Dwinin (12 views)
2014-07-29 10:59:34

E.R. Fleming (31 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (42 views)
2014-07-24 01:59:36

Riven (42 views)
2014-07-23 21:16:32

Riven (28 views)
2014-07-23 21:07:15

Riven (29 views)
2014-07-23 20:56:16

ctomni231 (60 views)
2014-07-18 06:55:21
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!