3

こんにちは、Ian Cinnamon 著「悪の天才のためのビデオ ゲームのプログラミング」という本を読んでいます。プロジェクトの 1 つで、彼はレーシング ゲームのアニメーションを作成する方法を説明しています。以下に簡単なコードを書きました(「ほとんど」不要なものをすべて削除しています)。しかし、結果は同じです:ちらつき.

私の質問は、同じコードを使用して(明らかに少し変更して)、ちらつきを止めるにはどうすればよいですか? 私のポイントは、 JLabelImageIconクラス、およびスプライトシートの画像ファイルを使用してゲーム全体を作成できるため、別の方法 (コード全体を変更する) を見つけることではありません。私のポイントは、これらの形状を削除せずにちらつきの問題を解決することです [ Rectangle (fillRect & 可能であれば drawImage)]。

ちなみにこれができないと「なんでそんなことするの!?」または「それは不可能です」も良い答えです。(使わないようにしましょう!)

ありがとう!

import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.net.*;

public class Race extends JFrame {
    public static void main(String[] args){
        new Race();
    }
        private Rectangle r1 = new Rectangle(0,0,800,100);
        private Rectangle r2 = new Rectangle(0,100,100,400);
        Image img = null;

    public Race(){
        super("Some Title");
        setVisible(true);
        setSize(800,600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        try{
             URL url= this.getClass().getResource("someImage.png");
            img =Toolkit.getDefaultToolkit().getImage(url);
        }catch(Exception e){}
        Race.GameLoop gameHeart = new Race.GameLoop();
        gameHeart.run();
    }

    public void paint(Graphics g){
        super.paint(g);
        g.setColor(Color.GREEN);
        g.fillRect(r1.x, r1.y, r1.width, r1.height);
        g.setColor(Color.RED);
        g.fillRect(r2.x, r2.y, r2.width, r2.height);
        g.drawImage(img, r2.x, r2.y, r2.width, r2.height, this);
        try {
            Thread.sleep(75);
        } catch (InterruptedException ex) {}
        repaint();
    }

    public class GameLoop extends Thread {
        public void run(){
            while(true){
                //game animations and logic
                //even if I put repaint() here it still flicker
            }
        }
    }
}
4

2 に答える 2

4

最上位のコンテナ ( などJFrame) にはペイントしないでください。これらはダブル バッファリングをサポートしていません。

代わりに、次のようなものを使用しますJPanel

paintComponent規約では、 よりもオーバーライドを優先しますpaint。これはpaint、実際には非常に複雑な方法であるため、主に行われます

どのpaint方法でもこれを絶対に行わないでください。

try {
    Thread.sleep(75);
} catch (InterruptedException ex) {}
repaint();

まず、遅延はすべてゲーム スレッドで処理する必要がありますThread#sleep。paint メソッド内で呼び出すと、イベント ディスパッチ スレッドがスリープ状態になり、(マウスとキーボードの操作に関する) イベントをポストできなくなり、プログラムが応答しなくなったように見えます。これにより、後で問題が発生します。

ペイント メソッド内からrepaint(または を呼び出す可能性のあるメソッド) を呼び出さないでください。repaintこれは、再描画マネージャーに別の描画サイクルをスケジュールするように要求するだけで、プログラムが応答しなくなるまで CPU を食いつぶします。繰り返しますが、これはゲーム スレッドの機能です。

Swing はスレッド保存ではないことに注意してください。UI とのすべての対話は、イベント ディスパッチ スレッドのコンテキスト内から行う必要があります。詳細については、Concurrency in Swingを参照してください。

ラインアニメーションをスムーズにする方法をご覧ください。例としてJava Bounce Ball

カスタム ペインティングの実行およびAWT と Swing でのペインティングをお読みください。

于 2012-11-26T20:00:29.077 に答える
0

ここに簡単な答えがあります(あなたが怠惰すぎるか、MadProgrammerとtrashgodからの答えで与えられたドキュメントを読む時間がない場合は、ちなみにこれを書くのに役立ちます)。ただし、時間に余裕ができたらすぐにドキュメントを読むことを強くお勧めします。

ちらつきがないように書き直した質問のコードです。コードを2つのクラスに分けました。GameFrameクラスのゲームを含むJFrameと、JPanelを拡張するRaceクラスのRacingゲーム自体(質問の一部)です。

GameFrame.java

import javax.swing.*;

public class GameFrame extends JFrame {

    public static void main(String args[]){
        new GameFrame();
    }

    public GameFrame(){
        super("Graphics with JFrame");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(800,600);
        Race game = new Race();
        this.getContentPane().add(game);
        this.setVisible(true);
        game.run();
    }

}

Race.java

import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.net.*;

public class Race extends JPanel implements Runnable {

    private Rectangle r1 = new Rectangle(0,0,800,100);
    private Rectangle r2 = new Rectangle(0,100,100,400);
    Image img = null;

    public Race(){
        try{
             URL url= this.getClass().getResource("someImage.png");
            img =Toolkit.getDefaultToolkit().getImage(url);
        }catch(Exception e){}
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.GREEN);
        g.fillRect(r1.x, r1.y, r1.width, r1.height);
        g.setColor(Color.RED);
        g.fillRect(r2.x, r2.y, r2.width, r2.height);
        g.drawImage(img, r2.x, r2.y, r2.width, r2.height, this);
}

    public void run() {
        while(true){
            try {
                Thread.sleep(75);
            } catch (InterruptedException ex) {}
            repaint();

            //game animations and logic
        }
    }
}

MadProgrammerとtrashgodに改めて感謝します。他の人にコメントする代わりに自分の質問に答えて申し訳ありませんが、前と後の違いを明確に示さなければなりませんでした。繰り返しますが、ちらつきを避けるためになぜこれらの変更を行ったのか理解できない場合。MadProgrammerとtrashgodのコメントと回答を読んでください。

于 2012-11-27T07:33:53.417 に答える