使用Java Graphics2D动画迷宫解决方案绘画

时间:2014-03-18 05:05:59

标签: java swing animation paintcomponent maze

我正在从事计算机科学项目,并且在接近72小时后一直被这个问题困扰。我第三次使用谷歌,谷歌和谷歌。不知何故,我似乎无法让它发挥作用。基本上,我必须画一个迷宫,然后为解决方案路径设置动画。这是我到目前为止的绘画代码,绘制迷宫的作品很好,我根本无法让它生动。

private class MazePanel extends JPanel
{
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        MazeApp.g = (Graphics2D) g;
        paintMaze();
    }
}
...
private static Timer timer = new Timer(1000, new ActionListener(){
    private int space = 0;
    @Override
    public void actionPerformed(ActionEvent e)
    {
        Point3d p = solutionSpaces.get(space);
        g.fillRect((int)p.x * spaceLength, (int)p.y * spaceWidth, spaceLength, spaceWidth); // g is static reference to Graphics2D, set from MazePanel
        mazePanel.repaint(); //mazePanel is instance
        space++;
    }
});
...
private void paintMaze()
{
    if (this.reader != null)
    {
        for (int col = 0; col < this.reader.getWidth(); col++)
        {
            for (int row = 0; row < this.reader.getLength(); row++)
            {
                MazeConstruct c = reader.check(row, col, floor);
                if (c == MazeConstruct.WALL)
                    g.setColor(Color.BLACK);
                else if (c == MazeConstruct.ELEVATOR)
                    g.setColor(Color.YELLOW);
                else if (c == MazeConstruct.START)
                    g.setColor(Color.CYAN);
                else if (c == MazeConstruct.FINISH)
                    g.setColor(Color.RED);
                else if (c == MazeConstruct.OPEN)
                    g.setColor(Color.GRAY);
                if (c != MazeConstruct.SOLUTION && c != MazeConstruct.TRAVERSED)
                    g.fillRect(row * spaceLength, col * spaceWidth, spaceLength, spaceWidth);
                g.setColor(Color.DARK_GRAY);
                g.drawRect(row * spaceLength, col * spaceWidth, spaceLength, spaceWidth);
            }
        }
    }
    if (solving)
    {
        timer.setInitialDelay(0);
        timer.start();
    }
}

提供的代码将立即充分绘制完整的解决方案,但我需要它作为动画逐步浏览每个单独的空间。请帮我。这是我绝对的最后手段!如果我需要提供任何其他信息,请告诉我。此外,欢迎建设性的批评。非常感谢。

[编辑]我在这里发现了一个随机问题,其中提出了一个通用点,即计时器的刻度(actionPerformed())应该只更新数据的状态(例如移动到下一个空格)而不是实际绘制,并且那个图形在paintComponent调用之后不应该保持g。我将使用这些新的小信息来解决我的问题。答案仍然受到欢迎。

2 个答案:

答案 0 :(得分:0)

如果我理解你的问题(如果没有,请纠正我),当你逐步浏览每个空间时,你不能让屏幕更新。在这种情况下你会使用repaint();方法

答案 1 :(得分:0)

在渲染图形Component时,您必须记住几件事:

1)GraphicsGraphics2D对象不是永久性的,它是在调用repaint()时临时创建的,你不能依赖Graphics对象的副本(比如保存它)作为静态变量)。使用后必须将其丢弃。

2)仅使用传递给paintComponent()方法的Graphics对象的副本,从paintComponent()方法内部使用Graphics对象调用所有方法。

以下是您必须使用的模板:

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.draw...(...);
    g.fill...(...);
    yourMethod((Graphics2D)g);
    ....
    ....
}
private void yourMethod(Graphics2D g) {
    g.setPaint(..);
    g.draw...();
    ....
}

您正在保存Graphics对象并在paintComponent()之外使用它不正确,并可能导致未定义的行为。您使用已保存的g.fillRect((int)p.x * spaceLength, (int)p.y * spaceWidth, spaceLength, spaceWidth);!实例调用g,这是一个严重的问题。

另一件需要记住的事情是,如果drawaint()方法已被绘制,则它可能不会调用paintComponent()。

以上模板适用于您的情况。但是,如果你真的对非常好的表现感兴趣(完成大量的绘图),你必须使用双缓冲(即使用单独的线程绘制到图像然后立即将图像放在屏幕上)。