私は Java で Tetris クローンに取り組んでいますが、行全体をクリアして上記のすべてを削除するまで、すべてが適切に機能しているようです。私のデータはすべて変換を適切に表していますが、私の paintComponent メソッドは行をクリアするだけのようですが、repaint() 呼び出しの前と同じように上に表示されているものはすべて残します。新しいピースはファントムブロックを通り抜けて落ち、上のピースが落ちたであろう一番下の列の目に見えないブロックに着地します。
これが私のペイントコンポーネントメソッドです:
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());
}
}
これは、タイマー リスナーの actionPerformed メソッドの一部で、ブロックを検出/クリアし、repaint メソッドを呼び出します。
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
最初の repaint() メソッドが呼び出されるまでに、well 配列は行全体が完全に null であることを適切に示します。repaint() メソッドでパネルを更新してこの空の行を表示したいのですが、paintComponent() が呼び出されていないようです。これは 2 番目の repaint() メソッドにも当てはまります。行をクリアしてドロップダウンした後、ブロックを新しい位置に表示するようにフレームを更新したいと考えています。繰り返しますが、paintComponent() は呼び出されません。ただし、前回の repaint() 呼び出しでは、落下するピースの位置を更新するだけで、以前に行う必要があったかどうかに関係なく、repaint() は paintComponent() を呼び出します。質問 1 は、なぜ paintComponent() が repaint() 呼び出しのこのインスタンスでのみ呼び出されるのかということです。
ただし、paintComponent() が呼び出されてメソッドの最後に到達すると、デバッグ モードで追跡して、パネルが変更を反映する行を確認します。:"Repaintmanager.paintDirtyRegions(Map< Component,Rectangle >)" 行:856 に到達すると、行がクリアされ、新しい落下ピースが表示されますが、見えないブロックとファントム ブロックがあります。
2 つ目の質問は、なぜ paintComponent() がこのように動作するのかということです。明らかに、Repaintmanager と Java ペインティング全般についてかなり読む必要がありますが、誰かが私にこれを説明してくれれば非常にありがたいです。
重要な場合の主な方法は次のとおりです。
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);
}
}
これが不快に長い場合は申し訳ありません。