0

アニメーションを作成しようとするときに RepaintManager がどのように機能するかを正しく理解するのに役立つことを願っています。基本的に、生き物/画像をJFrameに描画して更新するプログラムを作成しています。各クリーチャー オブジェクトには、x、y 座標や BufferedImage など、ペイントで描画できるすべての情報が含まれています。現在、クリーチャー オブジェクトが移動するたびに、repaint() が呼び出されます。これは、以下の paint/paintComponent (どちらが最適かはわかりません) メソッドでわかるように、既存のすべてのクリーチャーをループして、画面上の位置とグラフィックを更新します。 .

私の質問は、 RepaintManager が画面上のすべてを再描画していることを懸念しているため、これがこれを行うための最良の方法です。これはあまり効率的ではありません。更新メソッドのクリッピングまたはオーバーライドに関するいくつかの投稿/記事を読んだことがありますが、それらについて理解することはできません-再描画が呼び出されるたびに、変更されたオブジェクト/クリーチャーのみを更新することは可能ですか?

私が話していることのいくつかのコード:

public void paintComponent (Graphics g) {
       super.paintComponent(g);
       //setDoubleBuffered(true); //Probably not needed?
       Graphics2D g2d = (Graphics2D) g;

       //Draws the land area for penguins.
       g2d.setColor(new Color(121,133,60));
       g2d.fill3DRect(land.x, land.y, land.width, land.height, true);
       //OR g2d.fill(land);
       g2d.setColor(Color.BLUE);
       g2d.fill(sea);

       drawCreatures(g2d);              
    }

paint メソッドのすべてのグラフィックスは変更されず、再描画する必要はありませんが、以下のメソッドは...

   private void drawCreatures(Graphics2D g2d) {

   try {
        for (Creature c : crlist) {
            g2d.drawImage(c.createImage(txs,tys), c.getPos(1).width, c.getPos(1).height, this);
            //g2d.drawImage(cImg,c.getPos(1).width,c.getPos(1).height,this);

            if (c instanceof Fish && c.getMating().equals(Mating.WBABY)) {
                int xos=0;
                for (Creature fb : c.getChildren()) {
                    if (fb.getMating().equals(Mating.BABY)) g2d.drawImage(fb.createImage(txs,tys),c.getPos(1).width+xos,c.getPos(1).height+50,txs/2,tys/2,this);
                    xos+=25;
                }
            }

            if (c.getInfo()==true) displayInfo(g2d,c); //This changes when a creature is clicked on.
            else if (c.getState()!=State.NORMAL || c.getMating().equals(Mating.LOVE)) drawState(g2d,c); //updated through a creature's move/search methods.
       }
   }
   catch(ConcurrentModificationException cme) { System.out.println("CME ERROR!"); }

}

重要な部分は、強化された for ループの最初の行です。これは、JFrame ウィンドウに画像を描画するためです。createImage メソッドは単純に生き物の画像を取得し、変換/変更します。たとえば、ペイントが使用する前に左に移動すると反転します。

アニメーションは現在、スレッドを実行している各クリーチャーによって処理されますが、クリーチャーが新しいクリーチャーを crlist に追加しようとすると現在 ConcurrentModificationException が発生しているため、Swing Timer の方が良いかどうかも疑問です。

private class Creature implements Behaviours<Creature>, Runnable {
//...variables
//...constructor
//...methods for updating the creature/object

@Override
public void run() {

    while (getState()!=State.DEAD) {
        move(); //where the coordinates of a creature is updated.
        repaint();
        try { Thread.sleep(1000); }
        catch(InterruptedException e) {}
    }
}

したがって、クリーチャーの移動と再描画ごとに1秒ごとに呼び出されますが、ペイント内の各クリーチャーをループする必要がないか、再描画が呼び出されたときにそれを呼び出したクリーチャーのみを更新する方法が必要です。

提案や別の投稿を教えていただければ幸いです。ありがとう。

4

1 に答える 1

0

このコードを使用できます。描画オブジェクトを PaintObject、背景にも拡張する必要があります。独自のペイントを実装します。このコードがあなたにアイデアを与えることを願っています。再塗装が必要なすべての領域を収集できます。次に、そこにあるオブジェクトを見つけます。その後、この部分だけ塗り直します

class GameCanvas extends Canvas {
    private static final int FPS = 24;
    private boolean isAlive;
    private Vector<PaintObject> allObjects = new Vector<Rec.PaintObject>();
    private Vector<Rectangle> paintingClipsInTurn = new Vector<Rectangle>();
    public GameCanvas() {
        isAlive = true;
        new Thread(){
            @Override
            public void run() {
                while(isAlive){
                    long ti1 = System.currentTimeMillis();
                    repaint();
                    long ti2 = System.currentTimeMillis();
                    long frameTime = ti2-ti1;
                    long targetFrameTime = 1000/FPS;
                    if (targetFrameTime > frameTime){
                        try {
                            Thread.sleep(targetFrameTime - frameTime);
                        } catch (InterruptedException e){
                        }
                    }
                }
            }
        }.start();
    }

    @Override
    public void paint(Graphics g) {
        if (paintingClipsInTurn.size() > 0) {
            Rectangle s = paintingClipsInTurn.get(0);
            int min_x = s.x;
            int min_y = s.y;
            int max_x = s.x + s.width;
            int max_y = s.y + s.height;
            for (Rectangle r : paintingClipsInTurn) {
                if (r.x < min_x)
                    min_x = r.x;
                if (r.y < min_y)
                    min_y = r.y;
                if (r.x + r.width > max_x)
                    max_x = r.x + r.width;
                if (r.y + r.height > max_y)
                    max_y = r.y + r.height;
            }
            Rectangle totalclip = new Rectangle(min_x, min_y, max_x-min_x, max_y-min_y);
            for (PaintObject object : allObjects) {
                Rectangle r1 = object.getClip();
                if (totalclip.intersects(r1)){
                    object.paintObject(g);
                }
            }
        }
        paintingClipsInTurn.clear();
    }

    public void addDrawComponent(PaintObject object){
        object.parent = this;
        allObjects.add(object);
    }
    public void removeDrawComponent(PaintObject object){
        object.parent = null;
        allObjects.remove(object);
    }
    void requestRepaint(PaintObject object){
        paintingClipsInTurn.add(object.getClip());
    }
}


abstract class PaintObject {

    GameCanvas parent;
    private int x,y,w,h;
    public void setPosition(int x,int y,int w,int h){
        if (parent != null) parent.requestRepaint(this);
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        if (parent != null) parent.requestRepaint(this);
    }
    Rectangle getClip(){
        Rectangle rect = new Rectangle();
        rect.x = x;
        rect.y = y;
        rect.width = w;
        rect.height = h;
        return rect;
    }
    void paintObject(Graphics g){
        g.translate(x, y);
        Shape oldClip = g.getClip();
        g.setClip(0, 0, w, h); // in here you have to actually find intersection of current clip and object clip. this code needs to be fixed. 
        paint(g);
        g.setClip(oldClip);
        g.translate(-x, -y);
    }
    public abstract void paint(Graphics g);
}
于 2014-12-11T10:54:56.907 に答える