Jump 'n' Run-Spiel Kollisionserkennung

Schmetterhand

Aktives Mitglied
Hallo zusammen!

Ich bin ein neuer Benutzer und hoffe, daß ich mich an die Forumsrichtlinien halte… 🙂

Meine Frage bezieht sich auf ein Problem bei meinem Spiel mit JavaFx, und zwar speziell auf die Kollisionserkennung. Nach bereits einigen Tagen Suche nach einer Methode zur Kollisionserkennung frage ich nun Kollisionen erfolgreich ab, jedoch bleibt ein seltsames Ruckeln der (JavaFx-)Kamerasicht, sobald eine Kollision stattfindet.

Bitte nicht darüber erschrecken, daß ich auf Deutsch programmiere, aber ein Mensch denkt immer in seiner Muttersprache und so stört der englische Code nur den Denkfluss.

Ich habe versucht, eine klare Trennung zwischen "model, view & controller" (MVC-Konzept). Die Variable "mModell" ist die Instanz eines Singletons und hält alle logischen Daten, wie z.B. alle Aktoren.
Die verwendete Klasse "Tupel2d" ist ein Äquivalent zu Javas "Point2D"-Klasse, nur auf meine Bedürfnisse angepaßt.

Hier die stark vereinfachte Animationsfunktion des Spieler-Objekts, die bei jedem Zyklus aufgerufen wird:

Java:
/**
    * Hier kann der Aktor Aktionen vornehmen.
    */
   @Override
   public void animiere()
   {
      // Bewegung etc…

      if (mVektor.x != 0) {
         mPosition.x += mVektor.x;
         Aktor kollision = prüfeKollision();
         if (kollision != null) {
            while (istÜberschneidung(kollision)) {
               if (mVektor.x > 0) {
                  mPosition.x--;
               }
               else {
                  mPosition.x++;
               }
            }
            mVektor.x = 0;
         }
      }
      if (mVektor.y != 0) {
         mPosition.y += mVektor.y;
         Aktor kollision = prüfeKollision();
         if (kollision != null) {
            while (istÜberschneidung(kollision)) {
               if (mVektor.y > 0) {
                  mPosition.y--;
               }
               else {
                  mPosition.y++;
               }
            }
            mVektor.y = 0;
         }
      }
      transliere(mPosition);
   }

Hier noch die relevanten Funktionen aus der Superklasse:

Java:
/**
    * @param abfrage Der Aktor zu prüfende Aktor.
    * @return Ob Kollision zwischen diesem Aktor und dem Übergabe-Aktor.
    */
   public boolean istÜberschneidung(Aktor abfrage)
   {
      Rectangle2D aktormaß = abfrage.gibAusmaß();

      return gibAusmaß().intersects(aktormaß);
   }


   /**
    * @return Falls Kollision, wird der Aktor zurückgegeben.
    */
   public Aktor prüfeKollision()
   {
      for(Aktor aktor : mModell.gibBlockliste()) {
         if (aktor.mIstSolid) {
            if (istÜberschneidung(aktor)) {
               return aktor;
            }
         }
      }
      return null;
   }


  /**
  * Gibt die Maße des Aktors.
  *
  * @return Ausmaß.
  */
  public Rectangle2D gibAusmaß()
  {
     return new Rectangle2D(mPosition.x, mPosition.y, mBreite, mHöhe);
  }


  /**
  * Transliert sowohl die Logik- als auch die Sichtposition.
  *
  * @param neupos Die neue Position.
  */
  public void transliere(Tupel2d neupos)
  {
     mPosition.set(neupos.x, neupos.y);

     mBildsicht.setTranslateX(neupos.x);
     mBildsicht.setTranslateY(neupos.y);
  }
 
Zuletzt bearbeitet:
Ich glaube, daß ich jetzt eine Vorstellung habe, warum dieses seltsame Zittern bei einer Kollision passiert. Ich ziehe ja immer 1 ab von der jeweiligen Position. "position.x--". Da der Spieler aber manchmal auch nur 0,5 Einheiten in einem Block steckt, wird er um -1 herausgezogen und dann sofort wieder von der Schwerkraft nach unten gezogen. (Jedenfalls könnte das sein, nach verschiedenen Tests mit Konsolenausgaben).

Wenn ich aber jetzt meine Kollisionsprüfung umstellen will, stehe ich vor folgendem Problem:

Kollisionsdelta.png

Wie bekomme ich die Dimensionen des grünen Deltas heraus? (so nennt man das doch, glaube ich)
Und vor allem, funktioniert das auch, wenn der Block auf einer anderen Seite wäre?

Ich wäre über Hilfe sehr Dankbar (auch in "Gefällt mir"-Angaben 😉)

Gruß,
Schmetterhand.
 
Nabend,

Das Delta, ja so wird eine Differenz genannt", kann man ganz einfach berechen:

Ich nenne das Große rechteck jetzt mal r1, das kleine r2, und dann noch x und y für Koordinaten.
Das hier ist Pseudocode...

int deltaWidth = (r1x + r1width) - r2x
int deltaHeight = (r1y + r1height) - r2y

Das sollte es eigentlich auch schon gewesen sein, also immer einfach die R1-xKoordinate + R1-Breite - xKood-R2

mfg Major
 
Ich habe das Problem jetzt gelöst. Das ist schon eine Weile her, ich habe nur vergessen, es hier zu schreiben.
Es war eigentlich ziemlich leicht: Man muß einfach nur die Achsen separieren („separating axes theorem”), also zuerst eine Kollision der Hitbox des Spielers nur mit der Verschiebung auf der X-Achse durchführen und auf diese reagieren. Danach macht man das gleiche auch mit der Y-Achse.
Falls eine Kollision stattfindet, muß man noch die Bewegungsrichtung des Spielers herausfinden (entspricht der Seite der Kollision) und die Position des Spielers auf die Außenkante des Kollisionsobjektes zurücksetzen.

Java:
         if (aktor.istSolid() && kollidiert(aktor)) {
            // Nur in X-Richtung prüfen.
            Rectangle2D spieler = new Rectangle2D(gibAusmaß().getMinX()+mVektor.x, gibAusmaß().getMinY(),
                                                  gibAusmaß().getWidth(), gibAusmaß().getHeight());
            if (spieler.intersects(aktor.gibAusmaß())) {
               //Spieler bewegt sich nach rechts.
               if (mVektor.x > 0) {
                  mPosition.x = aktor.gibPosition().x - gibBreite() + cVersatz;
               }
               // Spieler bewegt sich nach links.
               else if (mVektor.x < 0) {
                  mPosition.x = aktor.gibPosition().x + aktor.gibBreite() - cVersatz;
               }
               mVektor.x = 0;
            }

            // Nur in Y-Richtung prüfen.
            spieler = new Rectangle2D(gibAusmaß().getMinX(), gibAusmaß().getMinY() + mVektor.y,
                                      gibAusmaß().getWidth(), gibAusmaß().getHeight());
            if (spieler.intersects(aktor.gibAusmaß())) {
               //Spieler bewegt sich nach unten.
               if (mVektor.y > 0) {
                  mPosition.y = aktor.gibPosition().y - gibHöhe() + cVersatz;
               }
               //Spieler bewegt sich nach oben.
               else if (mVektor.y < 0) {
                  mPosition.y = aktor.gibPosition().y + aktor.gibHöhe() - cVersatz;
               }
               mVektor.y = 0;
            }
            kollisionsliste.add(aktor);
         }
 

Neue Themen


Zurück
Oben