Problem mit repaint()

Ahoi!
Ich wollte mal probeweise Versuchen ein kleines Spiel in Java zu programmieren. Dabei wollte ich am Anfang nur mal eine Figur die ich mit der Tastatur über den Bildschirm lenken kann. Das funzt auch, nur seh ich die Grafik immer nur flimmern weil repaint() immer die ganze Zeichenfläche löscht, obwohl repaint() immer VOR dem nächsten Zeichenbefehl ausgeführt wird! :mad:

import java.awt.event.*;
import javax.swing.*;

public class Start extends JFrame {
	private static final long serialVersionUID = 1L;
	
	JPanel stdp;
	Graphics g;
	int x=10;
	int y=10;
	
	public static void main(String[] args) {
		new Start();
	}
	
	public Start() {
		this.setTitle("test-game");
		this.setLayout(null);
		//this.setBackground(new Color(0,0,0));
		this.setBounds(100, 100, 500, 250);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);
		this.addKeyListener( new KeyLi() );
		
		this.stdp = new JPanel();
		stdp.setBounds(0, 0, 500, 250);
		stdp.setBackground(new Color(250, 250, 250));
		
		this.add( stdp );
		
		this.g = this.stdp.getGraphics();
		if (g==null)
			System.err.println("null!");
		else
			g.drawString("test", 100, 100);
	}
	
	public void step( int key ) {
		if ( key == 37 ) { // LEFT
			if ( this.x-5 >= 0 )
				this.x -= 5;
			this.stdp.repaint();
			g.drawImage( Sprites.player_left, x, y, Sprites.player_left.getHeight(null), Sprites.player_left.getWidth(null), null);
		} else if ( key == 39 ) { // RIGHT
			this.x += 5;
			this.stdp.repaint();
			g.drawImage( Sprites.player_right, x, y, Sprites.player_right.getHeight(null), Sprites.player_right.getWidth(null), null );
		}
	}
	
	class KeyLi implements KeyListener {
		public void keyPressed(KeyEvent e) {
			step( e.getKeyCode() );
			
		}

		public void keyReleased(KeyEvent e) {}

		public void keyTyped(KeyEvent e) {}
	}
}

class Sprites {
	public static final Image player_left = new ImageIcon("dixie_left.gif").getImage();
	public static final Image player_right = new ImageIcon("dixie_right.gif").getImage();
}

Weiß jemand wo da der Hund begraben liegt?

ich glaub dein Problem kannst du durch Buffering beheben
http://www.galileocomputing.de/openbook/javainsel6/javainsel_15_006.htm#mjb7fad202ab53b6fdf68d31044d515222

Ein Graphics-Objekt sollte nicht gespeichert werden, das bereitet nur Probleme. Stattdessen sollte die paintComponent()-Methode überschrieben werden.

Und: Swing-Komponenten sind bereits gepuffert.

Ergo muss ich quasi eine Klasse schreiben die von JPanel erbt? Und wie kann ich die Methode dann gezielt ansprechen?

EDIT: Habs jetzt mal provisorisch so gelöst:

		if ( key == 37 ) { // LEFT
			if ( this.x-5 >= 0 )
				this.x -= 5;
			
			this.stdp.repaint(x+Sprites.player_left.getHeight(null), y, 5, Sprites.player_left.getHeight(null));
			g.drawImage( Sprites.player_left, x, y, Sprites.player_left.getHeight(null), Sprites.player_left.getWidth(null), null);
		} else if ( key == 39 ) { // RIGHT
			this.stdp.repaint(x, y, 5, Sprites.player_right.getHeight(null));
			this.x += 5;
			//this.stdp.repaint();
			g.drawImage( Sprites.player_right, x, y, Sprites.player_right.getHeight(null), Sprites.player_right.getWidth(null), null );
		}
	}```

Dabei habe ich allerdings das Problem, dass es leicht flackert, wenn sich die Figur bewegt ...
Gibt es sind extra Zeichenobjekte die für solche Aufgaben geeignet sind?

Wenn du zwei Objekte gleichzeitig bewegen willst (zwei Spieler),
dann brauchst du einen Thread, der abwechselnd jedem eine Chance einräumt:

/*
 * GameDemo.java
 */

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class GameDemo extends JFrame {

    private GameDemo.GamePanel gamePanel;

    public GameDemo() {
        super("Pfeiltasten=rot, A,D,W,S=schwarz");
        setSize(400, 300);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        gamePanel = new GamePanel();
        add(gamePanel);
        new Thread(gamePanel).start();
    }

    public static void main(final String[] args) {
        new GameDemo().setVisible(true);
    }

    class GamePanel extends JPanel implements KeyListener, Runnable {

        private int x1,  y1,  x2,  y2 = 100;
        private boolean r1,  l1,  o1,  u1,  r2,  l2,  o2,  u2;
        private int speed1=5, speed2=2;
        public GamePanel() {
            addKeyListener(this);
            setFocusable(true);
            requestFocusInWindow();
        }

        public void keyTyped(final KeyEvent e) {
        }

        public void keyPressed(final KeyEvent e) {
            setKey(e, true);
        }

        public void keyReleased(final KeyEvent e) {
            setKey(e, false);
        }

        private void setKey(final KeyEvent e, final boolean b) {
            if (e.getKeyCode() == KeyEvent.VK_A) {
                l1 = b;
            }
            if (e.getKeyCode() == KeyEvent.VK_D) {
                r1 = b;
            }
            if (e.getKeyCode() == KeyEvent.VK_W) {
                o1 = b;
            }
            if (e.getKeyCode() == KeyEvent.VK_S) {
                u1 = b;
            }
            if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                l2 = b;
            }
            if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                r2 = b;
            }
            if (e.getKeyCode() == KeyEvent.VK_UP) {
                o2 = b;
            }
            if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                u2 = b;
            }

        }

        public void run() {
            while (true) {
                if (l1) {
                    x1 -= speed1;
                }
                if (r1) {
                    x1 += speed1;
                }
                if (o1) {
                    y1 -= speed1;
                }
                if (u1) {
                    y1 += speed1;
                }
                if (l2) {
                    x2 -= speed2;
                }
                if (r2) {
                    x2 += speed2;
                }
                if (o2) {
                    y2 -= speed2;
                }
                if (u2) {
                    y2 += speed2;
                }
                repaint();

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        protected void paintComponent(final Graphics g) {
            super.paintComponent(g);
            g.fillOval(x1, y1, 10, 10);
            g.setColor(Color.RED);
            g.fillOval(x2, y2, 10, 10);
        }
    }
}```