0

画面に 1 つずつ描画されるグリッドがいくつかあります。矢印キーを使用して、グリッドをグループとして移動します。Swing はデフォルトで doubleBuffered であると言われているので、これframe.createBufferStrategy(2)は悪い習慣だと思いますが、問題は、手動のダブル バッファリングを使用しない場合、グリッドがずれてグリッド間にいくつかの穴が現れることです。手動のダブルバッファリングを使用すると修正されます。

また、実際のプログラム (SSCCE ではない) でグラフィックの問題 (ダイアログのボタンが正しく表示されないなど) が発生しているため、ダブルバッファリングの不適切な実装が原因である可能性があると考えました。

以下はプログラムの SSCCE で、手動でダブル バッファリングしないとグリッドがずれます。

package SSCCE;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {
boolean manuallyDoubleBuffered = false; //change this

static Main main;

public final JFrame frame = new JFrame();
public final Keys keys = new Keys();
private JPanel panel;
private BufferStrategy bufferStrategy;

 

public static void main(String[] args) {
    main = new Main();
    main.initiate();
    // --START LOOP--
    Thread loop = new Thread(main.new Looper());
    loop.start();
}

public void initiate() {
    frameInit();
    keys.start();
}

private void frameInit() {
    frame.setSize(1200, 750);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    setUpGUI();
    if (manuallyDoubleBuffered)
        frame.createBufferStrategy(2); // manual double buffering
    bufferStrategy = frame.getBufferStrategy();
}

private void setUpGUI() {
    panel = new JPanel() {
        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            Main.main.rendering(g2d);
            super.paintComponent(g);
        }
    };

    LayoutManager layout = new FlowLayout();
    frame.getContentPane().setBackground(Color.black);
    panel.setLayout(layout);
    panel.setOpaque(false);//
    JButton but1 = new JButton("but1");
    panel.add(but1);
    frame.add(panel);
}

class Looper implements Runnable {
    @Override
    public void run() {
        Main.main.gameLoop();
    }
}

private void gameLoop() {
    // variables are declared at start
    while (true) {

        if (manuallyDoubleBuffered)
            paint(); // MANUAL double buffering
        else
            frame.repaint();// no manual double buffering

        update();

        try {
            Thread.sleep(1000 / 60);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}// loop end

private void update() {
    move();

}

private void rendering(Graphics2D g2d) {
    // // testing
    paintGrids(g2d);
}

private void move() {
    x += sx;
    y += sy;
}

int sx = 0; //speedX
int sy = 0; //speedY

//top left corner of the grid
int x = 0; 
int y = 0;

private void paintGrids(Graphics2D g) {
    for (int i = 0; i < 100; i++) {
        for (int t = 0; t < 100; t++) {
            g.setColor(Color.GRAY);
            g.fillRect(i * 50 + x, t * 50 + y, 50, 50);
            g.setColor(Color.BLACK);
            g.drawString(i + "," + t, i * 50 + x, t * 50 + y + 10);
        }
    }

}

public void paint() {
    // uses double buffering system.
    do {
        do {
            Graphics2D g2d = (Graphics2D) bufferStrategy.getDrawGraphics();
            g2d.fillRect(0, 0, frame.getWidth(), frame.getHeight());

            try {
                frame.paint(g2d);
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
            g2d.dispose();
        } while (bufferStrategy.contentsRestored());
        bufferStrategy.show();
    } while (bufferStrategy.contentsLost());
}
}

class Keys implements KeyListener {// Trimmed down to shorten SSCCE
private final int leftKey = 37; // left b.
private final int rightKey = 39; // Right b.
private final int upKey = 38;// up k.
private final int downKey = 40;// down k.

public void start() {

    Main.main.frame.addKeyListener(this);
    Main.main.frame.setFocusable(true);
}

private void left() {
    Main.main.sx -= 10;
}

private void right() {
    Main.main.sx += 10;
}

private void up() {
    Main.main.sy -= 10;
}

private void down() {
    Main.main.sy += 10;
}

@Override
public void keyPressed(KeyEvent e) {
    // TODO Auto-generated method stub
    System.out.println(e.getKeyCode());
    switch (e.getKeyCode()) {
    case leftKey:
        left();
        break;
    case rightKey:
        right();
        break;
    case downKey:
        down();
        break;
    case upKey:
        up();
        break;
    }
}

@Override
public void keyReleased(KeyEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void keyTyped(KeyEvent arg0) {
    // TODO Auto-generated method stub

}

}// END OF THE KEYS CLASS

swing の Oracle チュートリアルでは、ゲーム ループでの使用法について説明していません。それを行う最良の方法は何ですか?私は何か間違ったことをしていますか?

他のコンピューターで視覚的なエラーが再現されない場合に備えて、スクリーンショットをアップロードします。 これらの黒い線は発生しないはずです。 黒い線は、長方形の誤用が原因です。手動ダブル バッファリングが true に設定されている場合、それらは存在しません。

前もって感謝します。

編集:グリッドが移動しているときに黒い線が発生することを忘れていました。

また、手動のダブルバッファリングがパフォーマンスを大幅に低下させることも発見しました。

編集 2: 問題を修正し、回答として投稿しましたが、コードに自由にコメントしてください。メイン クラス (gameLoop を除く) は、プログラムで使用する実際のメイン クラスに似ています。

4

2 に答える 2

1

背景に変化は見られませんでした。これが私が行ったコードの変更です。

public static void main(String[] args) {
    main = new Main();

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            main.initiate();
        }           
    });

    // --START LOOP--
    Thread loop = new Thread(main.new Looper());
    loop.start();
}

SwingUtilities.invokeLater を呼び出して Swing アプリケーションを開始する必要があります。

于 2014-12-06T17:23:09.200 に答える
0

私は問題を発見し、そのようなことが他の誰かに起こった場合に備えてここに書いています.

この問題は、プログラムがマルチスレッド化されているために発生しました。グリッド (x と y) の左上の座標は、paintGrids() メソッドの途中で別のスレッドによって更新されました。手動のダブル バッファリングにより、プログラムの速度が (数百倍) 低下し、x と y がキーによって更新される前に、paintGrids メソッドがペイントを終了することができました。

それを修正するために、paintGrids メソッドの先頭に以下を追加しました。

int x = this.x;
int y = this.y;
于 2014-12-06T19:44:26.183 に答える