Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (580)
games submitted by our members
Games in WIP (500)
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  
  Loading a Tilemap as Background  (Read 368 times)
0 Members and 1 Guest are viewing this topic.
Offline Muteking

Senior Newbie





« Posted 2013-08-02 13:54:56 »

I've been trying to find some deep and complete explanations on Backgroung tiling maps for weeks, but I still can't be confident at it. I need help.
I have my GamePanel class with the gameloop and the graphics g used to paint things on the screen. Quite well, my character is moving around and jumping happily.
Now comes the hard part, the TileMap class.
First question: which variables shall I use?
For now I'm thinking about those
         
       
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
//coordinates that I may use to offset the screen
  public int Tilemapx;
   public int Tilemapy;
   //number of tiles in the image
  private int TotalRows;
   private int TotalColumns;
   private int Rows;
   private int Cols;
   //size of the Tile
  public int TileSize;
        //Two Buffered images, one for the entire map and one for the single tile
  public BufferedImage EntireMap;
   public BufferedImage Tile;
   //a two dimensional array so I can reach any tile with two coordinates
  public int [] []  map;


Going on step by step I'd make a contructor and put on TotalRows and TotalColumns the columns and Rows to be rendered(+2 offscreen)
1  
2  
3  
4  
5  
public TileMap (int TileSize){
      this.TileSize = TileSize;
      TotalRows = Pannello.WIDTH / TileSize + 2;
      TotalColumns = Pannello.HEIGHT / TileSize + 2;
   }


So far so good(I hope).

Now, everybody speaks about this for loop, and I imagine that I have to retrieve a tile (or tiles?) with the subimage
and for the sake of learning I would be happy to display just one tile(the text map that drives the graphics is something I want to study when I'm more prepared).
So, here I have a method to load the map that I painted in Photoshop and the for loop that is supposed to draw a tile on 0, 0.

 
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
 public void loadTileImg (){
       String TileMapPath = "res/Tiles.png";
       try {
         EntireMap = ImageIO.read(new File(TileMapPath));
      } catch (IOException e) {
         e.printStackTrace();
      }
       for (int Cols = 0; Cols < TotalColumns; Cols++){
          for (int Rows = 0; Rows < TotalRows; Rows++){
              Tile = EntireMap.getSubimage(0, 0, TileSize, TileSize);
                         
          }


That's where my lacking of experience and newbieness comes in. The screen is actually flashing like a strobo and the tile isn't getting displayed.


Offline Jeremy
« Reply #1 - Posted 2013-08-02 15:19:21 »

Hmm, I am writing a tiled game engine right now (isometric) but logic like this is exactly the same regardless - so I believe I may be able to help you here.

I am not sure if I quite understand your question - but I believe I can give you a solid explanation to how I do it, and it may help you.

First of all, because you seem to be new to programming in general, here are some tips I will throw at you right away that will make your life a lot easier:

(You can skip this if you are just looking for an explanation to your problem, but I highly suggest some time later going over this and looking in to what I am saying here)

Variable names should usually start with a lower-case so you can differentiate them between a class name (which should usually start with an upper-case) and a variable name. Consider you have a class named Tile, you now end up with a declaration that looks like:

Tile Tile = new Tile();
Tile.x = 5; //etc

and 'Tile' because ambiguous because 'x' could be a static variable you are accessing in Tile, or it could be a member variable you are accessing that belongs to the instance of Tile named Tile (even that is confusing to comprehend!) - while Java resolves this appropriately it is still very confusing to any programming looking at the code.

Member variables usually start with some indication to suggest that they are a member variable that exists in the entire scope of the class. Some people prefer not to do this (and it is somewhat controversial among programmers) but I would say it can't hurt and it makes your code look cleaner. Most people either prefix member variables with _ or m_

Public member variables are usually avoided just because it's dangerous to expose these members directly unless the class is very simple (like a Vector, Matrix, Rectangle or Point). Instead people use get\set accessors. Some code (code that performs a dense and large amount of iterations over a time critical period like collision detection) can greatly benefit from directly access variables rather than using accessors - but I would say the rule of thumb should be to use get\set accessors - and then only if your profiler tells you that you can benifit from removing the accessors from the algorithm, do it.


Now on to the actual problem:


Like I said, I don't quite understand your question, so instead I will explain the process, and you can ask for details if you'd like. This describes a simple tiled map implementation, however the implementation would be different for something more complex (if you want more details on that just ask):

Your map is going to consists of a series of tiles, tiles contain information such as location, image (source image), maybe a rectangle describing what part of that image constitutes the visual depiction of the tile, some basic attributes like isBlocking, and a location. So lets make the problem simpler by creating a Tile class to describe our tile.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
    public class Tile
    {
        private Image m_sourceImage;
        private Rectangle m_sourceRectangle;
        private boolean m_isBlocking;

        public Tile(Image srcImage, Rectangle srcRectangle, boolean isBlocking)
        {
             m_sourceImage = srcImage;
             m_sourceRectangle = srcRectangle;
             m_isBlocking = isBlocking;
        }
       
        public void render(Graphics2D g, int x, int y)
        {
           //draw our tile at x, y using g
       }
       
        public boolean isBlocking()
        {
           return m_isBlocking;
        }
    }


Great, now we have a tile class that mostly takes care of itself. Now, lets think about our world.

Our world is going to consists of a series of tiles. We'll store our tiles in a single-dimensional array.

Here is how your world might look:
(I don't gurantee that this code works, my algorithm may be wrong, but it will at least give you a head-start.)
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  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
    public class World
    {
        //Store our world's dimensions
      private int m_worldWidth;
       private int m_worldHeight;
       
       //Our world will consists of tiles each of equal dimensions, lets store this information as well.
      private int m_tileWidth;
       private int m_tileHeight;
       
       //We'll store our tiles here
      private Tile[] m_tiles;
       
       //When create our world, it needs some information such as the world and tile dimensions
      //We pass this information in through the constructor
      public World(int worldWidth, int worldHeight, int tileWidth, int tileHeight)
       {
          m_worldWidth = worldWidth;
          m_worldHeight = worldHeight;
         
          m_tileWidth = tileWidth;
          m_tileHeight = tileHeight;
         
          //Create our array.
         m_tiles = new Tile[worldWidth * worldHeight];
         
          //Initialize your world's tiles.
         for(int i = 0; i < m_tiles.length; i++)
          {
             m_tiles[i] = new Tile(...);
          }
       }
       
       public Tile getTile(int iX, int iY)
       {
          //Calculate the index from the x\y location of the tile.
         int tileIndex = iY * m_worldWidth + iX;
         
          if(tileIndex > m_tiles.length)
             return null; //You'd want to throw an exception here for code-safety purposes, but we'll just return null for simplicity sake.
         
          return m_tiles[tileIndex];
       }
       
       //If you use this, you need to make sure that iX and iY are relative to the corner of the map.
      //This allows you to pass a coordinate (i.e, the location of a mouse click) and have it translated to the corresponding tile.
      public Tile pick(int iX, int iY)
       {
          return getTile(iX / m_tileWidth, iY / m_tileHeight);
       }
       
       //We call this to draw our tiled map onto the specified graphics object
      public void render(Graphics2D g, int offsetX, int offsetY)
       {
          for(int y = 0; y < m_worldHeight; y++)
          {
             for(int x = 0; x < m_worldWidth; x++)
             {
                getTile(x, y).render(g, x * m_tileWidth + offsetX, y * m_tileHeight + offsetY);
             }
          }
       }
    }

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
Offline Muteking

Senior Newbie





« Reply #2 - Posted 2013-08-03 07:27:02 »

Jeremy, this is very informative. Thank you. But some new questions arise, before trying to code something.
Why do you use the abstract Image class instead of BufferedImage?
What do you want to represent with the field m_sourceRectangle?

For the World class:
Does m_worldWidth represent the number of pixels being rendered on the screen?

I don't understand this line
1  
2  
//Create our array.
         m_tiles = new Tile[worldWidth * worldHeight];

I thought you had to use a two dimensional array (not a single dimensional), so you can easily retrieve a block from whereever you like.

And another thing: My approach is to draw from a class called GampePanel and then have a class dedicated only to the TileMap.
Is this ok?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Jeremy
« Reply #3 - Posted 2013-08-03 08:33:01 »

Jeremy, this is very informative. Thank you. But some new questions arise, before trying to code something.
Why do you use the abstract Image class instead of BufferedImage?
What do you want to represent with the field m_sourceRectangle?

For the World class:
Does m_worldWidth represent the number of pixels being rendered on the screen?

I don't understand this line
1  
2  
//Create our array.
         m_tiles = new Tile[worldWidth * worldHeight];

I thought you had to use a two dimensional array (not a single dimensional), so you can easily retrieve a block from whereever you like.

And another thing: My approach is to draw from a class called GampePanel and then have a class dedicated only to the TileMap.
Is this ok?

For this particular situation, it really doesn't matter if you reference the image as a Image or a subclass of Image such as BufferedImage. It is however more important if you are working on a more serious project. The reason is simple: All your tile needs to do with that Image is draw it via a graphics object, it doesn't need to care about how the image is stored, or what it does or doesn't implement outside of it's basic requirement (which is to draw it.) If you instead used a BufferedImage but decided you wanted that particular tile to initialize with a different subclass of Image, you can do that without breaking the design. In all likelihood, especially for a simple project, you won't need that abstraction - but it also makes the code simpler & less error prone by limiting it to only what it needs to do.

You can use a one or two dimensional array - but I think a single dimensional array is simpler. My problem with a two dimensional array is that it allows information in that array to contradict itself & the containing map. What I mean by that is, your map has a width and a height. What if your array looks like:

1  
2  
3  
4  
5  
{
    {tile, tile, tile, tile, tile, tile},
    {tile, tile, tile, tile, tile},
    {tile, tile, tile, tile, tile, tile, tile},
}

So is the width of your map 5, 4 or 6?

In theory, if your code proper, this should never happen - but that fact that your structure _can_ look like this makes it more error prone and messy than IMO the simpler alternative which is to just have a linear array.

m_worldWidth and m_worldHeight are the world's width & height in tiles.

Usually to reduce overhead tile sprites are loaded in sets. I.e, take a look at this sprite sheet: http://opengameart.org/content/lpc-terrain-repack
So usually all tiles share common Image references to a common sprite sheet, and they select which part of that sheet represents their tile. If it makes it simpler for you, just remove it.

Quote

And another thing: My approach is to draw from a class called GampePanel and then have a class dedicated only to the TileMap.
Is this ok?
Yep, that makes perfect sense.

JevaEngine, Latest Playthrough (This demo is networked with a centralized server model)

http://www.youtube.com/watch?v=rWA8bajpVXg
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.

xsi3rr4x (50 views)
2014-04-15 18:08:23

BurntPizza (46 views)
2014-04-15 03:46:01

UprightPath (62 views)
2014-04-14 17:39:50

UprightPath (44 views)
2014-04-14 17:35:47

Porlus (61 views)
2014-04-14 15:48:38

tom_mai78101 (84 views)
2014-04-10 04:04:31

BurntPizza (142 views)
2014-04-08 23:06:04

tom_mai78101 (242 views)
2014-04-05 13:34:39

trollwarrior1 (201 views)
2014-04-04 12:06:45

CJLetsGame (208 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
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!