KeyPressed

Michael...

Top Contributor
Wenn Du jetzt sauer bist deswegen kann ich das voll verstehen......

Du hast Dir echt eine Riesenmühe gemacht mit dem Programm da....

Mein Problem ist, ich verstehe 80-90% davon nicht!
keine Angst ich bin nicht sauer und viel Mühe hat es auch nicht gekostet, war ja nur ne Sache von ein paar Minuten

Grundvoraussetzung um das zu verstehen ist, dass man sich mit Threads etwas auskennt.
Vom Prinzip ist es ganz einfach. Es gibt einen Thread/Handlungsstrang der die Tastatur überwacht und entsprechend die boolean Flags setzt.
Parallel dazu läuft ein zweiter Thread/Handlungsstrang, der die Flags auswertet und entsprechende Manipulationen an der Position und Ausrichtung vornimmt.
Ist jetzt nicht MVC konform, aber sollte ja nur darstellen wie man mit Hilfe solcher Flags und zweier Threads kommunizieren und berechnen kann ohne sich gegenseitig zu blockieren.
 

Anto

Aktives Mitglied
2 Fragen dazu: Einerseits scheine ich ja, wenn ich das richtig sehe, nicht drumherumzukommen, dass die Klasse, die KeyPressed implementiert, auch Runnable implementiert, oder?

Genau das ist bei uns ja aber verboten, weil ich maximal ein Interface pro Klasse haben darf!

na ok die 2. frage geht da vielleicht doch etwas weit.....die besagten booleschen Variablen müssen auch wirklich in der Klasse mit dem Listener stehen, das ist unter keinen Umständen möglich dass die im model stehen oder?
 

Michael...

Top Contributor
2 Fragen dazu: Einerseits scheine ich ja, wenn ich das richtig sehe, nicht drumherumzukommen, dass die Klasse, die KeyPressed implementiert, auch Runnable implementiert, oder?
Nein, wird in meinem Fall nicht gemacht und bei Gossi nur um die Demo kompakter zu halten. Es gibt keinen Grund warum die Klasse den KeyListener implementiert ein Runnable sein sollte.
na ok die 2. frage geht da vielleicht doch etwas weit.....die besagten booleschen Variablen müssen auch wirklich in der Klasse mit dem Listener stehen, das ist unter keinen Umständen möglich dass die im model stehen oder?
Nein, in Deinem Fall würde ich Sie mit ins Model stecken, da das Model das zentrale Kommunikationsmittel über die Klassen und Threads hinweg ist.
 
Nein, in Deinem Fall würde ich Sie mit ins Model stecken, da das Model das zentrale Kommunikationsmittel über die Klassen und Threads hinweg ist.

Das muss man etwas anders sehen. Gemäß Single Responsibility Prinzip ist es nur Aufgabe des Models, die Spielelogik bereitszustellen. Es interessiert die Geschäftslogik nicht, ob irgendwelche Keys gedrückt werden und damit irgendwelche boolschen Werte. Darum hat das im Business Layer nichts zu suchen. Das Anfangen von Benutzereingaben ist beim MVC Aufgabe des Controlers und das Anzeigen der Spielfiguren Aufgabe der View. Es ist sehr wichtig, dieses zu beachten, da man sonst archtitekturelle Fehler macht, die später teuer werden.
 

Anto

Aktives Mitglied
Troll (ich hab so eine Ahnung dass ich weiß wer Du bist......), nach der Logik wäre meine Aufgabe aber schlicht nicht lösbar, bei mir müssen die Booleans ins Model.

Michael/Gossi: Wenn mein Thread aber doch nicht in der Listenerklasse sitzt, wie soll er dann an KeyPressed herankommen?
 
Troll (ich hab so eine Ahnung dass ich weiß wer Du bist......), nach der Logik wäre meine Aufgabe aber schlicht nicht lösbar, bei mir müssen die Booleans ins Model.

Das Model verliert dadurch seine Unabhängigkeit, weil es fest an eine Ausführung und Steuerung durch Tastatur gebunden wird. Das Model sollte aber überhaupt nicht wissen, wie es gesteuer wird. Darum gibt es ja den Controler als übergeordnete Zwischenschicht.
 

Anto

Aktives Mitglied
Ich habe einfach überall dasselbe Problem: Ich KANN da natürlich booleans einbauen und zum beispiel sagen: Bei dem und dem Keycode setze die up/down/right/left -Variable dieses oder jenes spielers auf true, wenn die taste losgelassen wird wieder zurück auf false.

Aber was soll mir das helfen? Ich kann doch dann immer noch nicht 2 Tasten gleichzeitig drücken.

Im Grunde suche ich doch nur die beiden Wunderzeilen, die mir das ermöglichen.
 
G

Gast2

Gast
Ich hab jetzt nicht den kompletten Thread gelesen, bin mir aber sicher dass das schon jemand gesagt hat:

Du brauchst 4 booleans pro Spieler (am besten im "Spieler" Objekt selbst). In der keyPressed setzt du den entsprechenden boolean auf true, in der keyReleased wieder auf false.
Ein separater Thread (deine GameLoop) schaut sich in jedem durchlauf die booleans an und bewegt den Spieler entsprechend. Wenn du 3 oder 4 Tasten gleichzeitig drückst sind bei dir halt 3 oder 4 booleans auf true gesetzt.
 

Sunchezz

Bekanntes Mitglied
Wenn du nirgendwo das Interface Runnable benutzen darfst, nimms doch im Gameloop (im seperaten Thread) als anonymes Objekt.

Java:
Thread gameloop = new Thread(new Runnable() {
  public void run() {
    while(gameIsRunning) {
      //TODO
    }
  }
)};
 

Anto

Aktives Mitglied
Wie gesag das mit den 4 booleans habe ich begriffen. Was ich nciht verstehe ist warum mein GameLoop dann plötzlich funktionieren soll
 

Anto

Aktives Mitglied
Moment langsam. Ich glaube ich habe so ganz langsam in Ansätzen das Problem begriffen. Das Problem ist dass meine Methode eigentlich während dem ganzen Spiel durchlaufen muss das aber nicht kann, richtig? und Run sorgt jetzt irgendwie auf wundersame Weise dafür dass sie das doch kann?
 

Sunchezz

Bekanntes Mitglied
Moment langsam. Ich glaube ich habe so ganz langsam in Ansätzen das Problem begriffen. Das Problem ist dass meine Methode eigentlich während dem ganzen Spiel durchlaufen muss das aber nicht kann, richtig? und Run sorgt jetzt irgendwie auf wundersame Weise dafür dass sie das doch kann?
Das hat nichts mit den zwei gleichzeitigen Tastenanschlägen zu tun!
Ich dachte das war dein Problem?
 

Anto

Aktives Mitglied
Ist das nicht dasselbe? Im Grunde muss doch die Methode, die checkt wie die booleans aussehen und entsprechend die Figuren versetzt während des ganzen Spiels laufen?

Und weil sie das nicht kann, bewegen meine Figuren sich nicht anständig parallel?
Ist das nicht der Grund?
 

Sunchezz

Bekanntes Mitglied
Also wenn dein Spiel nicht durchgängig läuft is sowieso was schiefgegangen^^

Aber mit dem ganz speziellen Problem der zwei Tastenanschläge hat das nichts zu tun.
Würde mich jetzt jedenfalls wundern. Wenn doch, würd ich gern mal den Code sehen^^


Ich unternehme mal einen gewagten versuch dir zu erklären warum es mit Booleans funktioniert:

fragst du jedesmal neu in der keyPressed() nach gedrückten Tasten ab, bekommst du IMMER nur eine Taste zurück (verrät dir auch der methoden Name)
Setzt du in einem boolean der zu der taste passt den wert true, speicherst du dir zwischen, das die taste immernoch gedrückt ist.
Somit weist du in der klasse der booleans zu jeder Zeit welche Taste(n) gedrückt sind/ist.

Wenn die taste losgelassen wird, erfärst du es in keyReleased (boolean auf false setzen)!
 

Michael...

Top Contributor
Wie gesag das mit den 4 booleans habe ich begriffen. Was ich nciht verstehe ist warum mein GameLoop dann plötzlich funktionieren soll
Weil hier zwei Threads/Abläufe laufen.
Threads sind in er Computertechnik ein Mittel um Prozesse "parallel" abarbeiten zu können. Ohne Threads könnten auf einem Computer keine zwei Programme gleichzeitig laufen. Ich könnte während ich diesen Text schreibe nicht nebenbei ein Video anschauen oder mein E-Mail Programm könnte nicht ständig überprüfen, ob neue E-Mails für mich eingegangen sind...
Anto hat gesagt.:
Ist das nicht dasselbe? Im Grunde muss doch die Methode, die checkt wie die booleans aussehen und entsprechend die Figuren versetzt während des ganzen Spiels laufen?

Und weil sie das nicht kann, bewegen meine Figuren sich nicht anständig parallel?
Ist das nicht der Grund?
Pauschal würde ich mal sagen: Ja
 

Sunchezz

Bekanntes Mitglied
Ist das nicht dasselbe? Im Grunde muss doch die Methode, die checkt wie die booleans aussehen und entsprechend die Figuren versetzt während des ganzen Spiels laufen?

Ok, damit wird langsam klar wo du hängst...
Hoff ich zumindest!

run()
bewirkt das nicht auf wundersame weise...
wohl eher "while(gameIsRunning)"

logisch muss die Methode die etwas überprüft in einem Spiel permanent laufen!
 

Anto

Aktives Mitglied
Ich habe aber keine Methode, wo etwas in der Art von "while game is running" drinsteht:

Ich setze einfach einmal mein Fenster mit allem was da so drauf ist und alles andere geschieht auf Tastendruck. Solange ich das fenster nicht wieder exe (habe ich noch nicht, ich habe noch kein Spielende) bleibt das Fenster ja bestehen, warum sollte ich da mehr tun als Tastendrücke fangen ?
 

Sunchezz

Bekanntes Mitglied
damit du zwei tastenanschläge gleichzeitig auswerten kannst...

Du erstellst einen Thread der immerwieder neu die Positionen für deine "figuren" setzt, sind die tastenbooleans auf false, bewegt sich auch nichts, hast also nen endlosschleife die nichts tut, aber sobald eine taste gedrückt wird (oder mehrere), kann das durch die dauerlaufende positions berechnung gleichzeitig verarbeitet werden.

warum du dafür nen Thread brauchst?
Damit die Schleife nicht das GUI, und den gesamten Programmablauf blockiert.
 

Anto

Aktives Mitglied
Ok, ich beginne zu verstehen, aber ich beginne gerade erst.

Muss dieser Thread denn dann mein ganzes Spiel steuern oder kann ich den einfach irgendwo hinschreiben?

Also ich erzeuge irgendwo einen Thread der eine Schleife macht die ich erst noch schreiben muss?
 

Anto

Aktives Mitglied
Vielleicht, um die Frage mal etwas klarer zu machen:

WO muss dieser Thread hin?
Ins Model?

WAS muss diesem Thread alles übergeben werden?

Wenn der Thread nicht in der Klasse steht, die Runnable implementiert, WOHER weiß er dann wass er alles kann?
 
G

Gast2

Gast
WO muss dieser Thread hin?
Ins Model?
Das wär so zimelich der letzte Platz wo ich den ansiedeln würde. Entweder in den Controller oder als extra Klasse auslagern.

WAS muss diesem Thread alles übergeben werden?
Alles was er braucht. Ich kenne deinen Code nicht, aber zumindest das Model und den Controller sollte der kennen.

Wenn der Thread nicht in der Klasse steht, die Runnable implementiert, WOHER weiß er dann wass er alles kann?
Öhm, was?
Ein Thread arbeitet ein Runnable Objekt ab. Mehr nicht. Alles was der Thread machen soll steht in der run() Methode von deinem Runnable. In deinem Fall würde die run() Methode irgendwie so aussehen:
Java:
public void run()
  while (gameIsRunning) {
    // process the game
  }
}
 

Anto

Aktives Mitglied
Aber ich darf doch nichts haben was das Model UND den Controller kennt!

Es gibt nur M, C und V, zu irgendeinem von den dreien muss er gehören!

Woher weiß ich denn, was mein Thread alles braucht?

Gibt es da irgendwelche Richtlinien?
 

Michael...

Top Contributor
WO muss dieser Thread hin?
Wo dieser Thread hin muss ist prinzipiell egal, das ist eine Designfrage, die Du mit Deinem Gewissen und dem Benoter der Aufgabe ausmachen musst.
Ich würde vermutlich den Thread als Unterkomponent des Controllers platzieren, man kann ihn theoretisch aber auch direkt ins Model stecken. Allerdings sollte man bedenken, dass darin Spielelogik abgebildet wird.

Viel wichtiger ist was der Thread macht und worauf er Zugriff benötigt:
- die boolean Flags
- Position der Spieler
- ...
also auf die Daten des Models, nicht mehr und nicht weniger.
Und er macht nichts anderes ausser die Flags auszuwerten und dem entsprechend die Daten des Models zu manipulieren.
 

Anto

Aktives Mitglied
Wenn er in erster Linie die Modeldaten braucht, ist er dann nicht Teil des models? Und wenn ich ihn stattdessen in den Controller packe und ihm stattdessen das Model übergebe (das ginge ja, in der Main), wie kann ich das wenn der Controller doch den Listener implementiert und daher nicht auch noch Runnable implementieren darf? Oder kann ich dafür eine neue Controllerklasse anlegen?
 

bERt0r

Top Contributor
Ich hab jetzt nicht die ganzen 4 Seiten Posts gelesen, aber einen Thread der die Positionen von Spielfiguren bestimmt würde ich als Controller einordnen.
Und eine Klasse kann ohne Probleme mehr als ein Interface implementieren.
 

Michael...

Top Contributor
Wenn er in erster Linie die Modeldaten braucht, ist er dann nicht Teil des models?
Gegenfrage: Die View benötigt ebenfalls in erster Linie die Modeldaten, daher könnte man sie doch ebenfalls als Teil des Models definieren?
Programmiertechnisch ist alles möglich, warum man etwas so oder so macht ist eine Designfrage und hier haben sich MVC und ähnliche Entwurfsmuster bewährt, da man hierbei leicht einzelne Komponenten austauschen kann ohne in die restlichen Komponenten eingreifen zu müssen.
Wenn man Spielelogik und Model mischen möchte darf man das. Man darf sich dann aber nicht wundern wenn man bei Änderungen am Model die Spielelogik anpassen muss und umgekehrt.
Und wenn ich ihn stattdessen in den Controller packe und ihm stattdessen das Model übergebe (das ginge ja, in der Main), wie kann ich das wenn der Controller doch den Listener implementiert und daher nicht auch noch Runnable implementieren darf? Oder kann ich dafür eine neue Controllerklasse anlegen?
Man muss ihn ja nicht direkt in den Controller packen, man kann ihn ja als Subkomponente halten. So wie der Controller Model und View steuert, könnte er noch als weiter Komponenten einen Thread in Form einer Gameloop steuern.
 

Michael...

Top Contributor
KANN sie schon aber darf sie bei uns nicht.
Um das nochmal klar zustellen. Der Controller muss dazu nicht das Runnable Interface implementieren. (Sollte er m.M. auch nicht unbedingt). Er kann genauso gut eine Referenz auf ein Objekt halten, welches dieses Interface implementiert.

####EDIT####
Zur Erläuterung was ich meine:
Java:
public class MVCTDemo {
	class Model{
		//...
	}
	
	class View {
		public View(Model model) {
			//..
		}
	}
	
	class GameLoop implements Runnable {
		public GameLoop(Model model) {
			//..
		}

		public void run() {
			//..
		}
	}
	

	class Controller {
		public Controller() {
			Model model = new Model();
			View view = new View(model);
			GameLoop loop = new GameLoop(model);
			//..
			new Thread(loop).start();
		}
	}
	
	public static void main(String[] s) {
		new MVCTDemo().new Controller();
	}
}
 
Zuletzt bearbeitet:

Anto

Aktives Mitglied
Also eine weitere Controllerklasse, die Runnable implementiert.
Ein Objekt dieser Klasse wird in der Main erzeugt und bekommt das Model übergeben.
Ok.
Und WO muss ich nun die Threads hinschreiben?

(Moment, langsam: Meine View hat keine Modelinstanz, das darf sie auch bei uns nicht).


Meine main sieht im übrigen so aus.

Java:
Mod m = new Mod();
Con c = new Con(m);
c.init();

Da wollte ich eben jetzt noch reinschreiben: Threadklasse t = new Threadklasse(m);

und dann halt irgendwas damit machen. Ist das richtig so?
 
Zuletzt bearbeitet:

Michael...

Top Contributor
Im Prinzip hast Du da oben ja schon ein komplettes Gerüst stehen, dass "nur" noch ausgefüllt werden muss. Wenn Du das Model - aus welchen Gründen auch immer - nicht der View übergeben darfst, dann muss man diesen Teil halt Euren Vorgaben anpassen.
 
Wunderbar! Michael hat völlig recht.

Da wollte ich eben jetzt noch reinschreiben: Threadklasse t = new Threadklasse(m);

und dann halt irgendwas damit machen. Ist das richtig so?

Nein, die (gute und richtige) Idee von Michael war, auf einer Controller-Ebene eine Klasse zu erstellen, die diese Aufgabe übernimmt.
 

Anto

Aktives Mitglied
Na aber.....das tue ich doch. Ich schreibe in das Controllerpackage eine solche Klasse, die Runnable implementiert.
Was mir noch ein völliges Rätsel ist, ist, wo ich dann die Threads erzeugen muss?

Im Controller, und ihnen da das Model übergeben, oder so?
 

Anto

Aktives Mitglied
Das habe ich mitbekommen ich habe nur nicht verstanden, WO diese Zeile stehen soll?

im Controller?

Bzw. ich denke mal schon aber muss die Zeile, wo start aufgerufen wird, dann im Konstruktor vom Controller stehen?
 
Zuletzt bearbeitet:

Anto

Aktives Mitglied
Das Thread erzeugen geht im übrigen in meiner Controllerklasse nicht, weil er das dann nicht findet?
Also....der Aufruf von start sagt "cannot find loop in location controllerklasse"
 

bERt0r

Top Contributor
Halt Stopp! Bevor du noch 5 Seiten Posts hier dranhängst mach mal einen Moment pause und überleg mal. WO code steht ist für dein Problem völlig irrelevant. Du kannst die gleiche Funktionalität, mit dem gleichen DesignPattern trotzdem noch auf zig unterschiedliche Arten realisieren.
Du scheinst zu glauben, dass durch deine Vorgaben manche Dinge unmöglich sind, stimmt aber nicht, du musst nur anders an die Sache herangehen.
Ein Beispiel: Wenn du immer nur ein Interface implementieren darfst, aber eben 2 implementieren möchtest für deine Funktionalität.
Lösung: Du schreibst dir 2 Klassen die jeweils ein Interface implementieren und machst dann eine Oberklasse, die je eine Instanz der jeweiligen Imlementierungen der Interfaces hält und diese dann bedient.
 

Anto

Aktives Mitglied
Dafür bräuchte ich aber doch viel mehr Wissen!

Ich meine ich habe mittlerweile begriffen, dass eine Klasse, die Runnable implementiert, aus irgendeinem Grund Threadobjekte erzeugen kann.

Anscheinend kann ich das aber nur IN dieser Klasse und an keinem anderen Ort, was also hilft mir das?

Ich bräuchte einfach viel mehr Wissen als ich habe.

Diesen Befehl, der die Startmethode aufruft: ich GLAUBE, das sind eigentlich 2 Befehle.
In der Schreibweise als EIN befehl verstehe ich aber nur begrenzt, was da geschieht.

Und in jedem Fall muss ich ja irgendwo ein Threadobjekt erzeugen, aber anscheinend gibt es ja keine einzige Klasse, in der das ohne Fehlermeldung geht?

Und eigentlich will ich nicht noch mehr Oberklassen haben, ich verstehe das was ich jetzt tue ja schon kaum.
Zumal ich dann hier wieder 5h fragen müsste, was jetzt wozu die Oberklasse sein muss und aus welchen Gründen überhaupt.



Kann man nicht in einfachen Worten sagen:

"Die Klasse, die den Listener implementiert/die Klasse, die den Spieler bewegt /welche Klasse auch immer muss ein Threadobjekt erzeugen. Dieses Objekt muss dann die Methode Start aufrufen. Start wird implementiert in der klasse, die folgendes macht: .....
und run tut im Grunde folgendes: "

So etwas in der Art suche ich, aber das scheint es nirgendwo zu geben.
 
Es gibt in der Programmierung keine Kochrezepte. Ebenso bringt es nichts, sich stumpf an irgendwelche künstlichen Regeln wie "nur ein Interface pro Klasse" zu implementieren, zu halten. Allerdings gibt es ein gewisses Set an Regeln, an dem sich orientieren kann, die sich als zuträglich erwiesen haben: Clean Code Developer - Clean Code Developer

Tatsächlich braucht man nicht einmal zwingend eine Klasse, die Runnable implementiert. (In diesem Fall aber schon).
Java:
Thread fred = new Thread(new Runnable()
  {
     run()
    {
    //
    }
   });

fred.start();
 
Zuletzt bearbeitet:

Anto

Aktives Mitglied
Naja. Bei den Programmieranteilen, die ich bis jetzt gut kann (nicht java, wie man sieht) habe ich mcih meist das erste halbe Jahr stumpf an Kochrezepte gehalten und dann angefangen mich davon wegzubewegen.
Aber für dieses erste halbe Jahr waren die Rezepte eben hilfreich.

Ich habe das nun so gemacht wie es da steht.

Bleiben 2 Fragen:
WO wird start implementiert (oder ist die vorgegeben?)

WAS in etwa kommt in run? also, ganz allgemein jetzt.
 

Sunchezz

Bekanntes Mitglied
der Thread sollte am sinnvollsten normaler weise im Controller implementiert werden.

Aber eigentlich ist das egal, es sei denn du willst dich an diese Regeln halten...
Die hauptsache ist nur das der Thread zufgriff auf alle Elemente bekommen kann (über getter) die für seine aufgaben wichtig sind.


in run() sollte alles stehen was für die flagAbfrage deiner key wichtig ist, und die berechnung der positionen!
 
Zuletzt bearbeitet:

Anto

Aktives Mitglied
Moment, langsam. Die Positionsberechnung sollte in Run stehen?
Aber die Methoden, die die Position neu setzen, stehen doch in meiner Spielerklasse! und ich dachte immer, da gehören sie logischerweise auch hin!

oder wäre das im zweifel nur die eine Methode die immer neu durchrennt?

Ihr sagt alle, ich soll zuerst Grundlagen lernen, aber wenn ich das tue, muss ich das Semester noch einmal machen!
 

bERt0r

Top Contributor
Tja, ohne die Grundlagen gehts leider nicht. Wenn du nicht weißt was ein Thread ist, wirst du auch keinen programmieren können.
 

Anto

Aktives Mitglied
Tja also, ich habe das jetzt so gemacht wie ich DACHTE dass es richtig ist: Mein Controler:

-erzeugt ein Objekt einer Klasse X, die Runnable implementiert, und zwar im Konstruktor, und ruft darauf start auf. ausserdem wird diesem Xobjekt das model übergeben.
-reicht Keycodes (bzw. Entsprechungen davon) ans Model weiter.

Das Model seinerseits setzt daraufhin die entsprechenden Booleans in den Spielerklassen. Außerdem setzt es auch noch einen boolean, der anzeigt, dass das Spiel gestartet wurde.

In run steht nun in etwa drin:

Solange das Spiel gestartet ist:

Überprüfe ständig, welche von den entsprechenden booleans gerade auf true stehen und nutze die entsprechenden Methoden der Spielerklasse, um die Werte zu ändern.
Außerdem rufe eine Methode in Model auf, die im grunde nichts anderes macht als setChanged usw.


Wenn ich nun mein Programm starten will, startet das Programm korrekt, aber ich kann keine meiner Spielfiguren bewegen.

Das ist im Nachhinein auch kein Wunder, denn run wird ja nirgends aufgerufen!
Wo wird das gemacht? In Euren Beispielen kam immer nur start....

Habe ich etwas wichtiges vergessen, nach meinen Erzählungen hier?
 
Zuletzt bearbeitet:

Ähnliche Java Themen


Oben