6

I posted a question in sun java forums sometime ago and i am finding it hard to understand the first response i received from the replier though it seems he gave me the correct approach to my problem. The link to the question is:

http://forums.sun.com/thread.jspa?threadID=5436562&tstart=0

Someone replied that i should use BufferedImage and make tiles. I don't really understand what the tiles mean in connection with the BufferedImage.

I would like someone to explain to me what the tiles are and how they are created in the BufferedImage.

I have searched the web for a while but couldn't find any link that can help me understanding the basics of the tiles and creating the tiles. Any pointer to a site is also appreciated.

I need help in understanding the tiles in connection with the BufferedImage and also how they are created.

Eddy Freeman
  • 89
  • 1
  • 1
  • 2
  • 1
    You need to rework this question. At least you should copy the question and the answer you don't understand from the other forum. – aioobe May 06 '10 at 15:26
  • I had wanted to do that but when you do that some people complain about double posts. That is why i provided the link. – Eddy Freeman May 06 '10 at 15:49
  • 1
    You don't write a new post...just edit this one. People will see the updates. (See the "edit" button underneath the tags in your question - that's what you use so you can make your question better.) – JasCav May 07 '10 at 19:28
  • BufferedImage actually has sophisticated support for tiles built in to the API and I'm not seeing any of this mentioned in the answers below. I think the idea is that rather than painting the tiles individually in the paint() or paintComponent() methods, you could update the tiles in the BufferedImage as needed and use getSubImage() on BufferedImage to get the viewable portion of the entire array of tiles, then just write this subimage in one step in paint() or paintComponent(); I only bring this up because I'm having serious performance issues using the ideas outlined below. – jk. May 18 '13 at 19:43

2 Answers2

16

A "tile" in a 2D game simply means an "image smaller than whole screen that you can reuse several times to create the background".

Here's a a working example where four tiles are created (adding some random noise to every pixel). Each tile is 50x50 pixels.

Then there's a "map" (that you call a "grid" in your case) representing which tiles you want to put where.

From that map, a bigger BufferedImage is created (note that it's just an example, in a real program you'll want to use a BufferedImage copy, not a pixel-by-pixel copy).

The map is 9x7, each tile is 50x50 pixels, hence the resulting image is 9*50 x 7*50 (ie 450 by 350).

Note that the following is really just a simple example, as short as possible, showing how to create a bigger BufferedImage using several tiles: the goal is not to give a tutorial on best Swing usage nor on how to squeeze every bit of performances out of BufferedImages, etc.

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class ToyTiled extends JFrame {

    private static final int IMAGE_TYPE = BufferedImage.TYPE_INT_ARGB;

    private BufferedImage img;

    public static void main( String[] args ) {
        new ToyTiled();
    }

    public ToyTiled() {
        super();
        this.add(new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                g.drawImage(img, 0, 0, null);
            }

        });
        img = new BufferedImage( 450, 350, IMAGE_TYPE );   // here you should create a compatible BufferedImage
        this.setSize(img.getWidth(), img.getHeight());
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);


        final int NB_TILES = 4;
        BufferedImage[] tiles = new BufferedImage[NB_TILES];
        tiles[0] = createOneTile( new Color( 255, 255, 255 ) );
        tiles[1] = createOneTile( new Color( 255,   0, 255 ) );
        tiles[2] = createOneTile( new Color(   0,   0, 255 ) );
        tiles[3] = createOneTile( new Color(   0, 255, 255 ) );  

        final int[][] map = new int[][] {
                { 1, 0, 2, 3, 0, 1, 2, 2, 2 },
                { 0, 2, 3, 0, 1, 2, 2, 2, 3 },
                { 1, 0, 2, 3, 0, 1, 2, 2, 2 },
                { 2, 1, 0, 1, 2, 3, 2, 0, 0 },
                { 1, 0, 2, 3, 0, 1, 2, 2, 3 },
                { 1, 0, 2, 2, 1, 1, 2, 2, 3 },
                { 1, 0, 2, 3, 0, 1, 2, 2, 3 },
        };

        for (int i = 0; i < map[0].length; i++) {
            for (int j = 0; j < map.length; j++) {
                final BufferedImage tile = tiles[map[j][i]];
                for (int x = 0; x < tile.getWidth(); x++) {
                    for (int y = 0; y < tile.getHeight(); y++) {
                        img.setRGB( x + i * 50, y + j * 50, tile.getRGB(x,y) );
                    }
                }
            }
        }

        this.setVisible( true );
    }

    private BufferedImage createOneTile( final Color c ) {
        final Random r = new Random();
        final BufferedImage res = new BufferedImage( 50, 50, IMAGE_TYPE );
        for (int x = 0; x < res.getWidth(); x++) {
            for (int y = 0; y < res.getHeight(); y++) {
                res.setRGB( x, y, c.getRGB() - r.nextInt(150) );
            }
        }
        return res;
    }

}
SyntaxT3rr0r
  • 27,745
  • 21
  • 87
  • 120
  • Thank you sooo much for your reply. I am still studying the code. Thanks. – Eddy Freeman May 06 '10 at 16:08
  • 2
    @Eddy Freeman: if this was an answer that solved the problem for you, or got you on the right track, it is considered courteous to select it as the "answer" to your problem. – aperkins May 07 '10 at 19:32
1

If you want to rotate a portion of a BufferedImage you might find these classes/methods useful:

Example:

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;

public class TileTest extends JFrame {

    public static void main(String[] args) throws IOException {
        URL logo = new URL("http://sstatic.net/so/img/logo.png");
        TileTest tileTest = new TileTest(ImageIO.read(logo));
        tileTest.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        tileTest.setVisible(true);
    }

    private TileTest(BufferedImage image) throws IOException {
        this.image = image; 
        setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
        JLabel label = new JLabel(new ImageIcon(image));
        add(label);
        BufferedImage tile = image.getSubimage(0, 0, 61, 61);
        add(new JButton(new RotateAction(tile, label)));
        pack();
    }

    private BufferedImage image;

}

class RotateAction extends AbstractAction {

    public void actionPerformed(ActionEvent e) {
        BufferedImage tmpImage = op.filter(image, null);
        image.setData(tmpImage.getRaster());
        component.repaint();
    }

    RotateAction(BufferedImage image, Component component) {
        super("Rotate");
        this.component = component;
        this.image = image;
        double x = 0.5 * image.getWidth();
        double y = 0.5 * image.getHeight();
        AffineTransform xfrm =
            AffineTransform.getQuadrantRotateInstance(1, x, y);
        op = new AffineTransformOp(
            xfrm, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
    }

    private final Component component;

    private final BufferedImage image;

    private final BufferedImageOp op;

}
finnw
  • 47,861
  • 24
  • 143
  • 221