1

私は2つのJPanelを持っています。1 つのパネルには、0,0 に描かれた 100x100 の長方形があります。もう1つは100、100で描画された100x100の長方形です。私の問題は、両方のJPanelがJFrameのコンテンツペインに描画されると、一方のJPanel(最後に描画されたもの)が他方を覆い、グラフィックを隠してしまうことです。以下は、2 つの長方形を描画する単純化されたコードと、私が試したことです。

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();
    }

}

なぜ私がこれをやりたいのか気になる人がいれば、

ゲームブレイクアウトを作成しています。私は初心者プログラマーで、ゲーム理論の知識はありません。そこで、大量のレンダリングとバッファリングを回避する最も賢明な方法は、4 つの JPanel を用意することだと判断しました。画像が描かれた一番後ろの静的 JPanel (楽しい背景画像)。パドルが描画された JPanel。レンガが描かれた JPanel。そして、ボールが描かれたJPanel。私の理論的根拠は、パドル、背景、およびヒットされていないレンガが動かされていない場合、パドルを再描画する必要がないということです。ブリックがヒットした場合、ブリックの arrayList を更新し、対応する JPanel で repaint を呼び出します。

4

1 に答える 1

4

私は初心者プログラマーで、ゲーム理論の知識はありません。

わかりました、それで作業できます。

そこで、大量のレンダリングとバッファリングを回避する最も賢明な方法は、4 つの JPanel を用意することだと判断しました。

プログラムを不必要に複雑にしただけです。

JPanel をキャンバスと考えてください。ブレイクアウト ゲーム全体を描画する必要があります。レンガ、パドル、ボールを 1 つの JPanel キャンバスに。必要に応じて、1 秒あたり 60 フレームの速度でキャンバス全体を再描画できます。

これを行う方法は、Brick クラス、Paddle クラス、および Ball クラスを作成することです。Paddle クラスの 1 つのインスタンス、Ball クラスの 1 つのインスタンス、および Brick クラスのインスタンスのリストを含む Game Model クラスを作成します。

Brick クラスには、壁内での位置、ボールがレンガに衝突したときに獲得されるポイント数、レンガの色、および 1 つのレンガを描画する方法を知る draw メソッドを決定するためのフィールドがあります。

ボール クラスには、x、y 位置、方向、速度、およびボールの描画方法を認識する draw メソッドを決定するためのフィールドがあります。

Paddle クラスには、その x、y 位置、方向、速度、およびパドルを描画する方法を認識する draw メソッドを決定するためのフィールドがあります。

ゲーム モデル クラスには、ボールがレンガに衝突するタイミングを決定するメソッド、ボールがレンガに衝突するタイミングを決定するメソッド、ボールが壁に衝突するタイミングを決定するメソッド、および他のモデル クラスの draw メソッドを呼び出してオブジェクトを描画する 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 ピクセルにしました。ボールを大きくして、drawOval の代わりに fillOval メソッドを使用することもできます。

30ms 間隔で repaint() を呼び出すだけでよいでしょうか

基本的に、はい。

疑似コードでは、ゲーム ループを作成します。

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

まず、ゲーム モデルを更新します。私はあなたにボールのクラスを与えました。パドルとブリックにも同様のクラスがあります。それらにはすべて draw メソッドがあります。

Game モデル クラスは、これらすべての描画メソッドを適切な順序で呼び出します。Breakout では、最初に境界を描き、次にレンガ、次にパドル、最後にボールを描きます。

JPanel (キャンバス) は、Game Model クラスの one draw メソッドを呼び出します。

お見せできるゲームの例はありませんが、Sudoku Solver Swing GUIという記事を読めば、Swing GUI を組み立てる方法と、モデル クラスが描画メソッドを実装する方法がわかります。

ブレイクアウトの作業をしばらく中断し、Oracle Swing チュートリアルを実行することをお勧めします。プログラムを書きたくて急いでセクションをスキップしないでください。チュートリアル全体を読み、Swing の動作を理解してから使用してください。

于 2013-05-24T22:13:34.377 に答える