Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

26.07.2012, 13:32

Totaler Wurm in Kollision Erkennung bei Jump 'n Run

Hey,

(SFML 2, C++)

ich hab irgend wie total den Wurm in der Kollision's Erkennung und finde ihn einfach nicht. Mal kann man durch Blöcke laufen und mal durch Luft nicht. Vielleicht kann mir jemand helfen oder sagen wie es besser geht. Idee war einfach die Maximale Laufweite auszurechnen und zu sagen er kann einfach nicht drüber gehen mit std::min bzw std::max.


Compilete Version (vielleicht weiß ja jemand beim Ausprobieren woran es liegt)
http://pkuebler.de/alteJumpRun.zip

Die Map für Kollisionen: (Alles über null ist nicht durchgehbar.).

Quellcode

1
std::vector<unsigned int> Map1::getMap() const {    return boost::assign::list_of<unsigned int>            ( 1)( 0)( 0)( 0)( 0)( 0)( 1)( 1)( 1)( 1)( 1)( 1)( 1)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 1)            ( 1)( 0)( 0)( 0)( 0)( 0)( 1)( 0)( 0)( 0)( 0)( 0)( 1)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 0)( 1)            ( 1)....



Die Spieler Datei: (Da mir das Forum immer alle Zeilenumbrüche löscht noch mal als Pastbin:
http://pastebin.de/28255 )

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
#include "Units.h"#include "Map.h"
Units::Units() {   bodyTexture.SetSmooth(true);
   speedY = 0.f;   speedX = 0.f;   //SetOrigin(0.f, bodySprite.GetSize().y);}Units::~Units() {}
void Units::Render(sf::RenderTarget& target, sf::Renderer& renderer) const {   target.Draw(bodySprite); // Zeichnet Player   }
void Units::timeUpdate(std::vector<unsigned int> map, int unsigned mapWidth) {   Run(map, mapWidth);}
void Units::Run(std::vector<unsigned int> map, int unsigned mapWidth) {   // Pro Frame   sf::Vector2i lbCorner;   sf::Vector2i rbCorner;   sf::Vector2i ltCorner;   sf::Vector2i rtCorner;
   // Ecken Definieren die Geprüft werden müssen   lbCorner.x = GetPosition().x / Map::SCALE;   lbCorner.y = (GetPosition().y + bodySprite.GetSize().y) / Map::SCALE;   rbCorner.x = (GetPosition().x + bodySprite.GetSize().x) / Map::SCALE;   rbCorner.y = (GetPosition().y + bodySprite.GetSize().y) / Map::SCALE;   ltCorner.x = GetPosition().x / Map::SCALE;   ltCorner.y = GetPosition().y / Map::SCALE;   rtCorner.x = rbCorner.x;   rtCorner.y = ltCorner.y;      // Finde Maixmale Positionen   float maxLeft = 0.f;   float maxRight = mapWidth*Map::SCALE;   float maxTop = 0.f;   float maxBottom = (map.size()/mapWidth)*Map::SCALE;      // Links Kollesion   if (map[lbCorner.y*mapWidth + (lbCorner.x-1)] > 0 ||       map[ltCorner.y*mapWidth + (ltCorner.x-1)] > 0) {            maxLeft = lbCorner.x*Map::SCALE; // Ziehe von Aktuellem Feld 1 ab, -> in linken feld drin         }      // Rechts Kollesion   if (map[rbCorner.y*mapWidth + (rbCorner.x+1)] > 0 ||       map[rtCorner.y*mapWidth + (rtCorner.x+1)] > 0) {            maxRight = ((rbCorner.x+1)*Map::SCALE)-0.1f; // Ende dieses Feldes ist Maximum   }   // Ziehe die Spieler Größe ab, damit die Rechte Ecke nicht drüber kommt   maxRight = maxRight - bodySprite.GetSize().x;
   // Unten Kollesion   if (map[(lbCorner.y+1)*mapWidth + lbCorner.x] > 0 ||       map[(rbCorner.y+1)*mapWidth + rbCorner.x] > 0) {            maxBottom = (lbCorner.y+1)*Map::SCALE -1.f; // Addiere 1 zum anfang nächstes feld, ziehe 0.1f ab um ende dieses feld         }   maxBottom = maxBottom - bodySprite.GetSize().y;      // Oben Kollesion   if (map[(ltCorner.y-1)*mapWidth + ltCorner.x] > 0 ||       map[(rbCorner.y-1)*mapWidth + rbCorner.x] > 0) {            maxTop = (lbCorner.y*Map::SCALE);   }   // Addiere KörperGröße damit nicht drüber geht//   maxTop = maxTop + bodySprite.GetSize().x;      if (isRunLeft()) {      // Prüfe Links      bodySprite.FlipX(false);      SetPosition(std::max(GetPosition().x - 2.f, maxLeft), GetPosition().y);          } else if (isRunRight()) {      // Prüfe Rechts      bodySprite.FlipX(true);      SetPosition(std::min(GetPosition().x + 2.f, maxRight), GetPosition().y);            }
   if (isJump()) {      // Tiefer geht an der Stelle nicht.      if (std::min(GetPosition().y, maxBottom) == maxBottom) {                   speedY = 5.f;      }   }         // Gravitation   // Verlangsamt Geschwindigkeit nach oben pro Frame         speedY = std::max(speedY - 0.2f, -5.f);   
   if (speedY > 0) {      // Aktuell nach oben      SetPosition(GetPosition().x, std::max(GetPosition().y - speedY, maxTop));   } else if (speedY < 0) {      // Aktuell nach unten      // Ist Land in sicht?      SetPosition(GetPosition().x, std::min(GetPosition().y - speedY, maxBottom));             }   }

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

2

26.07.2012, 13:38

was hast du denn versucht, umzusetzen? (Beschreibung mit eigenen Worten, nicht mit Quelltext)
so werden wir nur schwer Denkfehler oder Implementierungsfehler finden können
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

eXpl0it3r

Treue Seele

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

3

26.07.2012, 13:45

(SFML 2, C++)

Das ist aber eine alte Version von SFML 2 (CamelCase vs camelCase), ich würde dir empfehlen entweder die neuste Version direkt von GitHubselbst zu kompilieren oder aber die SFML 2rc binaries zu verwenden. ;)

Zur Kollision gibt es verschiedene Methoden (z.B. siehe Wiki), so wie du das jetzt momentan machst, ist es nicht wirklich übersichtlich und verständlich (z.B. zu vieles rumrechnen), was sehr schnell Fehler einschleusen kann.
In SFML gibt eine Klasse sf::Rect<T> mit den Typdefs sf::IntRect und sf::FloatRect mit welcher du ein Rechteck beschreiben kannst. Die Klasse hat dann die Funktionen intersects() und contains(), damit kannst du überprüfen ob sich zwei Rechtecke überschneiden oder ob ein Punk in einem Rechteck enthalten ist.
Mit diesem Wissen kannst du nun auf eine einfachere Art Kollisionstests durchführen, in dem du z.B. eine Funktion hast, die dir das Kollisions Rechteck eines Sprites konstruiert und dann kannst du ganz einfach das Rechteck des Spielers mit den Rechtecken der Spielumgebung per intersects() auf kollision prüfen.
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

4

26.07.2012, 14:19

@Sacaldur: Ich habe erstmal jede Ecke des Spielers genommen bzw Ausgerechnet und denn die Koordinaten genommen. Nun hab ich das Feld für jede Ecke rausgesucht und geschaut ob das nächste Feld nen Block ist (< 0). Wenn dies der Fall ist, denn Anfang des nächsten Feldes genommen und als Maximalwert verwendet. Rechts und Unten dann noch jeweils die Spielergröße dazu gebaut. Anschließend einfach normal die Bewegung abgezogen aber mit std::min bzw std::max das begrenzt. Für die Gravitation gibts nen speedY float. Dieser geht auf maximal -5.f so das man immer runter gezogen wird wenn man nicht gerade springt. Denn noch 2 If Schleifen die jeweils dabei Maximum nach oben und unten Berücksichtigen.

@eXpl0it3r: Kann ich die den Einfach im Ordner austauschen oder muss ich das alles wieder neu einstellen?

Die Kollision per intersects hab ich gelesen und hatte auch angefangen damit aber irgend wie ergab das für mich keinen Sinn da der Spieler immer mit mindestens 2.f wandert und wenn möglicherweise bei einer Kollision nicht bis zur Wand kommt. Darüber hier auch wieder nur die Felder aussen rum berechnen oder kann man die Ganze Map auf einmal reinhauen? Und das entschiedene... Wenn der Spieler Links anstößt aber im Sprung ist soll er ja denn an der Wand runter fallen... So stell ich doch nur fest das er irgend wo gegen kommt.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

5

26.07.2012, 16:44

Vermutlich suchst du nach den Stichworten TileMap und Tile Kollision.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

6

26.07.2012, 21:57

Wieso auch immer, mal mit einigen Bier und Abstand kam mir einfach die Lösung in den Sinn...

Das Problem fürs Rein springen war, dass die Figur größer ist als die Tiles. So konnte das zwischen den Ecken durchrutschen. Habe nun in der Mitte nochmal einen Punkt gemacht den ich überprüfe.

Zusätzlich schaut er, ob durch die Bewegung überhaupt ein neues Tile erreicht wird.


EDIT: Oben klappt nun auch, das war nur nen Dreher. Bleibt die Frage obs so sinnvoll is...

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »MyFrosch« (26.07.2012, 22:54)


Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

7

27.07.2012, 18:46

Du kannst die Geschwindigkeit pro Frame auch begrenzen. Einfach nicht weiter bewegen lassen, als die kleinste Tilegröße. Wenns doch schneller/weiter gehen soll, kannst du auch in mehreren Schritten auf Kollision prüfen. Quasi immer einen Kleinen Schritt bis du die gesamte Strecke überprüft hast.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

Werbeanzeige