我正在用Java开发一个俄罗斯方块克隆,在我想要清除整行并删除上面的所有内容之前,一切似乎都正常工作。虽然我所有的数据都正确地表示了转换,但我的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数组正确地显示整行现在完全为空。我希望repaint()方法更新面板以显示这一空行,但似乎没有调用paintComponent()。第二个repaint()方法也是如此,我希望它在清除一行并将其放下后,更新帧,以在新位置显示块。同样,paintComponent()没有被调用。然而,对于最后一个repaint()调用,我只想更新下落部件的位置,而不管它之前是否需要进行任何更新,repaint()确实调用了paintComponent()。所以:第一个问题是,为什么paintComponent()只在repaint()调用的这个实例中被调用。
然而,当调用paintComponent()并到达方法的末尾时,我会在调试模式下跟踪它,以查看面板在哪一行反映更改。一旦到达:“RepaitManager.PaintDirtRegions(地图
所以,我的第二个问题是,为什么paintComponent()会以这种方式运行。显然,我需要好好阅读一下RepaitManager和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);
}
}
如果时间过长,我道歉。
您可以尝试自己直接调用paint()
,而不是使用repaint()
。
Graphics g;
g = getGraphics();
paint(g);
这样,当您想进行更改时,它将立即绘制。将此分配给另一个函数,并在您想立即看到更改时调用它。
repaint()
不要调用paintComponent()
,这就是repaint()
方法的正确工作场景。
它只标记组件应该重新绘制的状态,Swing本身会进一步调用paintComponent()。
许多repaint()
调用只能导致单个paintComponent()
调用,这是有效的行为。
首先,如果你还没有这样做,我会通读AWT和Swing中的绘画,这解释了Swing(和AWT)使用的绘画方案。
其次,你不控制重绘,重绘管理器和操作系统控制重绘,你只是提供建议。
第三,你可以看看JComponent.paint立即方法,它需要知道你想要更新的领域,但可能会有所帮助
来自Java文档
立即绘制此组件中的指定区域及其与该区域重叠的所有子体。
很少有必要调用此方法。在大多数情况下,调用重新绘制更有效,它会推迟实际的绘制,并将冗余请求折叠成单个绘制调用。如果需要在分派当前事件时更新显示,此方法非常有用。
我可能会更谨慎地将游戏状态渲染到屏幕外缓冲区,并在paintComponent
方法中使用它。你可以把它们放在一个队列中,然后在绘制过程中弹出它们,这样就可以根据需要创建更多或更少的内容(保留一些内容,并不断增长,根据需要缩小这些内容)。。。
问题内容: 我读过,我们应该始终在循环内调用a : 它可以正常工作而没有循环,那为什么呢? 问题答案: 你不仅需要循环它,还需要在循环中检查条件。Java不能保证仅通过notify()/ notifyAll()调用或正确的notify()/ notifyAll()调用来唤醒你的线程。由于此属性,无环版本可能在你的开发环境上工作,而在生产环境上意外失败。 例如,你正在等待一些东西: 邪恶的线程出现了
问题内容: 我只是想简化我的一个类,并以与flyweight设计模式相同的样式介绍了一些功能。 但是,对于为什么总是调用after ,我有点困惑。我没想到这一点。谁能告诉我为什么会这样,否则我如何实现此功能?(除了将实现放入hack之外)。 这是一个例子: 输出: 为什么? 问题答案: 使用 时,你需要控制一个新实例的创建。 使用 时,你需要一个新的实例的控件初始化。 是实例创建的第一步。首先调用
本文向大家介绍为什么在__new __()之后总是调用__init __()?,包括了为什么在__new __()之后总是调用__init __()?的使用技巧和注意事项,需要的朋友参考一下 Python具有一种称为魔术方法的特殊类型的方法,该方法以前置和双下划线命名。 如果我们想谈论魔术方法__new__,那么显然也需要谈论__init__方法。创建实例时将调用魔术方法__new__。而在创建实
只是一个关于继承的理论问题。 假设我有一个类“GamePanel”,它扩展了JPanel。 我知道在课堂上,如果我调用,它将调用父类(JPanel)绘制方法。 但是如果我创建一个对象GamePanel,它不应该继承所有的JPanels方法吗?那么在这种情况下,为什么不工作?当前对象应该能够访问该方法,对吗? 如果没有,为什么
问题内容: 我只是想简化我的一个类,并以与flyweight设计模式相同的样式介绍了一些功能。 但是,对于为什么总是被称为after ,我有点困惑。我没想到这一点。谁能告诉我为什么会这样,否则我如何实现此功能?(除了将实现放到中之外)。 这是一个例子: 输出: 为什么? 问题答案: 使用时,你需要控制一个新实例的创建。 使用 时,你需要一个新的实例的控件初始化。 是实例创建的第一步。首先调用它,它
我在活动的中放置了一些缓存清理代码,但大多数情况下,除非通过显式地完成活动,否则这些代码不会执行。 编辑:只读仅在或系统资源不足时调用。那么我需要把我的缓存清理代码放在哪里呢?如果我把它放在中,用户返回到应用程序,缓存就会被清除。我实际上是在缓存中存储重要的临时文件,这些文件不应该在中删除。