0

只是希望人们可以帮助我正确理解 RepaintManager 在尝试创建动画时是如何工作的。基本上我正在创建一个将生物/图像绘制和更新到 JFrame 的程序。每个生物对象都包含用于绘制它的所有信息,例如 x,y 坐标和 BufferedImage。目前,每次生物对象移动时,它都会调用 repaint(),正如您将在下面的我的paint/paintComponent(不确定哪个是最好的)方法中看到的那样,它将在所有现有生物中运行一个循环并更新它们在屏幕上的位置和图形.

所以我的查询,这是最好的方法,因为我担心 RepaintManager 正在重绘屏幕上的所有内容,这不是很有效。我阅读了一些关于剪辑或覆盖更新方法的帖子/文章,但我无法完全理解它们 - 所以每次调用 repaint 时它是否可能只更新已更改的对象/生物?

我正在谈论的一些代码:

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 Timer 是否会更好,因为当一个生物尝试将新生物添加到 crlist 时,我目前正在收到 ConcurrentModificationException。

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 回答