我如何绘制两个重叠的jpanel,使绘制的图形都显示在屏幕上



我有两个jpanel。一个面板在0,0处绘制了一个100x100的矩形。另一个是100x100的矩形,画在100,100。我的问题是,当两个JPanel都在JFrame的内容窗格上绘制时,一个JPanel(最后绘制的那个)覆盖了另一个,隐藏了它的图形。下面是画两个矩形和我尝试过的东西的简化代码。

package playground;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Playground{
    public Playground(){
        JFrame frame = new JFrame("My Frame");
        frame.setSize(400, 400);
        JPanel backPanel = new JPanel(){;
                @Override
                public void paintComponent(Graphics g){
                    super.paintComponent(g);
                    Graphics2D g2 = (Graphics2D)g;
                    Rectangle2D rect = new Rectangle2D.Double(0, 0, 100, 100);
                    g2.draw(rect);
                }
        };
        JPanel frontPanel = new JPanel(){
            @Override
            public void paintComponent(Graphics g){
                super.paintComponent(g);
                Graphics2D g2 = (Graphics2D)g;
                Rectangle2D rect = new Rectangle2D.Double(150, 150, 100, 100);
                g2.draw(rect);
            }
        }; 
        frontPanel.setOpaque(true); //Does nothing
        frontPanel.setBackground(new Color(0, 0, 0, 0)); //Does nothing
        frontPanel.setForeground(new Color(0, 0, 0, 0)); //Erases the rectangle drawn

        frame.getContentPane().add(backPanel);
        frame.getContentPane().add(frontPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    public static void main(String[] args){
        System.out.println("Hello World");
        new Playground();
    }
}

如果有人关心我为什么要这样做,

我正在创建游戏爆发。我是一个新手程序员,我没有游戏理论的知识。所以我决定避免大量渲染和缓冲的最聪明的方法是使用四个jpanel。最后面是一个静态的JPanel,上面绘制了一个图像(有趣的背景图像)。一个画着桨的JPanel。一个带有砖块的JPanel。还有一个JPanel,上面画了一个球。我的理由是,如果桨没有被移动,背景和砖块没有被击中,我就不必重新绘制桨。如果一个砖块被击中,我将更新砖块的数组列表,并在相应的JPanel上调用repaint。

我是一个新手程序员,我没有博弈论知识。

好的,我们可以这样做。

所以我决定避免大量渲染和缓冲的最聪明的方法是使用四个jpanel。

你刚才不必要地把程序复杂化了。

把JPanel想象成一个画布。你想要绘制整个Breakout游戏;砖块,球拍和球,在一个JPanel画布上。不用担心,如果你想的话,你可以重画整个画布,速度足够快,可以达到每秒60帧。

要做到这一点,方法是创建一个Brick类、一个Paddle类和一个Ball类。你创建了一个游戏模型类,其中包含一个Paddle类的实例,一个Ball类的实例和一个Brick类的实例列表。

Brick类将有字段来确定它在墙上的位置,当球与砖块碰撞时得分的数量,砖块的颜色,以及知道如何绘制砖块的绘制方法。

球类将具有确定其x, y位置,方向,速度的字段,以及知道如何绘制球的绘制方法。

Paddle类将拥有用于确定其x, y位置,方向,速度的字段,以及知道如何绘制桨的绘制方法。

Game Model类将具有确定球何时与砖块碰撞的方法,确定球何时与砖块碰撞的方法,确定球何时与墙壁碰撞的方法,以及调用其他模型类draw方法来绘制球,桨和砖块墙的绘制方法。

这应该足以让你开始朝着正确的方向前进。

编辑回答问题:

我如何在所有这些类中实现绘制方法?

下面是一个示例Ball类。我还没有测试moveBall方法,所以它可能需要一些调整

import java.awt.Graphics;
import java.awt.geom.Point2D;
public class Ball {
    private Point2D position;
    /** velocity in pixels per second */
    private double  velocity;
    /**
     * direction in radians
     * <ul>
     * <li>0 - Heading east (+x)</li>
     * <li>PI / 2 - Heading north (-y)</li>
     * <li>PI - Heading west (-x)</li>
     * <li>PI * 3 / 2 - Heading south (+y)</li>
     * </ul>
     * */
    private double  direction;
    public Point2D getPosition() {
        return position;
    }
    public void setPosition(Point2D position) {
        this.position = position;
    }
    public double getVelocity() {
        return velocity;
    }
    public void setVelocity(double velocity) {
        this.velocity = velocity;
    }
    public double getDirection() {
        return direction;
    }
    public void setDirection(double direction) {
        this.direction = direction;
    }
    public void moveBall(long milliseconds) {
        Point2D oldPosition = position;
        // Calculate distance of ball motion
        double distance = velocity / (1000.0D * milliseconds);
        // Calculate new position
        double newX = distance * Math.cos(direction);
        double newY = distance * Math.sin(direction);
        newX = oldPosition.getX() + newX;
        newY = oldPosition.getY() - newY;
        // Update position
        position.setLocation(newX, newY);
    }
    public void draw(Graphics g) {
        int radius = 3;
        int x = (int) Math.round(position.getX());
        int y = (int) Math.round(position.getY());
        // Draw circle of radius and center point x, y
        g.drawOval(x - radius, y - radius, radius + radius, radius + radius);
    }
}

draw方法将球绘制到它实际所在的位置。这就是draw方法所做的。

实际上移动球是Game Model类的职责。移动球的方法包含在这个类中,因为移动球所需的信息存储在ball类中。

我给球的半径为3,或直径为6像素。你可能想让球更大,并使用fillOval方法而不是drawOval。

我应该每隔30ms调用repaint()吗

基本上,是的。

在psudeocode中,创建一个游戏循环

while (running) {
    update game model();
    draw game();
    wait;
}

首先,更新游戏模型。我给你上了一堂球课。你会有类似的桨和砖类课程。它们都有绘制方法。

你的游戏模型类以适当的顺序调用所有这些绘制方法。在Breakout中,你会先画边界,然后是砖块,然后是桨,最后是球。

你的JPanel (canvas)调用Game Model类中的一个draw方法。

我没有一个示例游戏给你看,但是如果你读了文章Sudoku Solver Swing GUI,你会看到如何把一个Swing GUI放在一起,你会看到模型类如何实现绘制方法。

我建议你停止在Breakout上工作一段时间,并通过Oracle Swing教程。不要在匆忙编写程序时跳过任何部分。在您尝试使用Swing之前,请通读整个教程,以便了解它是如何工作的。

相关内容

  • 没有找到相关文章

最新更新