Du bist nicht angemeldet.

niklas319

Schüler

  • »niklas319« ist der Autor dieses Themas

Beiträge: 103

Registrierungsdatum: 07.08.2011

Wohnort: Rheinland-Pfalz

Danksagungen: 10

  • Private Nachricht senden

1

03.10.2012, 15:04

Grafik mit Tasten bewegen

Heyho,

ich habe auf die schnelle mal ein Programm in Java gebastelt womit man ein Objekt bzw. eine Grafik mit den WASD Tasten bewegen kann.
Nur habe ich ein Problem, wenn 2 Tasten gedrückt werden. Das seitliche hochlaufen mit W & A un den anderen Kombinationen klappt schon.

Laufe ich eine Zeit nach links, drücke gleichzeitig w läuft die grafik nach links oben.
Lasse ich nun w los bleibt die Grafik stehen :(
Lasse ich stattdessen a los, läuft die Grafik so wie es sein soll weiter nach oben.

Ich benutze das Interface "KeyListener" um Tastatureingaben abzufangen.
Das Problem ist, wenn ich mich nach links bewege mit a ist a die aktive Taste. Drücke ich gleichzeitig noch w ist w die aktive Taste.
Somit geht der Tastendruck von a verloren und die Grafik bewegt sich nicht mehr, wenn ich w loslasse, da w die aktive Taste war.

Das ganze tritt nicht nur bei dem seitlichen hochlaufen nach Links Oben auf sondern in alle Richtungen :(


Habt ihr da einen Vorschlag wie man das beheben kann?
Gerne auch ein paar Vorschläge und den Code zu verbessern. Ich wollte das ganze nur mal schnell testen und ihn dann auslagern & verbessern.

Quellcode habe ich als Datei angehängt.

Vielen Dank.
Niklas
»niklas319« hat folgende Datei angehängt:
  • player.zip (2,13 kB - 408 mal heruntergeladen - zuletzt: Heute, 04:19)

liro

Fortgeschrittener

Beiträge: 180

Danksagungen: 36

  • Private Nachricht senden

2

03.10.2012, 15:56

Was mir einfallen würde ist, dass nicht dauernd repainted wird. Sondern nur bei nem Tastendruck?

Zitat

void keyPressed(KeyEvent e)
Invoked when a key has been pressed.

void keyReleased(KeyEvent e)
Invoked when a key has been released.

Java-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override 
public void keyPressed(KeyEvent e) 
{ 
this.getPlayer().keyPressed(e.getKeyCode()); 
this.repaint(); 
} 

@Override

public void keyReleased(KeyEvent e)

{

this.getPlayer().keyReleased(e.getKeyCode());

this.repaint();

}

Es hat sich bereits 1 registrierter Benutzer bedankt.

Benutzer, die sich für diesen Beitrag bedankt haben:

niklas319 (03.10.2012)

niklas319

Schüler

  • »niklas319« ist der Autor dieses Themas

Beiträge: 103

Registrierungsdatum: 07.08.2011

Wohnort: Rheinland-Pfalz

Danksagungen: 10

  • Private Nachricht senden

3

03.10.2012, 16:18

Stimmt, eigentlich brauche ich ja nichts zu machen, wenn eine Taste losgelassen wird ;)
Dann kann ich auch die Zeile "this.move()" in der keyReleased methode löschen :)

liro

Fortgeschrittener

Beiträge: 180

Danksagungen: 36

  • Private Nachricht senden

4

04.10.2012, 16:04

eigentlich meinte ich, dass es eben _nur_ dann neu gezeichnet wird, wenn man eine Taste runter drückt. Aber halt nicht wenn eine Bewegung aktiv ist.
Ich finde,dass passives Rendering eh nicht für Spiele geeignet ist.

far

Schüler

Beiträge: 57

Registrierungsdatum: 28.12.2011

Danksagungen: 14

  • Private Nachricht senden

5

04.10.2012, 16:55

eigentlich meinte ich, dass es eben _nur_ dann neu gezeichnet wird, wenn man eine Taste runter drückt. Aber halt nicht wenn eine Bewegung aktiv ist.
Vielleicht verstehe ich dich falsch, aber wie willst du denn bitte eine aktive Bewegung graphisch darstellen ohne neu zu zeichnen?


Niklas, ich weiß nicht ob dein Problem inzwischen gelöst ist, aber ich sag dir mal wie ich vorgehen würde.
Bei einem Spiel-artigen Programm brauchst du i. d. R. eine Endlosschleife, die nach jedem Durchlauf eine gewisse Zeit wartet (z. B. 50 ms) und bei jedem Durchlauf neu zeichnet sowie alle anderen das Spiel betreffenden Dinge tut. Dann kannst du in der Player-Klasse eine x- und eine y-Geschwindigkeit definieren, aufgrund derer dein Bild immer verschoben wird.
Ich hab mal die relevanten Teile kurz aufgeschrieben:

Java-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public class Player {	

	public static int x_pos = 100;
	public static int y_pos = 50;

	public static int x_speed = 0;
	public static int y_speed = 0;

	public static void move()
	{
		x_pos += x_speed;
		y_pos += y_speed;
	}
}

public class Main {

	while (running)	
	{					
		repaint();
    	Player.move();
    	thread.sleep(30);
	}

	public void paint (Graphics g) {

    	g.drawImage(Player.img, Player.x_pos, Player.y_pos, this);
	}

	public void keyPressed(KeyEvent e) {

    	if (e.getKeyCode() == KeyEvent.VK_W )
		{ y_speed = -2; }

    	if (e.getKeyCode() == KeyEvent.VK_A )
		{ x_speed = -2; }

    	if (e.getKeyCode() == KeyEvent.VK_S )
		{ y_speed = 2; }

    	if (e.getKeyCode() == KeyEvent.VK_D )
		{ x_speed = 2; }        	
	}

	public void keyPressed(KeyEvent e) {

    	if (e.getKeyCode() == KeyEvent.VK_W )
		{
        	if (y_speed == -2) { y_speed = 0; }
    	}

    	if (e.getKeyCode() == KeyEvent.VK_A )
		{
        	if (x_speed == -2) { x_speed = 0; }
    	}

    	if (e.getKeyCode() == KeyEvent.VK_S )
		{
        	if (y_speed == 2) { y_speed = 0; }
    	}

    	if (e.getKeyCode() == KeyEvent.VK_D )
		{
        	if (x_speed == 2) { x_speed = 0; }
    	}
        	
	}
}


So würde ich es machen, ist natürlich ein bisschen anders, weil ich mit Java nur Applets programmiere und auch ansonsten relativ low-level-mäßig, aber ich denke da hast du dir z. B. die ganzen Funktionen in der Player-Klasse gespart, das sind echt übertrieben viele finde ich.
Wer mich korrigieren mag, bitte gerne :)
lg
Support LibreOffice !

liro

Fortgeschrittener

Beiträge: 180

Danksagungen: 36

  • Private Nachricht senden

6

04.10.2012, 17:31

Ich meinte, dass beim runter Drücken der Taste neu gezeichnet wird (repaint in keyPressed), aber nicht in einer Schleife (die nötig ist bei Animationen).

niklas319

Schüler

  • »niklas319« ist der Autor dieses Themas

Beiträge: 103

Registrierungsdatum: 07.08.2011

Wohnort: Rheinland-Pfalz

Danksagungen: 10

  • Private Nachricht senden

7

04.10.2012, 20:20

Das Problem habe ich immer noch nicht gelöst.

Ich habe das ganze auch mal mit einem Thread probiert und mit einer Endlosschleife und einem Sleeper. Das ganze ging ganz gut nur ruckelte es anfangs, wenn man eine Taste drückt. Drückt man 2 sprang der Player regelmäßig von Position zu Position.
Ich schau mir das mit dem Thread morgen nochmal an.

Habt ihr sonst noch eine andere Möglichkeit?

far

Schüler

Beiträge: 57

Registrierungsdatum: 28.12.2011

Danksagungen: 14

  • Private Nachricht senden

8

05.10.2012, 12:49

Wenn deine Graphik wie bei Mario/Pacman/alle-anderen-Spiele sich hin- und herbewegen soll, ohne dass sie immer ausschließlich bei einem Tastendruck verschoben wird, also du eine flüssige Bewegung darstellen willst, brauchst du nunmal eine Schleife. Geht nicht anders :)
Wie ich finde ausgezeichnetes Tutorial zum Einstieg in Java-Spieleprogrammierung: http://www.javacooperation.gmxhome.de/TutorialStartDeu.html
Support LibreOffice !

niklas319

Schüler

  • »niklas319« ist der Autor dieses Themas

Beiträge: 103

Registrierungsdatum: 07.08.2011

Wohnort: Rheinland-Pfalz

Danksagungen: 10

  • Private Nachricht senden

9

05.10.2012, 14:42

Das ist klar, aber der Spieler soll sich bei mir ja nur über die Tasten bewegen.

liro

Fortgeschrittener

Beiträge: 180

Danksagungen: 36

  • Private Nachricht senden

10

05.10.2012, 14:55

ja, aber die Tastaturevents werden nur sehr unregelmäßig ausgelöst, was du schon selbst beobachtet hast. Du benutzt ja schon Flags für die Laufrichtungen. Jetzt muss du nur noch (in einer Schleife) gucken welche Flags gesetzt sind und je nach dem die Animation/Bewegung durchführen.

far

Schüler

Beiträge: 57

Registrierungsdatum: 28.12.2011

Danksagungen: 14

  • Private Nachricht senden

11

05.10.2012, 15:24

Das ist klar, aber der Spieler soll sich bei mir ja nur über die Tasten bewegen.
Um mal liros Beitrag zu ergänzen:
Wenn du dir mal alle verfügbaren key-events ansiehst, siehst du das Problem. Es gibt keyTyped (Taste gedrückt und wieder losgelassen), keyPressed (Taste gedrückt) und keyReleased (Taste losgelassen). Sagen wir du drückst die D-Taste und willst, dass deine Graphik sich nach rechts bewegt. Es wird keyPressed ausgelöst, weil du die Taste gedrückt hast. keyPressed wird aber wohlgemerkt nur einmal ausgeführt, nämlich dann, wenn du die Taste runtergedrückt hast. Lässt du sie wieder los, werden die anderen beiden ausgeführt. Das heißt du kannst natürlich auf eine Schleife verzichten und in der keyPressed-Funktion dein Graphik verschieben (sagen wir um 5 Bildpunkte). Dann wird sie aber bei jedem Druck auf die D-Taste nur einmal verschoben und zwar um deine angegebenen 5 Bildpunkte. Damit kriegst du also keine flüssige Bewegung hin. Wenn du natürlich um deine Graphik um 100 nach rechts zu verschieben 20 mal die D-Taste drücken willst - warum nicht. Wenn du sie aber einmal drücken willst und deine Graphik soll sich mit konstanter Geschwindigkeit nach rechts bewegen bis du sie wieder loslässt, DANN brauchst du eine Schleife.
Support LibreOffice !

Es hat sich bereits 1 registrierter Benutzer bedankt.

Benutzer, die sich für diesen Beitrag bedankt haben:

Erik (05.10.2012)

Erik

Profi

Beiträge: 1 274

Registrierungsdatum: 22.06.2011

Wohnort: Deutschland ;)

Danksagungen: 307

  • Private Nachricht senden

12

05.10.2012, 22:38

wo er recht hat... :D

und wenn man schon alles andere in einer schleife rendert, warum dann für den spieler noch ne eigene? würde wahrscheinlich eh beides gleich oft gerendert werden müssen, zumal die UPS rate leicht höher sein kann als die FPS, andersrum aber net unbedingt... und wie gesagt, man soll ja net auf der taste rumhämmern sollen :D auf key pressed/released events reagieren, velocity anpassen und alles in ne delta-loop schmeißen sollte eig ganz gut funktionieren...

PS.:

Zitat

die nach jedem Durchlauf eine gewisse Zeit wartet (z. B. 50 ms)

naja... so einfach ist das dann auch wieder nicht :D aber vom prinzip her ja...

hier ein richtig gutes tutorial dazu: http://fivedots.coe.psu.ac.th/~ad/jg/
ist es echt wert zu lesen ;D
Beste Webite im Internet ( ͡° ͜ʖ ͡°)
xinra.de

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Erik« (05.10.2012, 22:43)


Es haben sich bereits 2 registrierte Benutzer bedankt.

Benutzer, die sich für diesen Beitrag bedankt haben:

far (06.10.2012), Johannes S. (06.10.2012)

niklas319

Schüler

  • »niklas319« ist der Autor dieses Themas

Beiträge: 103

Registrierungsdatum: 07.08.2011

Wohnort: Rheinland-Pfalz

Danksagungen: 10

  • Private Nachricht senden

13

06.10.2012, 13:34

Vielen Dank für das Tutorial Erik ich werde mir das im laufe der Tage anschauen.

Aber bei keyPressed bin ich anderer Meinung, die Funktion wird auch getriggert, wenn man eine Taste z.B. D gedrückt hält.
Die keyReleased Methode wird allerdings nur 1x getriggert, selbst wenn man eine Taste z.B. D gedrückt hält (was ja auch logisch ist).

In meinem oben beschriebenen Fall sind die Booleans in der Klasse auch noch alle richtig gesetzt. Sprich der boolean für das nach links laufen ist noch auf true. Lässt man a los wird die keyReleased methode aufgerufen und das links laufen wird auf false gesetzt. Das Problem ist das die gedrückte a taste nicht getriggert wird und meine move methode nicht aufgerufen wird :(
Erst wenn ich die Taste los lasse(boolean auf false gesetzt wird) und wieder drücke wird die keyPressed methode aufgerufen und somit meine move methode die auch letzendlich die koordinaten für den Spieler neu setzt.

far

Schüler

Beiträge: 57

Registrierungsdatum: 28.12.2011

Danksagungen: 14

  • Private Nachricht senden

14

06.10.2012, 20:03

hier ein richtig gutes tutorial dazu: http://fivedots.coe.psu.ac.th/~ad/jg/
ist es echt wert zu lesen ;D
Das kenne ich, ist wirklich genial :D Aber für Niklas' Zwecke wohl zu krass ^^

Niklas:

Zitat

Aber bei keyPressed bin ich anderer Meinung, die Funktion wird auch getriggert, wenn man eine Taste z.B. D gedrückt hält.
Stimmt, hab's nochmal nachgeguckt - ist ja quasi wie wenn man bei einem Textverarbeitungsprogramm einen Buchstaben gedrückt hält. Für ein Spiel ist das aber trotzdem ungeeignet, weil man nicht kontrollieren kann, in welchen Abständen das keyEvent ausgelöst wird. Du merkst ja auch selbst, dass beim Drücken einer Taste die Graphik erst einmal bewegt wird, dann kurz aussetzt und sich dann weiterbewegt.

Ich hab deinen Quelltext jetzt mal ausführlich ausprobiert und weiß jetzt auch was du meinst. Wenn ich z. B. S drücke, dann A und dann A wieder loslasse, bewegt sich die Graphik nicht weiter nach unten, wie sie es sollte (was du ja in deinem Eröffnungspost beschrieben hast). Das liegt daran, dass das keyEvent dann einfach nicht mehr ausgelöst wird. Das ist m. E. eine keyEvent-spezifisches Problem (man könnte sagen Bug), welches schätze ich keinen interessiert, weil die Situation praktisch nie auftritt. Ich wüsste auch keinen Workaround dazu.

Es sei denn, man macht es gleich richtig und baut eine Schleife ein (die man sowieso braucht). Das hab ich jetzt mal bei deinem Quelltext kurzerhand gemacht - läuft wunderbar, auch ohne diese komischen Verzögerungen. Die von mir angepasste Version hab ich unten angehängt.

Btw, ich finde man kann es mit Objektorientierung auch übertreiben - diese Mini-Funktionen in deiner Player-Class finde ich ja sowas von unnötig. Aber ist wohl Geschmackssache. Der Quelltext ist jetzt jedenfalls deutlich kürzer - man könnte ihn nochmal halbieren ^^
»far« hat folgende Datei angehängt:
Support LibreOffice !

Es hat sich bereits 1 registrierter Benutzer bedankt.

Benutzer, die sich für diesen Beitrag bedankt haben:

niklas319 (06.10.2012)

niklas319

Schüler

  • »niklas319« ist der Autor dieses Themas

Beiträge: 103

Registrierungsdatum: 07.08.2011

Wohnort: Rheinland-Pfalz

Danksagungen: 10

  • Private Nachricht senden

15

06.10.2012, 21:22

Zitat von »Erik«
hier ein richtig gutes tutorial dazu: http://fivedots.coe.psu.ac.th/~ad/jg/
ist es echt wert zu lesen ;D

Das kenne ich, ist wirklich genial :D Aber für Niklas' Zwecke wohl zu krass ^^


Würde ich nicht sagen, ich möchte ja im Endeffekt ein 2d Spiel machen ;) Dort findet sich bestimmt das ein oder andere was nützlich sein wird.


Dein Projekt schaue ich mir mal morgen an, da bei mir im Moment alles sehr chaotisch ist.
Ich bedank mich schon mal im Vorraus ;)

Johannes S.

Fortgeschrittener

Beiträge: 444

Registrierungsdatum: 24.06.2011

Wohnort: Lychen

Danksagungen: 71

  • Private Nachricht senden

16

06.10.2012, 23:22

Die beiden Probleme die du beschreibst, sind keine Fehler. Würde ich zumindest sagen. Wenn du einfach mal in einen Editor gehst und S getrückt hälst, wird erst nur ein "S" geschrieben, dann gibt es eine Wartezeit und dann kommen erst die weiteren "S". Wenn ich nun zusätzlich noch "A" drücke werden ab sofort "A"-Buchstaben geschrieben und wenn ich nun A loslasse werden ja auch keine weiteren "S" geschrieben.
Da du das Spiel zuvor auf der Geundlage der Events, die auch für diese Funktionen zu ständig sind, geschrieben hast, waren diese "Fehler" nunmal auch unvermeidbar. Bei solchen Spielen kommt man einfach nicht an Schleifen vorbei. Außerdem bieten dir richtige Schleifen auch andere Vorteile. Z.B. ermöglichen sie Animationen.
Signatur ?

Erik

Profi

Beiträge: 1 274

Registrierungsdatum: 22.06.2011

Wohnort: Deutschland ;)

Danksagungen: 307

  • Private Nachricht senden

17

07.10.2012, 20:19

@fukar wenn du mit minifunktionen die getter und setter meinst, das ist doch normal? also public instanz-variablen würde ich fast nir benutzen, außer bei ganz ganz simplen utilities, wo sich das sonst net lohnt, da das fast schon primitive datentypen sind, bzw sowas wie structs, die sonst keine funktionen haben...

@niklas, das geht da nicht nur um 3d programmierung, das kommt erst später... es geht viel um allgemeine konzepte in der spieleprogrammierung mit java, wie zum beispiel die delta-loop, verschiedene timer-klassen... das beispiel ist da am anfang ja auch ein 2d spiel... gibts auch super viel hintergrund wissen und so, ist echt nice... ist nur blöd, dass man sich irgendwie jedes kapitel einzeln runterladen muss xD

vielleicht kann man einfach eine etwas direktere methode benutzen, um die inputs zu verarbeiten, als die awt keyevents?
Beste Webite im Internet ( ͡° ͜ʖ ͡°)
xinra.de

niklas319

Schüler

  • »niklas319« ist der Autor dieses Themas

Beiträge: 103

Registrierungsdatum: 07.08.2011

Wohnort: Rheinland-Pfalz

Danksagungen: 10

  • Private Nachricht senden

18

07.10.2012, 20:34

@niklas, das geht da nicht nur um 3d programmierung, das kommt erst später... es geht viel um allgemeine konzepte in der spieleprogrammierung mit java, wie zum beispiel die delta-loop, verschiedene timer-klassen... das beispiel ist da am anfang ja auch ein 2d spiel... gibts auch super viel hintergrund wissen und so, ist echt nice... ist nur blöd, dass man sich irgendwie jedes kapitel einzeln runterladen muss xD


Japp ich habs mir mal angeschaut ist echt genial was er da alles erklärt nur bin ich meistens zu Faul das alles zu lesen :(

vielleicht kann man einfach eine etwas direktere methode benutzen, um die inputs zu verarbeiten, als die awt keyevents?


Ich wüsste nicht wie. Du musst dem JFrame ja auch sagen, das er einen Adapter dafür hat. Mir wurde da nur der KeyListener angezeigt.

KeyAdapter
Vielleicht hilft das ja weiter, habe ich mir allerdings noch nicht angeschaut.

liro

Fortgeschrittener

Beiträge: 180

Danksagungen: 36

  • Private Nachricht senden

19

07.10.2012, 22:13

Der KeyAdapter ist doch nur eine Implementierung des KeyListener-Interfaces, dieses wird dann verwendet, wenn man nicht alle Methoden des Intrerfaces selbst implementieren möchte. Ist also nichts anderes als, wenn du das Intreface direkt verwendest.

far

Schüler

Beiträge: 57

Registrierungsdatum: 28.12.2011

Danksagungen: 14

  • Private Nachricht senden

20

07.10.2012, 23:41

@fukar wenn du mit minifunktionen die getter und setter meinst, das ist doch normal? also public instanz-variablen würde ich fast nir benutzen, außer bei ganz ganz simplen utilities, wo sich das sonst net lohnt, da das fast schon primitive datentypen sind, bzw sowas wie structs, die sonst keine funktionen haben...
Ja leider, das stört mich auch immer wieder an Java ^^
Aber man kann ja diesen setter/getter-Schrott möglichst gering halten. Ich zeig dir mal seinen Code (204 Zeilen) und den von mir geupdateten (106 Zeilen), der hat sich mal eben halbiert. Und dabei hab ich noch versucht möglichst viel zu belassen wie es ist (Dateien sind angehängt).

Java-Quelltext

1
2
3
4
private void updateTop()
{
		this.setY(this.getY() - this.PIXEL_MOVE_PER_STEP);
}

Da sind drei Funktionen verwendet, wo ein einziges

Java-Quelltext

1
y -= 3;
gereicht hätte - dafür mach ich doch nicht eine Funktion, die dann auch noch innerhalb der Klasse die jeweiligen setter/getter aufruft?! Nur ein Beispiel.
»far« hat folgende Dateien angehängt:
Support LibreOffice !

Ähnliche Themen

Verwendete Tags

2D, Grafik, Java, KeyListener, Objekt, Spiel, Tastatur