Mit getSubimage ruckelt das Bild

tugberk

Mitglied
Hallo,

ich habe folgendes Problem: Es geht um die Zeile 69(unten ist der Code). Wenn ich diese Zeile weglasse, dann bewegen
sich meine Sprites flüssig, wenn nicht, dann bewegen sie sich ruckelartig. Das, was mich jedoch wundert, ist, dass die
Framerate davon nicht beeinträchtigt wird, und trotzdem sieht es so aus, als würde das Bild ruckeln.
Ich verstehe den Zusammenhang nicht. Der Konstruktor Game() wird nur einmal aufgerufen. Was hat das mit
dem Zeichnen zu tun? Wenn das so weiter geht, dann lass ich getSubimage(...) komplett weg, und zeichne
Bildausschnitte komplett mit drawImage(...). Ich dachte, wenn ich meine Sprites mit getSubimage unterteile, dann
ich das schneller. Hat jemand von Euch schon so ein ähnliches Problem gehabt?
Java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JPanel;


public class Game extends JPanel implements Runnable {

    private Image star, integral;
    private BufferedImage bad ,audi, test;
    private Thread animator;
    private int x, y;
    public Font f1; 
    public long frameRate = 0;
    public long frames = 0;
    public long seconds = 0;

    private final int DELAY = 25; // Framerate: 40 Bilder pro Sekunde


    public Game() {
    	/*
    	int width;
    	int height;
    	*/
        setDoubleBuffered(true);
        
        ImageIcon ii = new ImageIcon(this.getClass().getResource("star.png"));
        star = ii.getImage();
        ImageIcon i2 = new ImageIcon(this.getClass().getResource("integral.png"));
        integral = i2.getImage();
        
        
        try
        {
           audi = ImageIO.read( new File("audi.png") ) ;
        }
        catch(IOException ex)
        {
        	ex.printStackTrace();
        	System.out.println("Datei nicht gefunden");
        	System.exit(1);
        }
        
        try
        {
           bad = ImageIO.read( new File("bad.png") ) ;
        }
        catch(IOException ex)
        {
        	ex.printStackTrace();
        	System.out.println("Datei nicht gefunden");
        	System.exit(1);
        }
        /*
        width = bad.getWidth();
        height = bad.getHeight();
        BufferedImage bad = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        */
        test = audi.getSubimage(100, 100, 100, 100);
        
        f1 = new Font("Arial",Font.BOLD,20);

        x = y = 10;
    }

    public void addNotify() {
        super.addNotify();
        animator = new Thread(this);
        animator.start();
    }
    
    /*
    @Override 
    protected void paintComponent( Graphics g ) 
    { 
      super.paintComponent( g ); 
      g.drawImage(audi, 0, 0, this);
      g.drawImage(test,150,150,this);
      g.drawLine( 10, 10, 400, 450 ); 
      g.drawImage(star, x, y, this);
    } */
    
    
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D)g;
        g2d.drawImage(audi, 0, 0, this);
        g2d.drawImage(star, x, y, this);
        g2d.drawImage(integral, 200, 200, this);
        g2d.drawImage(bad, 200+x, 200+y, this);
        
        //g2d.drawImage(audi, 0, 200, 20, 220, 0, 0, 20, 20, this);
            
        g2d.setColor(Color.WHITE);
        g2d.setFont(f1);
        g2d.drawString("Framerate: " + frameRate,850,30);
        g2d.drawString("Sekunden: " + seconds,850,50);
        Toolkit.getDefaultToolkit().sync();
        g.dispose();
    }


    public void cycle() {

        x += 1;
        y += 1;

        if (y > 440) {
            y = -45;
            x = -45;
        }
    }

    public void run() {

        long beforeTime, timeDiff, sleep;
        long fTime=0, dTime;

        beforeTime = System.currentTimeMillis();
        
        Test.pp("Hallo");
        

        while (true) {

            cycle();
            repaint();

            dTime = System.currentTimeMillis() - fTime;
            
            timeDiff = System.currentTimeMillis() - beforeTime;
            sleep = DELAY - timeDiff;

            if (sleep < 0)
                sleep = 25;
            try {
                Thread.sleep(sleep);
            } catch (InterruptedException e) {
                System.out.println("interrupted");
            }

            beforeTime = System.currentTimeMillis();
            if(dTime >= 1000)
            {
            	frameRate = frames * 1000 / dTime;
            	frames = 0;
            	fTime = System.currentTimeMillis();
            	seconds++;
            }
            frames++;
        }
    }
}
 
[OT]
Ausserdem dispost du das Graphics-Objekt, das dir übergeben wird. Darf man nicht machen.
Auf so etwas habe ich gewartet... :lol:
Wann sollte man Graphics überhaupt disposen, wenn man am Ende so etwas findet? (Auszug aus SunGraphics2D OpenJDK)
Java:
    /**
     * This object has no resources to dispose of per se, but the
     * doc comments for the base method in java.awt.Graphics imply
     * that this object will not be useable after it is disposed.
     * So, we sabotage the object to prevent further use to prevent
     * developers from relying on behavior that may not work on
     * other, less forgiving, VMs that really need to dispose of
     * resources.
     */
    @Override
	public void dispose() {
        surfaceData = NullSurfaceData.theInstance;
        invalidatePipe();
    }

    /**
     * Graphics has a finalize method that automatically calls dispose()
     * for subclasses.  For SunGraphics2D we do not need to be finalized
     * so that method simply causes us to be enqueued on the Finalizer
     * queues for no good reason.  Unfortunately, that method and
     * implementation are now considered part of the public contract
     * of that base class so we can not remove or gut the method.
     * We override it here with an empty method and the VM is smart
     * enough to know that if our override is empty then it should not
     * mark us as finalizeable.
     */
    @Override
	public void finalize() {
        // DO NOT REMOVE THIS METHOD
    }
Gibt es noch andere Java2D-RenderEngines (Denke nicht, wär ja schön, z.B. bei Android)?[/OT]
Ansonsten (um auch was zum Thema beizutragen)... Ich würde für so etwas niemals getSubImage() verwenden, denn damit bekommt man einen neuen Image-Puffer der erstens auch erstmal kopiert sein will um zweitens in einen weiteren gezeichnet zu werden (erneutes kopieren). Besser ist hier die Graphics-Methode mit den vielen Int-Werten als Parameter. [c]g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer)[/c].
 
ja Spacerat, so mach ichs:
Code:
g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer)
.
Das ist schnell genug, habe ich ausprobiert. Trotzdem würde mich interessieren, warum das Bild so ruckelt. An paint und paintCompenent liegt es nicht, habe ich ausprobiert. Auch an dem dispose liegt es nicht. Ich werde das Programm am Mittwoch an der FH testen, an einem LINUX-Rechner. Ich benutze gerade Windows Vista und Eclipse. Danke für Eure Antworten.
 
Anmerkung:
Auf keinen Fall solltest du den Zeichen-Code in die paint()-Methode einer Swing-Komponente schreiben.
Dafür ist die paintComponent()-Methode gedacht.
Code:
setDoubleBuffered(true)
hat keine Wirkung, weil Swing-Komponenten von Haus aus gepuffert sind.
Und falls das
Code:
getGraphics()
immer noch irgendwo im Code steht, ist das auch immer noch ein Fehler.
Bei simplen Animationen solltest du auch ohne Synchronisation auskommen.
 
Trotzdem würde mich interessieren, warum das Bild so ruckelt.
Es liegt an der Quelle des ImageBuffer vom Bildauschnitt. Mit getSubImage erstellst du bei jedem Paintloop einen neuen (zwei Kopiervorgänge pro Loop) und mit dieser drawImage-Methode halt nicht (ein Kopiervorgang pro Loop).
 

Zurück
Oben