I'm working on a Tetris clone in Java, and all seems to work properly until I want a full row to be cleared and everything above to be dropped. Although all my data properly represents the transformation, my paintComponent method seems to only clear the row, but leave everything displayed above as it was before the repaint() call. The new piece will fall through the phantom blocks and land on invisible blocks at the bottom row, where the above pieces would have fallen.
Here's my paint component method:
public void paintComponent(Graphics page)
{
super.paintComponent(page);
Graphics2D page2D = (Graphics2D) page;
for (int c = 0; c < 10; c++)
{
for (int r = 0; r < 18; r++)
{
if (well[c][r] != null) //Well is a 2D array of Block objects that have Rectangle object, coordinates and color
{
page2D.setColor(well[c][r].getColor());
page2D.fill(well[c][r].getSquare());
page2D.setColor(Color.gray);
page2D.draw(well[c][r].getSquare());
}
}
}
for (int i = 0; i < 4; i++) //tetro = the player's tetris piece
{
page2D.setColor(tetro.getColor());
page2D.fill(tetro.getBlock(i).getSquare());
page2D.setColor(Color.GRAY);
page2D.draw(tetro.getBlock(i).getSquare());
}
}
This is the portion of my actionPerformed method in my Timer listener that detects/clears blocks and calls the repaint method.
int count = 0; //Number of occupied cells in well
int clears = 0; //number of rows to be clear
int lowestClear = -1; //Lowest row that was cleared, -1 if none
for (int row = 0; row < 18; row++)
{
for (int col = 0; col < 10; col++)
{
if (well[col][row] != null)
{
count++;
}
}
if (count == 10)
{
clears++;
if (lowestClear < 0)
{
lowestClear = row;
}
for (int col = 0; col < 10; col++)
{
well[col][row] = null;
}
}
count = 0;
}
if (clears > 0)
{
repaint(); //Doesn't call paintComponent()
for (int i = 1; i <= clears; i++)
{
for (int r = 16; r >= 0; r--)
{
if (r > lowestClear)
{
break;
}
for (int c = 0; c < 10; c++)
{
if (well[c][r] != null)
{
well[c][r+1] = well[c][r];
well[c][r] = null;
}
}
}
}
repaint(); //Does not call paintComponent()
}
tetro.fall();
repaint(); //DOES call paint component
By the time the first repaint() method is called, the well array properly shows that the full row is now entirely null. I would like the repaint() method to update the panel to show this empty row, but paintComponent() doesn't seem to be called. This is also the case with the second repaint() method, where I would like it to update the frame to show the blocks in their new positions after clearing a row and dropping them down. Again, paintComponent() isn't called. For the last repaint() call, however, where I just want to update the position of the falling piece regardless of whatever updates it may or may not have needed to make before, repaint() DOES call paintComponent(). So: question number one is, why is paintComponent() only called at this instance of the repaint() call.
However, when paintComponent() is called and it reaches the end of the method, I follow it in debug mode to see at what line does the panel reflect the changes. Once it reaches :"Repaintmanager.paintDirtyRegions(Map< Component,Rectangle >)" line:856, it has cleared the row and displays the new falling piece, but has invisible blocks and phantom blocks.
So, my second question is, why is paintComponent() behaving in this way. Obviously I need to do a good bit of reading on Repaintmanager and Java painting in general, but I would greatly appreciate it if someone could explain this to me.
Here's the main method if important:
import javax.swing.JFrame;
public class TetrisDriver
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Tetris");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Matrix()); //Matrix = jPanel class
frame.pack();
frame.setVisible(true);
}
}
I apologize if this is obnoxiously long.