Swing Jump and Run Bewegung!?

fl_ex

Bekanntes Mitglied
Hey Leute,

ich hab ein Frame auf dem ein Panel liegt mit ner Hintergrundgrafik und ner Figur dadrauf... Möchte die figur nun bewegen...hier der Code erstmal:

Java:
		window.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
			}

			@Override
			public void keyReleased(KeyEvent e) {
			}

			@Override
			public void keyPressed(KeyEvent e) {
				int keyCode = e.getKeyCode();

				// links
				if (keyCode == 37) {
					player.setLocation(player.getX() - 10, player.getY());
				}

				// springen
				if (keyCode == 38) {
					// player.setLocation(player.getX()-3, player.getY());
				}

				// recshts
				if (keyCode == 39) {
					player.setLocation(player.getX() + 10, player.getY());
				}

				// ducken
				if (keyCode == 40) {
					// player.setLocation(player.getX() - 3, player.getY());
				}

			}
		});

funktioniert auch alles soweit... jedoch wartet er in dem Fall beim Anlaufen einmal kurz und rennt dann los... Und ich kann z.B in dem Fall keine anderen Tasten mehrdrücken...

jemand eine Idee wie ichs anders angehen kann?

gesammter code:
Main:

Java:
/**
 * 
 */
package main;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;

import classes.Player;
import classes.World;

/**
 * 
 */
public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		JFrame window = new JFrame();
		World world = new World("Y:\\bg.jpg");
		final Player player = new Player("Y:\\player.png");
		window.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
			}

			@Override
			public void keyReleased(KeyEvent e) {
			}

			@Override
			public void keyPressed(KeyEvent e) {
				int keyCode = e.getKeyCode();

				// links
				if (keyCode == 37) {
					player.setLocation(player.getX() - 10, player.getY());
				}

				// springen
				if (keyCode == 38) {
					// player.setLocation(player.getX()-3, player.getY());
				}

				// recshts
				if (keyCode == 39) {
					player.setLocation(player.getX() + 10, player.getY());
				}

				// ducken
				if (keyCode == 40) {
					// player.setLocation(player.getX() - 3, player.getY());
				}

			}
		});

		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.setSize(500, 500);
		window.add(world);

		world.setLayout(null);

		window.setVisible(true);
		window.setSize(window.getPreferredSize());
		window.setLocationRelativeTo(null);

		world.add(player);
		player.setLocation(50, 10);

	}
}

Player:
Java:
/**
 * 
 */
package classes;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

/**
 * 
 */
@SuppressWarnings("serial")
public class Player extends JLabel {

	private Image img;

	public Player(String img) {
		this(new ImageIcon(img).getImage());
	}

	public Player(Image img) {
		this.img = img;
		Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
		setPreferredSize(size);
		setMinimumSize(size);
		setMaximumSize(size);
		setSize(size);
		setLayout(null);
	}

	public void paintComponent(Graphics g) {
		g.drawImage(img, 0, 0, null);
	}
	
}
 
M

MiDniGG

Gast
Ändere die Location vom Player in einem extra Thread.
Und bei keyPressed und keyTyped setze einen boolean bspw. right auf true. Bei keyReleased wieder auf false. Das sollte das Problem beheben.
 

fl_ex

Bekanntes Mitglied
Hey danke schonmal für die Hilfe, jedoch habe es nun so gemacht und nun verschwindet die figur wenn ich eine Taste drücke^^

Java:
/**
 * 
 */
package main;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;

import classes.Player;
import classes.World;

/**
 * 
 */
public class Main {

	static boolean right = false;

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		JFrame window = new JFrame();
		World world = new World("Y:\\bg.jpg");
		final Player player = new Player("Y:\\player.png");
		final Player kasten = new Player("Y:\\kasten.png");

		final Thread threadRight = new Thread() {
			public void run() {
				while (right == true) {
					player.setLocation(player.getX() + 10, player.getY());
				}
			}
		};

		window.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
				int keyCode = e.getKeyCode();
				if (keyCode == 39) {
					right = true;
				}
			}

			@Override
			public void keyReleased(KeyEvent e) {

				right = false;
			}

			@Override
			public void keyPressed(KeyEvent e) {
				int keyCode = e.getKeyCode();

				// rechts
				if (keyCode == 39) {
					right = true;
					threadRight.start();
				}
			}
		});

		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.setSize(500, 500);
		window.add(world);

		world.setLayout(null);

		window.setVisible(true);
		window.setSize(window.getPreferredSize());
		window.setLocationRelativeTo(null);

		world.add(player);
		world.add(kasten);
		player.setLocation(50, 10);
		kasten.setLocation(400, 200);

	}
}
 

Michael...

Top Contributor
jedoch wartet er in dem Fall beim Anlaufen einmal kurz und rennt dann los...
Das liegt an der im Betriebssystem eingestellte Wiederholungsverzögerung.

Ich hab sowas noch nie gemacht, würde das aber etwas anders angehen und nur auf das Drücken und Loslassen von Tasten reagieren (nicht auf das Gedrückthalten)
Grundsätzlich würde ich das ganze statt mit Key Bindings anstelle von KeyListenern umsetzen. Über deren Actions wird dann einfach nur der Status gesetzt bzw. eine Aktion initialisiert. Das Laufen, Hüpfen usw. wird dann in einem separaten Thread ausgeführt.
 

fl_ex

Bekanntes Mitglied
wie ist das nu gemeint? Also habs immer nochnicht hinbekommen... Habe jetzt bewegunge nach Rechts und Links in Threads gepackt... jedoch ist dieses "Stocken" immernoch da... :/
 

Fu3L

Top Contributor
Java:
final Thread threadRight = new Thread() {
            public void run() {
                while (right == true) {
                    player.setLocation(player.getX() + 10, player.getY());
                }
            }
        };

Das halte ich nicht für sinnvoll^^ Einen ganzen Thread nur für so einen einfachen Methodenaufruf? Und dann die Variabel right nicht einmal volatile gesetzt... Könnte sein, dass sie nie als wahr oder wenn sie einmal wahr ist, nie wieder als false sichtbar wird, weil das Setzen in einem anderen Thread stattfindet. (Wobei ich zugeben muss, dass ich in meinem ersten SpaceInvaders aus Uniwssenheit auch nciht die Bewegungsbooleans volatile gemacht habe und es funktionierte trotzdem^^ Kann aber einfach Glück gewesen sein ;))
(Edit2: Wird bei repaint() irgendwo ein synchronized Block aufgerufen? Das würds erklären^^)

Du solltest deine ganze Klasse am besten Runnable implementieren lassen und einen update-loop einbauen, da du noch mehr machen wollen wirst, als nur deine Spielfigur bewegen zu lassen.

Edit:

Java:
	public void keyPressed(KeyEvent e) {
		
		
		if(e.getKeyCode() == KeyEvent.VK_LEFT) {
			
			leftPressed = true;
			rightPressed = false; //Es darf immer nur eine der beiden Tasten aktiv sein
			
		}
		
	} //Ende keyPressed
	
	public void keyReleased(KeyEvent e) {
		
		
		if(e.getKeyCode() == KeyEvent.VK_LEFT) {
			
			leftPressed = false;
			
		}
          }
So in etwa sollte das (die Abfrage der Tasten) aussehen. Erst prüfen: "Wird die Taste runtergedrückt, dann boolean setzen". "Wird die Taste nicht mehr gedrückt, dann boolean zurücksetzen"
(Hab das schnell aus Eclipse rauskopiert und dran rumgebastelt, also Einrückung etwas mau grad^^)
 
Zuletzt bearbeitet:

fl_ex

Bekanntes Mitglied
Würde erstmal gerne eine funktionierende Funktion haben, die Funktioniert den Rest kann ich daraus ja dann evtl. erschließen ^^

wieso geht jedoch das nicht?
Java:
window.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {

				int keyCode = e.getKeyCode();

				if (keyCode == 37) {
					left = true;
                                                              right = false;
				}
				if (keyCode == 39) {
					right = true;
                                                                left=false;
				}
			}

			@Override
			public void keyReleased(KeyEvent e) {
				right = false;
				left = false;
			}

			@Override
			public void keyPressed(KeyEvent e) {
				if (right == true) {
					new MoveRightThread(player);
					System.out.println("nach rechts!");
				}

				if (left == true) {
					new MoveLeftThread(player);
					System.out.println("nach links!");
				}
			}
		});[
beim drücken wird right oder left auf true gesetzt und beim halten direkt danach müsste es die figur sich doch bewegen... :/
 
Zuletzt bearbeitet:

Fu3L

Top Contributor
Hast du mein Edit noch bemerkt? So sollte es aussehen. Und in dem Haupt-Update Loop, den ein solches Spiel haben sollte, kannst du dann die Richtung prüfen bei jedem Durchlauf.
 

Fu3L

Top Contributor
Java:
public class Game implements Runnable {
	
	boolean left;
	boolean gameIsRunning = true;
	
	public Game() {
		Thread t = new Thread(this);
		t.start();
	}
	
	@Override
	public void run() {
		while(gameIsRunning) {
			if(left) {
				player.moveX(-1);
			}

         repaint();
			
			try {
				Thread.sleep(50);
			} catch(InterruptedException ex) {
				//Sollte hier nicht passieren
				ex.printStackTrace();
			}
			
		}
	}

}

Das wäre jezz mal ein nicht funktionierendes Beispiel^^
Könntest die Klasse dann von JFrame ableiten und den KeyListener einbauen und damit die Variablen manipulieren und im Update-Loop halt deine Spieler-bewegen-methode aufrufen.
 

fl_ex

Bekanntes Mitglied
Super Klasse! :)
Danke dir, funktioniert jetzt! ;)

hier nochmal der "End-Code"

Main:
Java:
/**
package main;

import java.awt.event.KeyEvent;

/**
 * 
 */
public class Main {

	static boolean right = false;
	static boolean left = false;

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		final Player player = new Player("Y:\\player.png");
		final Player kasten = new Player("Y:\\kasten.png");
		Game window = new Game(player);
		World world = new World("Y:\\bg.jpg");

		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.setSize(500, 500);
		window.add(world);

		world.setLayout(null);

		window.setVisible(true);
		window.setSize(window.getPreferredSize());
		window.setLocationRelativeTo(null);

		world.add(player);
		world.add(kasten);
		player.setLocation(50, 10);
		kasten.setLocation(400, 200);

		window.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {

			}

			@Override
			public void keyReleased(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_LEFT) {
					left = false;
				}
				if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
					right = false;
				}
			}

			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_LEFT) {
					left = true;
					right = false;
				}
				if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
					right = true;
					left = false;
				}
			}
		});
	}
}

Game:
Java:
/**
 * 
 */
package main;

import javax.swing.JFrame;

import classes.Player;

/**
 * @author Felix-André Böttger
 * 
 */

@SuppressWarnings("serial")
public class Game extends JFrame implements Runnable {
	boolean gameIsRunning = true;
	Player player;

	public Game(final Player player) {
		Thread t = new Thread(this);
		t.start();
		this.player = player;
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	public void run() {
		while (gameIsRunning) {

			if (Main.right == true) {
				player.moveX(10);
			}
			if (Main.left== true) {
				player.moveX(-10);
			}

			repaint();

			try {
				Thread.sleep(50);
			} catch (InterruptedException ex) {
				// Sollte hier nicht passieren
				ex.printStackTrace();
			}

		}
	}
}

Player:
Java:
/**
package classes;

import java.awt.Dimension;

/**
 * @author Felix-André Böttger
 * 
 */
@SuppressWarnings("serial")
public class Player extends JLabel {

	private Image img;

	public Player(String img) {
		this(new ImageIcon(img).getImage());
	}

	public Player(Image img) {
		this.img = img;
		Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
		setPreferredSize(size);
		setMinimumSize(size);
		setMaximumSize(size);
		setSize(size);
		setLayout(null);
	}

	public void paintComponent(Graphics g) {
		g.drawImage(img, 0, 0, null);
	}

	public void moveX(final int move) {
		this.setLocation(getX() + move, getY());
		System.out.println("Move!");
	}

}

Jetzt komm ich weiter! ;)
 

Fu3L

Top Contributor
Java:
t.start();
        this.player = player;

Das würde ich umdrehen. Also erst den Spieler der Variablen zuweisen und dann den Thread starten, weil du im Thread auf die Variable player zugreifst. Könnte vllt eine NullPointerException geben, wenn du Pech hast^^

Ich persönlich würde die beiden Klassen Game und Main in eine zusammenfassen, aber das ist denke ich Geschmackssache^^
Außerdem würde ich für left und right getter-Methoden empfehlen.. Bei den beiden wird sich die Implementierung wohl so schnell nicht ändern, aber generell sollte man die Felder anderer Klassen nicht direkt aufrufen ;) Dafür müsste "Game" natürlich noch mit this die Referenz zu Main übergeben werden.
 

Ähnliche Java Themen

Neue Themen


Oben