Loading A 2D Array Into A Image. Drawing Not Working!

Okay so I am trying to draw a tiled map in Java. I am currently doing the following:

[]Loading mapData from a text file (level1.dat) which is then stored into a 2D Integer Array
[
]Draw a BufferedImage dependant on the map data
[*]Draw the BufferedImage to my JFrame.

I have four classes:

[]ArrayToImage - Class whereby I convert the Array to the Image
[
]MapToArray - Class whereby I convert the level1.dat into the 2D Array
[]Main - Class that instantiates the MainFrame
[
]MainFrame - JFrame to display the Image

I think the problem is in MainFrame (Perhaps I am drawing the Image wrong?) or in ArrayToImage as the double for loop might not be working properly?

Here is the code I have worked on so far:

ArrayToImage


import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;


public class ArrayToImage {
	Image image;
	   //ignore this part
	private Image wall = null;
	 private Image table = null;
	 private Image floor = null;
	   int x,y,temp=0;
	   //nothing here yet
	   
	   public void loadImages() {
		 
		 wall = Toolkit.getDefaultToolkit().getImage("Tree.bmp");
			 table = Toolkit.getDefaultToolkit().getImage("Icicle.bmp");
			floor = Toolkit.getDefaultToolkit().getImage("floor.bmp");
		   
	   }
	   public ArrayToImage(){
		   loadImages();
	   }
	   //This function will return an BufferedImage with all the tiles drawn on it
	   public BufferedImage getMap(int[][] map){
		   loadImages();
	      BufferedImage bufferedImage = new BufferedImage(map.length*4, (map[0].length)*15, BufferedImage.TYPE_INT_BGR);
	      Graphics2D g2d = bufferedImage.createGraphics();
	      g2d.setColor(Color.green);
	      g2d.fillRect(0, 0, map.length*4, (map[0].length)*15);
	      for(int height= 0; height<map[0].length; height++){
	      for(int length = 0; length<map.length; length++) {
              switch(map[length][height]){
case 0:
g2d.drawImage(floor, length*15, height*15, null);
                                break;
case 1:
g2d.drawImage(wall, length*15, height*15, null);
break;
case 2:
g2d.drawImage(table, length*15, height*15, null);
break;
}
           }
	      }

	      g2d.finalize();
	      g2d.dispose();
	      return bufferedImage;
	   }
	}


MapToArray



import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.ArrayList;
public class MapToArray {

	private final String fileName;
	public int length;
	public int height;
	//simple constructor, Sets the map
	MapToArray(String fileName) {
		this.fileName = fileName;
	}
	
	//returns the 2D array of the map in INT[] []
	public int[] [] getArray() throws IOException {
		ArrayList<String> array = new ArrayList<String>();
		 length = getLength();
		 height = getHeight();
		
		LineNumberReader reader = new LineNumberReader (new FileReader(fileName));
		for (int i = 0; i < height; i++) {
		array.add(reader.readLine());
		}
		
		if (array.size() == 0) {
			System.out.println("Empty map");
	}
		int[][] numbers = new int [length][height]; //reserve space in memory
	int r= 0; 
	//now that we have the size of our array and the data, we fill it in
	for (String s : array) {
		toArray(s, r, numbers);
		r++;
	}
	return numbers; //return map
	}
		
	//returns the map's Length
	private int getLength() throws IOException {
		int countChar = 0;
		try {
			LineNumberReader reader = new LineNumberReader (new FileReader(fileName));
		String lineRead = reader.readLine();
		int length = 0;
		while (countChar < lineRead.length()) {
			if (!(lineRead.charAt(countChar) == ',')) {
				length++;
			}
			countChar++;
		}
		reader.close();
		return length;
		} catch (IOException e) {
			throw e;
		}
	}
	
	//returns height of map (number of lines)
	public int getHeight() throws IOException {
		int height = 0;
		try {
			LineNumberReader reader = new LineNumberReader(new FileReader(fileName));
			String lineRead;
			while ((lineRead = reader.readLine()) != null) {
			}
			//loops to last line of file}
				height = reader.getLineNumber();
				reader.close();
				return height;
			
		} catch (IOException e) {
			throw e;
		}
	

	}
	
	//This function will fill an entire row with the numbers from String s.
    private void toArray(String s, int row, int[][] numbers) {
        String match = ",";
        String[] veld = s.split(match);
        
        for(int i = 0; i<veld.length;i++)
           veld[i] = veld[i].replaceAll(" ","");
        
        for (int i = 0; i < veld.length; i++) {
            try {
                numbers[i][row] = Integer.parseInt(veld[i]);
            } catch (NumberFormatException e) {
                System.out.println("Not a valid map!");
            }
        }
    }

}

MainFrame


import javax.swing.*;

import java.awt.*;
import java.io.IOException;
public class MainFrame extends JFrame{
	int[][] array_map1;
	MapToArray map1;
	Image bckground_1;
	ArrayToImage draw = new ArrayToImage();

public void init() throws IOException {
	map1 = new MapToArray("level1.dat"); //sets the current map
	array_map1 = map1.getArray(); // grabs the map data and stores it in a 2D integer Array.
	bckground_1 = draw.getMap(array_map1); //draws the "Map" by creating a BufferedImage dependant on the 2D Array.
	}

	MainFrame() throws IOException {
		setSize(640,480);
		setTitle("MapLoad Demo");
	init();
	setVisible(true);
	
	}
	public void paint (Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
	g2d.drawImage(bckground_1, 0, 0 ,null);
	}
	
	
	
}

Main


public class Main {
	public static void main(String[] args) throws IOException {
		new MainFrame();
}
}

The problem is when I run main.java ; A 15 * 15 Image loads in the top right (only 1 tile?) so I think It might not be looping properly in ArrayToImage.java. The problem can be seen in the screenshot below:

[spoiler]


http://s18.postimage.org/fk63ftzyt/map_Demo_Screen.jpg

[/spoiler]

I also think that all the Images are loading correctly as I painted one Image.
I am pretty sure that I am drawing the images incorrectly in MainFrame.java
Any help is appreciated, Thanks
v0rtex

P.S.: Here is the map Data for level1.dat

1,1,1,1,1,
1,0,0,0,1,
1,0,2,0,1,
1,0,0,0,1,
1,1,1,1,1,

Credit goes to elamre to whom provided most of the code through this tutorial.

Don’t draw directly to a JFrame or some parts of all sides will be cut off due to window decorations, as shown by that cut off green rectangle. It is best to extend JComponent and draw in its paintComponent(Graphics g) method and add that JComponent to the JFrame.

Concerning your problem, it looks like it’s more of a problem in your MapToArray class. You are opening 3 streams of the same file, two to get the width and height, and one to actually read it. This is very inefficient and error prone. It is best to just open 1 BufferedReader on your file and add all the lines to the ArrayList, only to split it up later on.

Did you try printing out what is in your map array before drawing its contents in ArrayToImage.getMap?

hmmyez, that seems to work ra4king.
I know this class might not be to your standards, but the mapToArray class works perfectly fine. And yeah its not efficient, but the efficiency isnt really important at this point :).
Also i used to have it differently, untill somebody on this forum told me this way it was better. But ill have to do some research to it i guess.

And write a foolproof tutorial as well it seems.

I am answering here from now on as it was the site that I got the original information from. I added a JComponent and am drawing the bufferedImage to the JComponent and then adding the JComponent to a JFrame like ra4king suggested and this makes the image display correctly but the Image is still not showing up, any help is appreciated. This is really getting rather annoying :frowning:

Also I have confirmed (thanks to the help of elamre) that the level1.dat is being read correctly but g2d.drawImage is not adding the Images to the bufferedImage as the returned Image is simply blank?

Got it working, for some reason returning an ImageIcon when loading the Image corrected the Image, I also added a boolean check on whether the Images were loaded correctly.



import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;

import javax.swing.ImageIcon;

public class ArrayToImage {
	Image image;

	private Image wall = null;
	private Image table = null;
	private Image floor = null;
	int x, y, temp = 0;
	private boolean imagesLoaded = false;

	public void loadImages() {
		wall = loadImage("wall.jpg");
		table = loadImage("Icicle.jpg");
		floor = loadImage("Floor.jpg");

		imagesLoaded = true;
	}

	private Image loadImage(String fileName) {
		return new ImageIcon(fileName).getImage();
	}

	public void drawImage(Graphics g, Image image, int x, int y) {
		g.drawImage(image, x, y, null);
	}

	public ArrayToImage() {
	}

	// This function will return an BufferedImage with all the tiles drawn on it
	public BufferedImage getMap(int[][] map) {
		loadImages();
		int largestRow = 0;
		for (int i = 0; i < map.length; i++) {
			if (map[i].length > largestRow)
				largestRow = map[i].length;
		}
		int tileSize = 32;

		BufferedImage bufferedImage = new BufferedImage(map.length * tileSize,
				largestRow * tileSize, BufferedImage.TYPE_INT_BGR);
		Graphics2D g2d = bufferedImage.createGraphics();
		g2d.setColor(Color.white);
		if (imagesLoaded) {
			for (int heigth = 0; heigth < map[0].length; heigth++) {
				for (int length = 0; length < map.length; length++) {
					switch (map[length][heigth]) {
					case 0: {
						g2d.drawImage(floor, length * tileSize, heigth
								* tileSize, null);
						break;
					}
					case 1: {
						g2d.drawImage(wall, length * tileSize, heigth
								* tileSize, null);
						// g2d.setColor(Color.red);
						// g2d.fillRect(length*tileSize, heigth*tileSize, 32,
						// 32);
						break;
					}
					case 2: {
						g2d.drawImage(table, length * tileSize, heigth
								* tileSize, null);
						break;
					}
					}
				}
			}
			if (imagesLoaded == false) {
				System.out.println("Error Loading Images!");
			}
		}
		g2d.finalize();
		g2d.dispose();
		return bufferedImage;
	}

}

Thanks again all!

Don’t use ImageIcon, it is best to use javax.imageio.ImageIO:


BufferedImage image = ImageIO.read(getClass().getClassLoader().getResource(path));

Where “path” is relative to the root of your project.

Any reason why in particular? Is it better resource or performance wise?
Just curious,
v0rtex

Both, first off you creating an ImageIcon instance, waste of resource and performance. Secondly, internally it just does Toolkit.getDefaultToolkit().getImage(path). Also it is much cleaner to use ImageIO codewise, and I consider using ImageIcon for anything other than Swing icons a sin :slight_smile:

I don’t want to sin! Ok will integrate that, thanks!

REPENT OF YOUR SINS! ;D

Uhm, one last question when I run the code, the tiles now load fine but there is huge spaces in the tiles themselves. I am unsure of how to remedy that? Any help is appreciated…

What do you mean by huge spaces? Could you provide a screenshot?

Sure.

http://s16.postimage.org/j78mb49xh/spacing.png

Are the images 15x15? :wink:

128 x 128. But I changed the tileSize variable:


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;

import javax.swing.ImageIcon;

public class ArrayToImage {
	Image image;

	private Image wall = null;
	private Image stone = null;
	private Image Water = null;
	int x, y, temp = 0;
	private boolean imagesLoaded = false;

	public void loadImages() {
		wall = loadImage("Wall.png");
		stone = loadImage("Stone.png");
		Water = loadImage("Water.png");

		imagesLoaded = true;
	}

	private Image loadImage(String fileName) {
		return new ImageIcon(fileName).getImage();
	}

	public void drawImage(Graphics g, Image image, int x, int y) {
		g.drawImage(image, x, y, null);
	}

	public ArrayToImage() {
	}

	// This function will return an BufferedImage with all the tiles drawn on it
	public BufferedImage getMap(int[][] map) {
		loadImages();
		int largestRow = 0;
		for (int i = 0; i < map.length; i++) {
			if (map[i].length > largestRow)
				largestRow = map[i].length;
		}
		int tileSize = 128;

		BufferedImage bufferedImage = new BufferedImage(map.length * tileSize,
				largestRow * tileSize, BufferedImage.TYPE_INT_BGR);
		Graphics2D g2d = bufferedImage.createGraphics();
		g2d.setColor(Color.white);
		if (imagesLoaded) {
			for (int height = 0; height < map[0].length; height++) {
				for (int length = 0; length < map.length; length++) {
					switch (map[length][height]) {
					case 0: {
						g2d.drawImage(Water, length * tileSize, height
								* tileSize, null);
						break;
					}
					case 1: {
						g2d.drawImage(wall, length * tileSize , height
								* tileSize, null);
						// g2d.setColor(Color.red);
						// g2d.fillRect(length*tileSize, height*tileSize, 32,
						// 32);
						break;
					}
					case 2: {
						g2d.drawImage(stone, length * tileSize, height
								* tileSize, null);
						break;
					}
					}
				}
			}
			if (imagesLoaded == false) {
				System.out.println("Error Loading Images!");
			}
		}
		g2d.finalize();
		g2d.dispose();
		return bufferedImage;
	}

}

The screenshot doesn’t look like the tiles are 128x128, they look more like 96x128.

Also, you don’t need curly braces around cases in a switch statement.

They were 76x128. OOPS :slight_smile: