Reputation: 558
I'm making a new game that generates a huge grid (lets say 1000x1000). The player starts in the middle and moves around looking for "points". The player can only see a portion of the larger grid in the window (15x15). Right now I just have a huge array of rectangles each that paint a bufferedimage of a dirt block that I created. Question: Is there a better variable type I should be using to store all these images?
This is what my Dirt class looks like (holds the rect, and the image which is generated at the beginning):
public class Dirt extends Spot{
private int index;
public Dirt(int temp){
index = temp;
}
public Image getImageIndex(){return index;}
}
And here is apart of my Board class that draws all the Dirt:
public class Board extends JPanel{
private final int BLOCK_SIZE; //Holds the size of each block
private final int SIZE; //Holds the size of the board
private DirtImages[] imgs_Dirt = new DirtImages[20]; //Holds 20 random dirt images - generated at begtinning
private Spot[][] spots;
public Board(int size, int blocksize){
SIZE = size;
BLOCK_SIZE = blocksize;
//Board
setSize(SIZE,SIZE);
//Timer Label
add(JTimerLabel.getInstance());
//Create 20 random Images of dirt to use for the rest of dirts
for(int i = 0; i < 20; i++){
imgs_Dirt[i] = new DirtImages(new Rectangle(0,0,BLOCK_SIZE,BLOCK_SIZE));
add(imgs_Dirt[i]);
}
//Create Dirt
spots = new Dirt[500][500];
java.util.Random randomGenerator = new java.util.Random();
for(int i = 0; i < spots.length; i++){
for(int j = 0; j < spots.length; j++)
spots[i][j] = new Dirt(randomGenerator.nextInt(20));
}
}
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//Draw Grid #First
for(int i = 0; i < spots.length; i++){
for(int j = 0; j < spots.length; j++)
if(spots[i][j] != null)
g2d.drawImage(imgs_Dirt[((Dirt)spots[i][j]).getImageIndex()].getImage(), BLOCK_SIZE*i,BLOCK_SIZE*j,BLOCK_SIZE,BLOCK_SIZE, null);
}
Toolkit.getDefaultToolkit().sync();
g2d.dispose();
requestFocus();
}
Just to clarify. I create 20 Dirt images so that the dirt (when painted) don't look like they're tiled but are random. So in my array of Dirt, each Dirt points to a random image.
Additional Question: Now that I create my huge grid, how would I make it so the player starts at the center and I draw the surrounding cells. Currently I start at the beggining of the array in the top left corner of my array. Should I create a boolean flag for each dirt of whether or not it should be drawn?
Upvotes: 0
Views: 698
Reputation: 109823
put all those together, and with determine visible JComponents
in the JViewPort
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.*;
public class TilePainter extends JPanel implements Scrollable {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Tiles");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(new TilePainter()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private final int TILE_SIZE = 50;
private final int TILE_COUNT = 100;
private final int visibleTiles = 10;
private final boolean[][] loaded;
private final boolean[][] loading;
private final Random random;
public TilePainter() {
setPreferredSize(new Dimension(TILE_SIZE * TILE_COUNT, TILE_SIZE * TILE_COUNT));
loaded = new boolean[TILE_COUNT][TILE_COUNT];
loading = new boolean[TILE_COUNT][TILE_COUNT];
random = new Random();
}
public boolean getTile(final int x, final int y) {
boolean canPaint = loaded[x][y];
if (!canPaint && !loading[x][y]) {
loading[x][y] = true;
Timer timer = new Timer(random.nextInt(500),
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
loaded[x][y] = true;
repaint(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
});
timer.setRepeats(false);
timer.start();
}
return canPaint;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle clip = g.getClipBounds();
int startX = clip.x - (clip.x % TILE_SIZE);
int startY = clip.y - (clip.y % TILE_SIZE);
for (int x = startX; x < clip.x + clip.width; x += TILE_SIZE) {
for (int y = startY; y < clip.y + clip.height; y += TILE_SIZE) {
if (getTile(x / TILE_SIZE, y / TILE_SIZE)) {
g.setColor(Color.GREEN);
} else {
g.setColor(Color.RED);
}
g.fillRect(x, y, TILE_SIZE - 1, TILE_SIZE - 1);
}
}
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(visibleTiles * TILE_SIZE, visibleTiles * TILE_SIZE);
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return TILE_SIZE * Math.max(1, visibleTiles - 1);
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return false;
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return TILE_SIZE;
}
}
Upvotes: 1
Reputation: 5094
If you have 1,000,000 Dirts and only 20 images, it's kind of a waste to store an image in each dirt. You can use an index instead. So to draw, instead of drawing
((Dirt)spots[i][j]).getImage()
you would draw
imgsDirt[((Dirt)spots[i][j]).getImageIndex()]
For the updated question:
You seem to be drawing your whole grid(0-1000,0-1000). What you really want is just to paint the 15x15 'viweable' area. So instead of
//Draw Grid #First
for(int i = 0; i < spots.length; i++){
for(int j = 0; j < spots.length; j++)
it would be
//Draw Grid #First
for(int i = player.xpos-7; i < player.xpos+7; i++){
for(int j = player.ypos - 7; j < player.ypos+7; j++)
You would need an appropriate shift in your drawImage method to make sure it still starts drawing at the upper left of your window.
Upvotes: 3