Computerhilfen.de Logo
Forum
Tipps
News
Frage stellen

Java Applet "Ping-Pong"<<Problem im Anfangsstadium mit KeyListener und Thread>&a

Hi.
Ich als Java-Einsteiger hab mir gleich n großes Projekt vorgenommen, an dem ich etwas tüfteln kann, um mich in die Programmiersprache Java einzuarbeiten.

Mein Ziel ist ein Ping-Pong-Spiel. ;D

Wenns fertig is, solls nen Start-Button, nen Punktezähler und natürlich das Ping-Pong an sich haben.

Im Moment bin ich erst soweit, dass eine Spielfläche geschaffen wird (fillRect  ;) ) und darin einer der 'Blocker' ist.
Dieser lässt sich leider nich bewegen :(
 
Zwischenziel ist also, den einen Blocker mit den Pfeiltasten bewegen zu können!



Hier ein Foto vom aktuellen Stand:

 



 Erklärung des Listings:
Zuerst werden Variablen und der Hintergrund erstellt und mit der Funktion "blocker()" der erste Blocker, welcher leider anscheinend wegen einem Fehler nicht bewegbar ist, eingefügt.
Darauf folgt der KeyListener, der die Pfeiltasten hoch und runter überwacht und bei Drücken einen Thread startet, der zur bewegung führen soll, bei Loslassen diesen Thread wieder beendet.
Im Thread wird jeweils mit der blocker(); -Funktion das schwarze Rechteck, welches den Blocker darstellt erst mit gelb überzeichnet(Farbe des Hintergrundes) und dann an neuer Position mit schwarz neu gezeichnet.

Im folgenden das Listing:


import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;


public class Mehrere extends Applet  implements KeyListener, Runnable{

Label L1=new Label("Position");
Thread move_ball=new Thread();
Thread move_blocker=new Thread();
Thread moveup=null;
Thread movedown=null;
int a=1;


public void init(){
add(L1);//L1.setLocation(50, 50);
L1.setBackground(Color.yellow);
this.setSize(500, 350);
this.addKeyListener(this);
}
public void paint(Graphics s){
s.setColor(Color.yellow);
s.fillRect(25, 25, 450, 300);
blocker(Color.black, 150);
}

void blocker(Color col, int pos){
Graphics s1;
s1=getGraphics();
s1.setColor(col);
s1.fillRect(450, pos, 10, 50);
}




public void KeyPressed(KeyEvent e){
if(e.getKeyCode()==KeyEvent.VK_UP){
if (moveup==null){L1.setText("Up");
moveup=new Thread();  a=-1; moveup.start();
}
}
if(e.getKeyCode()==KeyEvent.VK_DOWN){
if (movedown==null){L1.setText("Down");
movedown=new Thread();  a=1; movedown.start();
}
}
}
public void KeyReleased(KeyEvent ex){
if(ex.getKeyCode()==KeyEvent.VK_UP){L1.setText("xUp");
moveup.stop();
moveup=null;
}
if(ex.getKeyCode()==KeyEvent.VK_DOWN){L1.setText("xDown");
movedown.stop();
movedown=null;
}
}



public void run(){
int posblocker;
while ((moveup!=null) ^ (movedown!=null)){
try{
if((posblocker>25)&(posblocker<275)){
blocker(Color.yellow, posblocker);
posblocker=posblocker+a;
Thread.sleep(10);
blocker(Color.black, posblocker);
L1.setText(""+posblocker);
}
} catch(Exception e){}

}
}

}

 

Ich weiß, dass es Zeitaufwendig ist, das nun alles durchzuschauen. Es wäre aber trotzdem sehr nett, wenn sich jemand die Mühe machen könnte.

Nützlich für mich wäre, wenn mir jemand erklärt, was der Fehler ist, dass nichts passiert bei Tastendruck sowie evtl. Hinweise an manchen Stellen um meinen Stil zu verbessern.
Zudem möchte ich gern den Thread noch ausgliedern, also in eine eigene Klasse setzen, da ich ja noch mehr brauchen werde (für den Ball und die KI). Ich weiß jedoch nicht genau, wie ich das anstelle.



Vielen Dank an alle, die sich die Zeit genommen haben dies alles zu lesen!  :D
Ich freue mich auf eure Antworten.
Fragen dazu nehm ich gern entgegen. Wenn ihr wollt kann ich das Listing auch in anderer Form irgendwie online stellen..oder die *.java und *.class Dateien hochladen.

LG
Tobi
« Letzte Änderung: 18.12.06, 23:25:25 von SLik »

Antworten zu Java Applet "Ping-Pong"<<Problem im Anfangsstadium mit KeyListener und Thread>&a:

Hallo Tobi,
ich habe mir die Mühe gemacht und mal geschaut was Du fabriziert hast. Auf Anhieb würde ich sagen nicht schlecht aber:
In der Methode "public void run()" finde ich mehrere Sachen die zu Fehlern führen könnten.
1. Du initialisierst "posblocker" aber gibst ihm keinen Startwert mit, obwohl Du ihn drei Zeilen später in der Verknüpften "if-Anweisung" abfragst. Wenn ich mich nicht irre, solltest Du den Startwert auf 150 legen.
2. In der oben genannten "if-Anweisung" verknüpfst Du zwei Aussagen mit einem einfachen "&", welches für bitweises Vergleichen steht. Sehr wahrscheinlich sollten aber beide Ausdrücke im ganzen verglichen werden. Deshalb "&&"
3. Du solltest Dir die allgemeingültigen Coding-Konventionen aneignen. Das hilft anderen Leuten Deine Quellcodes schneller zu lesen und zu verstehen. Einfaches Mittel, wenn Du mit Eclipse arbeitest, dann lade Dir doch mal das PlugIn "CheckStyle" runter und baue es ein. Der gibt Dir rechtgenaue Meldungen, was er zu bemeckern hat.

Externe Klassen sind kein Problem. Hauptsache sie liegen im gleichen Verzeichnis. Du solltest dann Packages definieren. Wenn Du Dir wegen der Abhängigkeiten der Klassen nicht sicher bist, solltest Du beim Compilieren einfach alles auf einmal von javac oder jikes übernehmen lassen.: javac *.java
Wenn Du nun die Klasse Ball erstellt hast, dann erzeugst Du Dir im Applet einfach eine Instanz davon. Ball ball = new Ball(); Nun kannst Du auf alle öffentlichen Methoden zugreifen und den Ball steuern bzw. steuern lassen. Da der Ball sich bewegen soll, solltest Du entweder das Interface "Runnable" implementieren oder von Thread ableiten.

Ansonsten noch viel Erfolg

Vielen Dank für die Hilfe.

Ich hab das & nun durch && ersetzt und die int-variable posblocker mit dem Wert 150 initialisiert.
Jedoch funktioniert es noch immer nicht :(

Ich bin ratlos.. ???

eclipse gibt mir folgendes Fehler-Listing:

Exception in thread "AWT-EventQueue-1" java.lang.Error: Unresolved compilation problem:
The type Mehrere must implement the inherited abstract method KeyListener.keyPressed(KeyEvent)

at Mehrere.keyPressed(Mehrere.java:6)
at java.awt.Component.processKeyEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-1" java.lang.Error: Unresolved compilation problem:
The type Mehrere must implement the inherited abstract method KeyListener.keyReleased(KeyEvent)

at Mehrere.keyReleased(Mehrere.java:6)
at java.awt.Component.processKeyEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)


vllt hilft euch das mir zu helfen :)

Vielen Dank im voraus!
LG
Tobi
« Letzte Änderung: 19.12.06, 17:50:41 von SLik »

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button
keyPressed und keyReleased kleinschreiben...

Java ist case-sensetive, du musst die Methoden also genau so klein/groß schreiben wie es die Schnittstelle KeyListener vorgibt.
« Letzte Änderung: 20.12.06, 08:26:02 von mati »

Juhu..
nun funktioniert der KeyListener :)

Danke

Allerdings wird der Thread (public void run(){..}) torzt des x.start(); befehls nicht gestartet. :(
 ???

Weiß jemand vllt weshalb..?
LG
Tobi

Wird der Thread definitiv nicht gestartet, oder siehst Du nur nicht das gewünschte Ergebnis? Solltest Dir vielleicht mal im Thread eine ANweisung einbauen, die das deutlich macht.

Weiterhin viel Erfolg

Ja. ich hab ne Textausgabe als ersten Befehl des Threads zur überprüfung eingebaut.

Ah ..hab in nem Tutorial was gefunden und meinen Fehler behoben. :)

Der Thread läuft nun.
Weiteres dazu schreib ich heute Nachmittag^^

« Letzte Änderung: 20.12.06, 13:19:09 von SLik »

So.
Der erste Blocker ließ sich nun einwandfrei bewegen^^
(Betonung auf *ließ* :P)
Ich hab nu dem Thread eine eigene Klasse gegeben. Dann lief es auch noch super.
Dann hab ich mir gedacht, kann ich die dafür geschriebenen Funktionen ja auch einfach als void angeben und im Thread ausführen; dabei die nötigen Variablen übergeben.
Dann brauche ich die nicht für den 2. blocker genauso zu schreiben :)

Nun habe ich mich da durchgewühlt..Funktionen umgestellt, umstrukturiert..usw
Jetzt haberts aber daran, dass ich seltsamerweise mit meinem Befehl zum starten des Threads:
x.start();
keine Variablen übergeben kann:

The method start() in the type Thread is not applicable for the arguments (int)

Kann ich die Variablen irgendwie übergeben?
..andernfalls müsste ich einen eigenen Thread für die Anzeige des KI-Blockers schreiben, wo ich doch schon eine identische für den Spieler-Blocker habe :(

Vielen Dank im Voraus
LG
Tobi

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button
1 Leser hat sich bedankt

Wie ich das verstanden habe, willst du also ein und die selbe von Thread abgeleitete Klasse 2 mal benutzen.
Dazu erstellst du zwei Instanzen und lässt die quasi gleichzeitig loslaufen.

Wenn du das wirklich so machen willst, dann kannst du dieser von Thread abgeleiteten Klasse eine Eigenschaft vom Typ int verpassen.
Den Initialisierungswert von dieser Eigenschaft kannst du dann im Konstruktor dieser Klasse übergeben.
Aus run kannst du dann auf diese Eigenschaft zugreifen anstatt auf einen Übergabeparameter (du übergibst den Parameter also einfach schon bei der Erstellung des neuen Threads, nicht erst wenn du ihn loslaufen lässt).

« Letzte Änderung: 20.12.06, 20:23:11 von mati »

Danke für die Hilfe  :)

Ich hab leider nich mehr so viel Zeit. Ich werds am Wochenende testen. :)

So.
Hab nun mal ein ganzes Stück weitergemacht :)

Jetzt steht schon der KI-Blocker, die Ballbewegung funktioniert.
Ein einfaches hin und her funktioniert einwandfrei (solange man den KI-Blocker trifft ;) ).

Nun bin ich am überlegen wie ich die KI programmiere, sodass sie nicht zu stark, aber auch nicht zu schlecht ist.

Ich hab überlegt, ob ich die KI den Blocker einfach immer in Höhe des Balls halten lassen soll. Allerdings wäre dann schon bei geschwindindigkeitsstufe 2 Ende.

Dann hab ich überlegt, ob die KI nach dem blocken einfach immer zur mitte; sobald der Spieler blockt den Zielort des Balls berechnet und hinfährt. Aber ich befürchte, dass das dann zu schwer zu besiegen sein könnte.

Könnt ihr mir einen Tipp geben, wie es möglichst ausgeglichen ist?


Grüße
Tobi



Wenn ihr wollt stell ich auch den bisherigen Quellcode nochmal online. Er ist allerdings schon so lang^^ ..da wollt ich nicht, dass es abschreckend wirkt; evtl. nichts wegen der Länge gelesen bzw geantwortet wird :)

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Die KI soll ja einen Mensch simulieren...

von daher ist das schon OK, wenn die KI "abschätzt" wo der Ball hinkommen wird und den Schläger erst mal da hin bewegt.

Abschätzen kannst du simulieren, indem du zunächst berechnest, wo der Ball hinkommt, dabei aber nicht den wirklichen Winkel des Balls nimmst, sondern einen um einen Zufallswert leicht veränderten... dadurch wird die Berechnung nicht perfekt.

Wenn der Balls sehr nahe an den Schläger der KI kommt, kannst du dann machen, dass die KI die Position des Schlägers noch versucht zu korrigieren.

Jap.
Das hört sich gut an. :)

Ich werds mal testen.
Weiteres dazu stell ich innerhalb der nächsten Woche rein, sobald ich fertig bin bzw. ein Problem haben sollte, das ich allein nicht lösen kann.  ;)

Vielen Dank
Tobi


Das Programm ist nun größtenteils fertig. Fehlt nurnoch ein bisschen was zur benutzerfreundlichkeit.
zu testen ist es hier: >>Programm<<
der passende Quelltext steht hier: >>Quelltext<<

ihr seht gleich wo mein Problem liegt. Die Anzeige des KI-Blockers stimmt ganz und garnicht.

Ich finde alledings meinen fehler nicht. Mein Informatiklehrer meinte, ich müsse die  Threads synchronisieren, damit das reibungslos läuft.. wie das geht wusste er allerdings nicht^^


es wäre nett ein paar tipps dazu von euch zu bekommen :)


Vielen Dank
Tobi

Was mich etwas stört ist die hohe CPU-Auslastung bei dem ganzen.
Ich werde wohl die Blocker sowie den Ball durch Grafiken ersetzen anstatt sie immer neu zu zeichnen. Zudem muss ich mich da mal mit Prioritäten beschäftigen glaube ich.. welche Prozesse sind dabei wichtiger als andere?

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Das mit dem Threads synchronisieren trifft es denke ich noch nicht ganz.

Du darfst nur in einem Thread zeichnen... im EventDispatchingThread.

Immer wenn du irgendwas zeichnen willst, musst du das mit invokeLater aufrufen:

invokeLater Doku

Ausnahme: Du reagierst auf einen Tastendruck oder so... KeyListener-Events laufen automatisch im EventDispatchingThread ab. Daher funktionier das Zeichnen des menschlichen Spielers auch besser.

« Letzte Änderung: 27.01.07, 13:45:43 von mati »

« Java - Regular Expressions-ProblemJava Packages »
 

Schnelle Hilfe: Hier nach ähnlichen Fragen und passenden Tipps suchen!

Fremdwörter? Erklärungen im Lexikon!
Java
Java ist eine von der Firma SUN entwickelte Programmiersprache. Da Java unabhängig vom Betriebssystem läuft, kann ein einmal geschriebenes Programm auf allen Ja...

Javascript
JavaScript ist eine weit verbreitete Skriptsprache, die ursprünglich von Netscape für das DOM-Scripting für Webseiten entwickelt wurde. Sie hat sich seitde...

Standardgateway
Das Standardgateway dient in einem Netzwerk ist das Gerät, das als Vermittler den Datenverkehr zwischen dem lokalen Netzwerk (wie einem Heim- oder Büronetzwerk)...