Abfrage-Fehler? - Hilfe bei Tetris

LP_SE

Aktives Mitglied
Ich habe hier ein Spiele-Programmierungs-Tutorial, um zu lernen, wie man Java-Spiele schreibt.
Habe noch keine Erfahrung mit paint() und Graphics gemacht und habe dies als Einstieg benutzt. Habe jetzt eine Tetris-Version programmiert (im Tutorial war was anderes, habe dann aber gedacht: Tetris passt besser und habe das Tut als Hilfe genommen).
Nun habe ich die Anzeige halbwegs hinbekommen, habe aber irgendwo einen Denkfehler, weiß nicht, warum es nicht geht. Es kommt immer nur einer von vier Teilen des Steins runtergefallen, ein weiteres bleibt in der linken oberen Ecke. Beim Bewegen treten manchmal völlig abwegige Exceptions auf, wie ArrayIndexOutOfBounds (-1), obwohl alle Zahlen positiv sind.

Habe hier mal grob zusammengestell, wie ich das Tetris angegangen bin:

-Stein-Objekte mit 4-Koordinaten, davon einer als Referenz, anhand welcher die anderen berechnet werden.
-Color[][] zum speichern der Steine die schon unten sind (schwarz = unbesetzt)
-Feld zeichnen nach den Koordinaten (ein Element 40x40p, ein Pixel schwarzer Rand also 38x38)
-javax.swing.Timer zum Fallenlassen der Steine

Hab den src-Ordner gezippt und angehangen, wer Lust hat kann sich den Lösungsweg anschauen und mir dann vllt meine Fehler mitteilen, das wäre klasse:toll:
 

Anhänge

Ich denke du wirst mehr Unterstützung bekommen wenn du sagst in welcher Zeile die Exception auftritt, den entsprechenden Code postest und noch zeigst wo du das array initialisierst.
 
Das ist ja das Problem, das ist unterschiedlich.
Code posten geht schlecht, da der Fehler irgenwo in den Verbindungen oder Abfragen steckt, deßhalb kann ich auch kein kskb machen, da das problem in der Komplexen Logik liegt.

Hier die Exception: (hab das mit der OutOf Bounds(-1) schon hingekriegt, da war eine Klammer falsch.)
Code:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 9
	at virtuelgamepanel.CVirtuelPanel.checkMovement(CVirtuelPanel.java:124)
	at virtuelgamepanel.CVirtuelPanel.stepRight(CVirtuelPanel.java:59)
	at ui.CGamePanel$2.keyPressed(CGamePanel.java:104)
	at java.awt.Component.processKeyEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Window.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.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.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(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)

Das gleiche noch an der Stelle:
Code:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 16
	at virtuelgamepanel.CVirtuelPanel.checkMovement(CVirtuelPanel.java:105)
	at virtuelgamepanel.CVirtuelPanel.stepDown(CVirtuelPanel.java:67)
	at ui.CGamePanel$2.keyPressed(CGamePanel.java:105)


Hier diese Stellen (ja, schlecht formatiert, aber cih blick kaum noch durch, die formatierung ist für mich so am besten, um noch halbwegs was zu wissen):

[JAVA=102]
switch(pos) {
case 0: {
if((akt.getKoo1().getY() & akt.getKoo2().getY() & akt.getKoo3().getY() & akt.getKooM().getY()) < 15) {
if(ground[akt.getKoo1().getX()][akt.getKoo1().getY()+1] == Color.black && ground[akt.getKoo2().getX()][akt.getKoo2().getY()+1] == Color.black && ground[akt.getKoo3().getX()][akt.getKoo3().getY()+1] == Color.black && ground[akt.getKooM().getX()][akt.getKooM().getY()+1]== Color.black) {
return true;
}
else return false;
}
else return false;

}
case 1: {
if((akt.getKoo1().getX() & akt.getKoo2().getX() & akt.getKoo3().getX() & akt.getKooM().getX()) > 0) {
if(ground[akt.getKoo1().getX()-1][akt.getKoo1().getY()] == Color.black && ground[akt.getKoo2().getX()-1][akt.getKoo2().getY()] == Color.black && ground[akt.getKoo3().getX()-1][akt.getKoo3().getY()] == Color.black && ground[akt.getKooM().getX()-1][akt.getKooM().getY()]== Color.black) {
return true;
}
else return false;
}
else return false;
}
case 2: {
if((akt.getKoo1().getX() & akt.getKoo2().getX() & akt.getKoo3().getX() & akt.getKooM().getX()) < 8) {
if(ground[akt.getKoo1().getX()+1][akt.getKoo1().getY()] == Color.black && ground[akt.getKoo2().getX()+1][akt.getKoo2().getY()] == Color.black && ground[akt.getKoo3().getX()+1][akt.getKoo3().getY()] == Color.black && ground[akt.getKooM().getX()+1][akt.getKooM().getY()]== Color.black) {
return true;
}
else return false;
}
else return false;
}
}
return false;
[/code]
 
auf solchem Code wird wohl niemand genauer drauf schauen,
wozu machst du alles doppelt und dreifach?

es reicht doch vor dem switch EINMAL
int x = akt.getKoo1().getX() & akt.getKoo2().getX() & akt.getKoo3().getX() & akt.getKooM().getX();
auszurechnen,
dann musst du akt.getKoo1().getX() & akt.getKoo2().getX() & akt.getKoo3().getX() & akt.getKooM().getX()
nicht wer weiß wie oft schreiben,
dir fällt doch sicher auch auf, wie unleserlich etwas ist, wenn akt.getKoo1().getX() & akt.getKoo2().getX() & akt.getKoo3().getX() & akt.getKooM().getX() zwischen akt.getKoo1().getX() & akt.getKoo2().getX() & akt.getKoo3().getX() & akt.getKooM().getX() jeden akt.getKoo1().getX() & akt.getKoo2().getX() & akt.getKoo3().getX() & akt.getKooM().getX() Wort akt.getKoo1().getX() & akt.getKoo2().getX() & akt.getKoo3().getX() & akt.getKooM().getX() steht

-----

als nächstest hast du
ground[akt.getKoo1().getX()][akt.getKoo1().getY()+1]
ground[akt.getKoo1().getX()-1][akt.getKoo1().getY()]
ground[akt.getKoo1().getX()+1][akt.getKoo1().getY()]
usw.,
wie wäre es dort mit Hilfs-Methoden a la

getColor(ground, akt.getKoo1(), 1, 0)
wobei die letzten Parameter +- auf x und y zu rechnen sind, nicht ganz einfach aber wenn man das 10x braucht,
dann wirds doch leserlicher als diese dicken Arrays,
und vermeidet Tippfehler, etwa Array-Zugriff Koo1.x, Koo2.y,

noch wirksamer wird dies bei größeren Zeilen, du hast da etwa

if(ground[akt.getKoo1().getX()+1][akt.getKoo1().getY()] == [..] && ground[akt.getKoo2().getX()+1][akt.getKoo2().getY()] == [..]
if(ground[akt.getKoo1().getX()-1][akt.getKoo1().getY()] == [..] && ground[akt.getKoo2().getX()-1][akt.getKoo2().getY()] == [..]

da sind also an drei Codestellen in einer Zeile gleich mehrere Array-Zugriffe mit diesen -1 oder +1 konsistent,
diese Zeilen könnten so leicht in einer Hilfsmethode verschieden:
if(isKoo123MBlack(ground, akt, 1, 0))
sehr kurzer Aufruf und in der Methode werden von akt die Koo1 bis Koo3 abgefragt,
einheitlich die x/y Parameter drauf addiert, bei ground auf Color.Black verglichen usw.,
quasi so wie bisher, nur nur noch 1x statt 3x und weniger fehleranfällig dass irgendwo +2 statt +1 steht


-------

zu Fehler:
letztlich musst du die exakte Zeile des Arrayzugriffs anschauen und prüfen, warum dort gerade dieser falsche Array-Zugriff verwendet wird,
wer ist dafür verantwortlich, wer stellt die Anfrage und warum,
wenn z.B. rechts von einem belegten Spielfeld nachgeschaut wird, fehlt dann ein Check ob Spielfeld zu Ende?
usw.
 
Zuletzt bearbeitet von einem Moderator:
In dem Switch die ersten Abfragen schauen, ob das Verschieben noch im Spielfeld stattfindet, hab dort einen Fehler gefunden: es muss dort auch
Java:
akt.getKoo1().getX() < 8 && ...
bzw. Y<15 und X>0 (je nach richtung) heißen.
Werde mich gleich mal um die Hilfsmethoden kümmern.
Ich kann jetzt schon die einzelnen Referenzkordinaten verschieben, komischerweise werden die anderen aber nicht berechnet bzw. angezeigt :bahnhof:
außerdem kann ich nur nach rechts verschieben sowie nach unten beschleunigen.
Hat jemand ne ahnung woran dies liegen könnte, hab keine Exception und keine ahnung woran es liegen könnte, der code ist equivalent zum verschiebn nach rechts und wird einfach nicht ausgeführt. Da ich nicht weiß, wo der Fehler leigt, kann ich auch keinen Code posten (sind ca. 300 Zeilen in der Stone-Klasse, 50 Zeilen in der VirtuelPanel-Klasse und ein Aufruf in der GamePanel-Klasse).
 
Zuletzt bearbeitet:
habe jetzt ein neues Konzept gemacht, eine abstrakte Superklasse für die Steine und dann einzelne Subklassen gebildet, die Verwaltungsklasse in die Spielklasse mitaufgenommen und die Abfragen korrigiert.
Ich arbeite nun mit Offset-Koordinaten für die drei Neben-Steine und nun funktioniert alles wunderbar.

Wer will kann sich den Quellcode gerne anschauen. Habe auch eine Spielfertige Version angefügt.
 

Anhänge

Ganz nett geworden, noch 2 Sachen:
1) Irgendein Effekt wäre schön wenn du eine Reihe zuerstörst
2) Drück mal nach GameOver auf die Pfeiltaste nach unten 🙂
 
Funktioniert ganz gut 🙂 Ich weis nicht, ob das früher auch so war, aber wenn die Steine ganz am Rand sind, kann man dich nicht drehen, das vermisse ich ein wenig. Zudem stimmt etwas bei deiner Abfrage nicht, da man die Steine in andere hineindrehen kann 😱 Am simpelsten geht das wohl, wenn man eine zusätzliche Abfrage macht nachdem man den Stein gedreht hat und wenn der etwas schneidet, dann wird die Bewegung rückgängig gemacht.
 
Zuletzt bearbeitet:
Ja, diese Bugs sind mir bekannt, habe aber jetzt nicht vor diese zu beheben, da dies nur ein Übungsprojekt war.
Wer will, darf meinen Source-Code verwenden und diese Bugs beheben bzw. mein Programm weiterentwickeln.
P.S.: die Überschneidungsabfrage bei Rotation ist entweder noch drin oder war drin, funktioniert aber nicht richtig.
 

Neue Themen


Zurück
Oben