Java анимация и менеджер перекрасок

Просто надеясь, что люди помогут мне правильно понять, как работает 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);              
    }

Вся графика в методе рисования не изменится и не должна быть перекрашена, однако метод ниже...

   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 просто получает изображение существ и конвертирует / модифицирует, например, переворачивает его, когда они двигаются влево, прежде чем его использует краска.

Анимация в настоящее время обрабатывается каждым существом, использующим Поток, однако мне также интересно, будет ли лучше Таймер Swing, поскольку в настоящее время я получаю исключение ConcurrentModificationException, когда существо пытается добавить новое существо в crlist.

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 секунду для каждого движения существа и перерисовки вызывается, но я бы хотел, чтобы способ не проходил по циклу через каждое существо в краске, или чтобы при вызове перекраски он обновлял только существо, которое его вызвало.

Будем благодарны за любые предложения или просто указание мне на другой пост. Благодарю.

1 ответ

Вы можете использовать этот код. Вы должны расширить свои объекты рисования на 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);
}
Другие вопросы по тегам