Hello, I've been working on a fun project of my own. I didn't really start out with a plan in mind, but now it has turned into an attempt to make some Advance Wars type TBS game. The problem I ran into is trying to display the base "terrain" image beneath the grid. It produced a fairly sweet effect of "cascading" image tiles (See attachment).
The problems:
-Why is it repainting if the mouse isn't moving? (Should repaint on MouseMove)
-Why is the image not loading completely?
I found in the API that the Graphics.drawImage() displays whatever amount of the image is loaded, but why isn't the image loaded all the way, and once it is, why is it reverting back to an unloaded state between two calls of the same method?
I think I need to find some way to load the image beforehand (through a thread or something) so it stays in a loaded state. I'm afraid the API has been confusing me, and I really don't understand how Image finds and uses an image. Can someone give me a few pointers?
Thanks for any help!
Code:
The important bits:
...
Images resource=new Images();
int result=resource.collectResources();
if (result == 0 )
{
JOptionPane.showMessageDialog(mainFrame, "One or more images could not be found or retreived.\nPlease try again! :)", "Fatal Error",JOptionPane.ERROR_MESSAGE);
}
...
private void paintTerrain(Graphics g)
{
for (int j=0;j<grid.rows; j++)
{
for (int k=0; k<grid.columns; k++)
{
if (grid.terrain[j][k].type == 0)
{
g.drawImage(/*grid.terrain[j][k].getImage()*/Images.grass01, GRID_OFFSET + (j*GRID_SIZE), GRID_OFFSET + (k*GRID_SIZE), this); //should use commented argument, but that produces no image whatsoever
} // end Crucial, unit-detected, IF statement
} //inner for
} //outer for
}
...
class Images //has all the image resources
{
public static Image grass01;
public static Image noImage;
public int collectResources()
{
grass01=new ImageIcon("resources/grass01.gif").getImage();
noImage=new ImageIcon("resources/noImage.gif").getImage();
return 1;
}
} //class Images ends here
The full code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GridTest
{
public static void main(String[] args)
{
GridTestStarter starter=new GridTestStarter();
starter.init();
starter.start();
}
} //end of class GridTest
////////////////////////////////////////////////////////////////////////////////
class GridTestStarter implements MouseMotionListener
{
JFrame mainFrame;
JPanel mainPanel;
GridPanel gridPanel;
UnitGrid grid;
int past_shade_x, past_shade_y=-1;
public void init()
{
mainFrame=new JFrame("Grid Test");
mainFrame.setSize(800, 600);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel=new JPanel();
mainPanel.setBackground(Color.WHITE);
grid=new UnitGrid(20, 20); //20 x 20 grid
gridPanel=new UnitGridPanel(grid); //panel to display grid and units
gridPanel.setGridOffset(20); //20 pixels away from upper left hand corner
gridPanel.setGridSize(22); //22 x 22 pixels (don't know why, just seemed right)
gridPanel.finalizeSize(); //use current settings to create correct Panel size in pixels
gridPanel.setDoubleBuffered(false); //??? is this doing anything?
gridPanel.setShading(false);
mainFrame.getContentPane().add(gridPanel);
Images resource=new Images();
int result=resource.collectResources();
if (result == 0 )
{
JOptionPane.showMessageDialog(mainFrame, "One or more images could not be found or retreived.\nPlease try again! :)", "Fatal Error",JOptionPane.ERROR_MESSAGE);
}
}
public void start()
{
mainFrame.setVisible(true);
gridPanel.repaint();
gridPanel.addMouseMotionListener(this);
}
public void mouseMoved(MouseEvent e)
{
int x= e.getX() - gridPanel.getGridOffset(); //removes borders from x
int y= e.getY() - gridPanel.getGridOffset();
int shade_x2=-1;
int shade_y2=-1;
if ( ( (x>0) && (x<gridPanel.getGridSize()*grid.columns) ) && ( (y>0) && (y<gridPanel.getGridSize()*grid.rows) ) )
{ //if x and y are within the grid
shade_x2=(int) (x/gridPanel.getGridSize() ); //discovers which square x is in x-wise
shade_y2=(int) (y/gridPanel.getGridSize() ); //same for y
if ( (past_shade_x != shade_x2) || (past_shade_y != shade_y2) )
{ //if the square is different then previous than set square to shade and repaint()
gridPanel.setShade(shade_x2, shade_y2);
gridPanel.repaint();
}
}
else //x or y is outside the grid
{
if ( (past_shade_x != shade_x2) || (past_shade_y != shade_y2) )
{ //moved to outside the grid
gridPanel.setShade(-1,-1); //will trigger ShadeAway procedure during repaint
gridPanel.repaint();
}
}
past_shade_x=shade_x2;
past_shade_y=shade_y2;
}
public void mouseDragged(MouseEvent e) {}
} //end of Starter/Controller class
////////////////////////////////////////////////////////////////////////////////
class Terrain
{
byte type;
Image image;
public Terrain(byte type_given)
{
type=type_given;
image=findImage();
}
private Image findImage()
{
if (type == 0)
{
return Images.grass01;
}
return Images.noImage;
}
public Image getImage()
{
return image;
}
}
////////////////////////////////////////////////////////////////////////////////
class UnitGrid
{
public static final byte VISIBLE=0;
public static final byte FOGGED=1;
public static final byte UNDISCOVERED=2;
byte[][] unit;
byte[][] FoW;
Terrain[][] terrain;
int rows, columns=0;
public UnitGrid(int x1, int y1)
{
rows=x1;
columns=y1;
unit=new byte[rows][columns];
terrain=new Terrain[rows][columns];
FoW=new byte[rows][columns];
for (int j=0;j<rows; j++)
{
for (int k=0; k<columns; k++)
{
unit[j][k]=0;
terrain[j][k]= new Terrain( (byte) 0);
FoW[j][k]=VISIBLE; //should be UNDISCOVERED after debugging
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
class UnitGridPanel extends GridPanel
{
UnitGrid grid;
public UnitGridPanel(UnitGrid gridToUse)
{
super(gridToUse.rows, gridToUse.columns);
grid=gridToUse;
setDrawGrid(false); //allows for additional drawing to occur before painting grid
}
public void paint(Graphics g)
{
paintBackground(g); //clear to white
paintTerrain(g); //do grass, etc.
//paintFoW(g); //then shade black Fog of War
//paintShade(g); //finally, do a shade (this should be removed and replaced with GIF drawing selection sprite)
//paintUnits(g); //will draw the units onto the grid...
paintGrid(g); //and finish off with the default black grid
}
private void paintUnits(Graphics g)
{
for (int j=0;j<grid.rows; j++)
{
for (int k=0; k<grid.columns; k++)
{
if (grid.unit[j][k]!=0)
{
} // end Crucial, unit-detected, IF statement
} //inner for
} //outer for
} //end of function paintUnits()
private void paintTerrain(Graphics g)
{
for (int j=0;j<grid.rows; j++)
{
for (int k=0; k<grid.columns; k++)
{
if (grid.terrain[j][k].type == 0)
{
g.drawImage(/*grid.terrain[j][k].getImage()*/Images.grass01, GRID_OFFSET + (j*GRID_SIZE), GRID_OFFSET + (k*GRID_SIZE), this);
} // end Crucial, unit-detected, IF statement
} //inner for
} //outer for
}
private void paintFoW(Graphics g)
{
for (int j=0;j<grid.rows; j++)
{
for (int k=0; k<grid.columns; k++)
{
if (grid.FoW[j][k]!=UnitGrid.VISIBLE)
{
} // end Crucial, unit-detected, IF statement
} //inner for
} //outer for
}
} //end of class UnitGridPanel
////////////////////////////////////////////////////////////////////////////////
class GridPanel extends JPanel
{
protected int GRID_SIZE; //pixel width and height of the pixels
protected int GRID_OFFSET; //width and height away from upper left-hand corner that grid begins
private boolean SHADING;
private boolean DRAW_GRID;
public Color gridColor;
public Color shadeColor;
public Color backgroundColor;
int columns, rows;
private int shade_x, shade_y = 0;
public GridPanel(int rowss, int columnss)
{
gridColor=Color.BLACK;
shadeColor=new Color(198,226,255); //BGR values for square shading (blueish)
backgroundColor=Color.WHITE;
SHADING=true;
DRAW_GRID=true; //by default grid is drawn, and shading is active
GRID_SIZE=20; //individual grid nodes 20 x 20 pixels
GRID_OFFSET=0; //by default, grid is in Upper Left hand corner
rows=rowss;
columns=columnss; //ensure at least a size of 1
}
public void finalizeSize()
{
setSize( (columns*GRID_SIZE) + columns, (rows*GRID_SIZE) + rows ); //set the size to what is needed for drawing and stuff.
}
public void paint(Graphics g)
{
paintBackground(g); //clear drawing board, including gridoffset, with background color. Default white
paintShade(g); //paints or removes shading before grid is drawn
if (DRAW_GRID) //grid drawing can be turned off here, either for a different timing or another reason by subclasses.
{
paintGrid(g);
}
}
protected void paintBackground(Graphics g)
{
g.setColor(backgroundColor);
g.fillRect(0,0,(GRID_OFFSET*2)+(GRID_SIZE*columns), (GRID_OFFSET*2)+(GRID_SIZE*rows) );
}
protected void paintShade(Graphics g)
{
if (SHADING) //allow user to turn off shading
{
if (shade_x >= 0) //shade != -1 indicates shading required
{
shade(g); //shades individual square
}
else
{
shadeAway(g);
}
}
}
protected void paintGrid(Graphics g)
{
g.setColor(gridColor); //default Black
for (int j=0; j<=rows; j++)
{
g.drawLine( GRID_OFFSET,(j*GRID_SIZE)+GRID_OFFSET,GRID_SIZE*columns+GRID_OFFSET,(j*GRID_SIZE)+GRID_OFFSET );
}
for (int j=1; j<=columns; j++)
{
g.drawLine( (j*GRID_SIZE)+GRID_OFFSET, GRID_OFFSET, (j*GRID_SIZE)+GRID_OFFSET, GRID_SIZE*rows+GRID_OFFSET );
}
g.drawLine(GRID_OFFSET, GRID_OFFSET, GRID_OFFSET, GRID_OFFSET+(rows*GRID_SIZE) ); //not sure why this is here, and not just in the second For loop's iteration
}
private void shade(Graphics g)
{
g.setColor(shadeColor); //default color
g.fillRect(GRID_OFFSET + (GRID_SIZE * shade_x), GRID_OFFSET + (GRID_SIZE * shade_y), GRID_SIZE, GRID_SIZE);
//starts drawing with whatever shade_x/_y is (0,0 indicates upper left node) and draws size equal in pixels to GRID_SIZE
}
private void shadeAway(Graphics g) //exactly the same as paintBackground(), this ensures that shading is removed. ////Possibly obsolete/unnecessary?
{
g.setColor(backgroundColor);
g.fillRect(GRID_OFFSET, GRID_OFFSET, (columns*GRID_SIZE)+GRID_OFFSET, (rows*GRID_SIZE)+GRID_OFFSET);
}
public void setShade(int xs, int ys)
{
shade_x=xs;
shade_y=ys;
}
public void setShading(boolean tof)
{
SHADING=tof;
}
public boolean getShading()
{
return SHADING;
}
public void setDrawGrid(boolean tof)
{
DRAW_GRID=tof;
}
public boolean getDrawGrid()
{
return DRAW_GRID;
}
public void setGridOffset(int offsetInPx)
{
GRID_OFFSET=offsetInPx;
}
public int getGridOffset()
{
return GRID_OFFSET;
}
public void setGridSize(int sizeInPx)
{
GRID_SIZE=sizeInPx;
}
public int getGridSize()
{
return GRID_SIZE;
}
} //end of GridPanel class
////////////////////////////////////////////////////////////////////////////////
class Images //has all the image resources
{
public static Image grass01;
public static Image noImage;
public int collectResources()
{
grass01=new ImageIcon("resources/grass01.gif").getImage();
noImage=new ImageIcon("resources/noImage.gif").getImage();
return 1;
}
} //class Images ends here