Java Game verbesserte Kollisionserkennung

BraunBerry

Mitglied
Hallo Community,
ich melde mich nach meinem Waypointproblem nochmal zurück. In meinem Spiel habe ich auch ein terrain mit einem Spieler. Also der Spieler befindet sich in einem Raum (mehrere Ecken, nicht rechteckig). Ich habe kein Problem damit, die Kollisionskanten parallel zur X bzw. zur Y Achse zu setzen. Deshalb habe ich auch zuerst die Standardtaktik angewandt: Wenn ein X oder Y Wert überschritten wird, wird er auf das Maximum zurück gesetzt z.B.:
if(X >= 100){X = 100;}
Alles schön und gut aber dennoch frage ich mich ob es nicht eine einfachere und vorallem zeitsparendere Lösung gibt. Ich habe mich gefragt, ob es nicht möglich wäre, passend zum entsprechenden Terrain noch eine Grafik anzufertigen, in dem der Raum, in dem sich der Spieler bewegen kann beispielsweise transparent ist und der Raum in den der Spieler nicht kann bzw. bis zu den Kollisionskanten beispielsweise pink ist. Diese grafik könnte man dann unsichtbar im Spiel hinterlegen und so die Kollision abfragen. So zummindest meine Vorstellung. WICHTIG: Es sollten keine Fehler entstehen, wenn ich meine DIMENSION auf die Grafik anwende, also ein float Wert, der mit der Fenstergröße und allen Bildgrößen multipliziert wird, um eine einheitliche Größe einstellen zu können. Wenn ihr eine Idee hättet wie man soetwas verwirklichen könnte oder ob es so ein Verfahren schon mal in einem Spiel gabwürde ich mich sehr freuen. 🙂

lg BraunBerry
 
hast du jetzt ein Problem mit der Haltung der Kollisionsinformation oder mit dem Kollisionsverfahren?
Egal ob du jetzt die Informationen in einem Bild, einer Textdatei, irgendeinem Binärformat oder CSV Datein hinterlegst,
die Abfrage wäre immer die gleiche (zb. dein Rücksetz-Verfahren). Das mit der Grafik als Speicherort für die Kollisionsinformation ist auf jeden Fall eine gute Lösung, ich würde sagen da ist es Geschmackssache und abhängig von der Komplexität der Karten welches Verfahren am sinnvollsten ist. In einer Bilddatei könntest du theorietisch mit jeder RGB (oder RGBA) Farbe eine bestimmte Aktion interpretieren (zb. Spawnpunkte oder eben Kollisionsflächen). Wenn man aber komplexe Metadaten zusätzlich zur Kollision hat, und nicht mit mehreren Files rumhantieren will, dann lohnt es sich über ein eigenes Format nachzudenken. Deshalb könnte ich dir jetzt keine Antwort geben welches das beste Verfahren für dein Projekt wäre.
 
Mein Problem ist die Rücksetztung. In einem Rechteck wäre das gar kein Problem. Allerdings in komplexerem Raum ist das etwas koplizierter. Ich habe versucht die letzte Position des Spielers (also des Terrains, weil der Spieler immer zentriert ist) nach jeder Kollisionsabfrage in einer Variable zu speichern. Dann habe ich versucht die Intersection von Rectangels (playerHitbox und der Kollisionskante Bound001) abzufragen, so dass bei
if (playerHitbox.intersects(Bound001))
Die Koordinaten wieder auf den letzten Punkt zurückgesetzt werden. Allerdings bewegt sich dann garnichts mehr und ich glaube auch nicht dass das so funktionieren wird. Obwohl ich zwar alles selber schreiben wollte, frage ich mich ib es nicht irgendeine Library gibt, die die Kollisionsabfrage und Rücksetztung vereinfacht.

Lg BraunBerry
 
Anstatt die Position neu zu setzen und bei kollision zurückzusetzen, kannst du auch einfach die position nur ändern, wenn dies zu keiner Kollision führt.
quasi:
Java:
target = position + delta;
if(!kollision(target)) {
  position = target;
  // ... restliche bewegung durchführen
}

Um dir mehr helfen zu können, wäre es gut wenn du mehr zum Spielfeld sagst. Denn je nach Aufbau gibt es unterschiedliche Lösungsmöglichkeiten. Nutzt du eine Tilemap? Beliebige Positionen? etc.

Ansonsten würde ich dir sowieso empfehlen das ganze mit sowas wie z.B. LibGDX zu machen, das ist ein Framework für Spiele.
 
Du redest dauernd von einem komplexen Raum, der kein Rectangle ist, überprüfst aber mit Rectangles die Intersection? Kannst du mal ein Screenshot von so einem Raum hochladen?
 
Im Bild habe ich versucht zu skizzieren, wie ich mir den Raum vorstelle.
PlayerSchema.png
InfectedBytes Idee, einfach die Bewegung zu deaktivieren wenn eine bestimmte Koordinate erreicht ist ist eigentlich sehr gut. Ich habe das mit den boolean Variablen canMoveRight und canMoveLeft in der Player-Klasse realisiert. Das Problem hierbei ist, dass wenn ich rechts am Maximum bin, der Spieler die ganze Zeit springt und wenn ich links am Maximum bin, das Bild immer hin und her springt. Hier nochmal mein Jump void:

Java:
public static void Jump(){
     if (isGrounded == true){
       isGrounded = false;
       isJumping = true;
       FALLVALUE = -FALLSPEED;
     }
   }

@Override
   public void actionPerformed(ActionEvent e) {
     if (e.getSource() == FallTimer){
       if (isGrounded == false){
         if (isJumping == true){
           JUMPHEIGHT += 1;
           MainTerrain.Y -= FALLVALUE;
           if (JUMPHEIGHT >= (MAXJUMPHEIGHT - JUMPSLOWDOWNINDICATOR)){
             JUMPHEIGHT = 0;
             FALLVALUE += 1;
           }
         }
       }
     }
   }

und meine KeyEvents:

Java:
switch(e.getKeyCode()){
       case KeyEvent.VK_A: if (Player.canMoveLeft == true){
                 MainTerrain.SPEEDX = Player.WALKSPEED;
                 Player.DIRECTION = "left";
                 Player.isWalking = true;
                 Player.initAniState();
                 break;}
     
       case KeyEvent.VK_D: if (Player.canMoveRight == true){
                 MainTerrain.SPEEDX = -Player.WALKSPEED;
                 Player.DIRECTION = "right";
                 Player.isWalking = true;
                 Player.initAniState();
                 break;}
     
       case KeyEvent.VK_SPACE: if (Player.isGrounded == true){Player.Jump();}
                  break;
       }

falls ihr damit etwas anfangen könnt.

Ich probiere derzeit immernoch verschiede Möglichkeiten von Kollision aus.

PS: Jeder Mensch hat Stärken. Themen in Foren verständlich schreiben gehört bei mir leider nocht nicht wirklich dazu. :/

lg BraunBerry
 
Zuletzt bearbeitet von einem Moderator:
Hmm was hat das jetzt alles plötzlich mit Springen zu tun?
Wenn das Bild hin und herspringt sieht das für mich eher aus als ob das Rücksetzen
an einer Stelle noch "kaputt" im Code ist. PS: Bei dem bisschen Code was du jetzt vom Springen gezeigt hast fehlt doch noch das zurücksetzen der isGrounded und isJumping wenn der Sprung fertig ist?
 
Java:
public static void Update(){
     System.out.println(MainTerrain.X + " , " + MainTerrain.Y + " , " + isGrounded + " , " + JUMPHEIGHT + " , " + FALLVALUE + " , " + Application.WIDTH + " , " + Application.HEIGHT);  // ***TEMP***
     System.out.println(GUI.MOUSEX + " , " + GUI.MOUSEY);
     detectCollision();
   }
 
   public static void detectCollision(){
     if (MainTerrain.activeTerrain == "Scout001"){
     
       if ((MainTerrain.X <= 96) && (MainTerrain.X >= -270)){
         if (MainTerrain.Y <= 0){MainTerrain.Y = 0; isGrounded = true;}
       }
     }
   }

Hier ist nochmal meine bisherige Kollisionserkennung.
Ja die Kollision am liken Rand scheint irgendwie nicht richtig zu funktionieren (wenn ich a gedrückt halte). Und wenn ich am rechten Rand d gedrückt halte wird solange ich halte immer der Jump void ausgeführt. Ich vermute dass das Programm auf die nächste Aktion ausweicht (welche der Sprung ist) wenn eine Rechtsbewegung nicht mehr möglich ist.
 
Zuletzt bearbeitet:
Hmm wo wird da jetzt in detectCollision das canMoveRight/canMoveLeft gesetzt/zurückgesetzt?
Und bei isGrounded= true müsste doch noch isJumping = false gesetzt werden ,wenn ich alles richtig verstanden habe.
 
Ich hab das jetzt mal eingefügt:

Java:
public static void detectCollision(){
     if (MainTerrain.activeTerrain == "Scout001"){
     
       if ((MainTerrain.X <= 96) && (MainTerrain.X >= -270)){
         if (MainTerrain.Y <= 0){MainTerrain.Y = 0; isGrounded = true;}
       }
     
       if (MainTerrain.X <= -262){
         canMoveRight = false;
         MainTerrain.X = -262;
       }else{canMoveRight = true;}
     }
   }

Die Variable isJumping ist im Prinzip das umgekehrte Äquivalent zu isGrounded. Die Variable existiert nur schon, da ich für später Dublejumps, etc. geplant habe. Ich habe jetzt nur die Kollision für den rechten Rand eingefügt, da hier nur das Problem mit dem Springen bei d gedrückt halten auftritt.
 
Zuletzt bearbeitet:
Naja wie InfectedBytes schon gesagt hat ist die oberste Bedingung niemals true, weshalb der ganze Code ansich unerreicht ist. Dh. du dürfest gar keinen Unterschied merken wenn du dort was änderst. Änder doch mal das == zu equals bei dem String Vergleich und schau wie es dann läuft. Oder wo ist jetzt noch das Problem?
 
Nach gründlicher Überarbeitung kann ich noch einen Lösungsvorschlag hinterlassen: Wenn eine Bewegung nicht möglich war ist der switch auf die nächstmögliche Aktion im Code ausgewichen. Jetzt habe ich für jede Bewegungsart (Links, Rechts, Sprung) einen extra
Java:
switch(e.getKeyCode()){
geschrieben und die Kollision verläuft reibungslos.

Hier des Rätsels Lösung:
Java:
switch(e.getKeyCode()){
       case KeyEvent.VK_A: if (Player.canMoveLeft == true){
                 MainTerrain.SPEEDX = Player.WALKSPEED;
                 Player.DIRECTION = "left";
                 Player.isWalking = true;
                 Player.initAniState();
                 break;}}
       
       switch(e.getKeyCode()){
       case KeyEvent.VK_D: if (Player.canMoveRight == true){
                 MainTerrain.SPEEDX = -Player.WALKSPEED;
                 Player.DIRECTION = "right";
                 Player.isWalking = true;
                 Player.initAniState();
                 break;}}
       
       switch(e.getKeyCode()){
       case KeyEvent.VK_SPACE: if (Player.isGrounded == true){Player.Jump();}
                  break;}
 
die vielen switch sind recht unnötig und gehen am ganzen Sinn von switch vorbei. Du musst nur das break außerhalb der if machen.
Besser:
Java:
switch(e.getKeyCode()) {
  case KeyEvent.VK_A:
    if(...) { ... }
    break;
  case KeyEvent.VK_D:
    if(...) { ... }
    break;
  // ...
}
 
Kein Problem.
Du musst dir halt deinen Code einfach mal genauer ansehen. Hier war eben das Problem dass du mit break eben nur aus dem Switch gesprungen bist wenn dein if erfüllt war. Wenn es aber nicht erfüllt war, bist du einfach fröhlich weiter durch das switch gegangen.

Ansonsten mach bitte dringen das == true weg!
Es ist zwar nicht falsch, aber dennoch recht unschön und vorallem unnötig, denn immerhin ist deine Variable schon ein boolean, da brauchst nicht auch noch prüfen ob dieser boolean gleich einem anderen boolean ist.
Einfach:
Java:
if(Player.isGrounded) { ... }
und fertig. Falls du wissen willst ob der boolean false ist, machst du einfach:
Java:
if(!Player.isGrounded) { ... }
 

Neue Themen


Zurück
Oben