C++ Problem mit Kollisionsabfrage

01/25/2015 12:32 Verteidiger#1
Guten Tag an die Community,

Im Sinne meines Abschlussprojektes programmiere ich ein 2D-Platformer mit Microsoft Visual Studio 2010, C++, Der Bibliothek "Allegro 4". Das ganze natürlich objektorientiert.

Ich habe folgendes Problem:

mit dieser Methode:
Code:
void Collision::LoadCollisionMap(const char *filename)
{
   ifstream openfile(filename);
   if(openfile.is_open())
   {
     openfile >> mapSizeX >> mapSizeY;
     while (!openfile.eof())
     {
       openfile >> ColMapFile[loadCounterX][loadCounterY];
       loadCounterX++;
       if(loadCounterX >= mapSizeX)
       {
         loadCounterX = 0;
         loadCounterY ++;
       }
     }
     loadCounterX = loadCounterY = 0;
     
   }
}
lade ich meine Map:

10 8
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

in das zweidimensionale Array "ColMapFile[loadCounterX][loadCounterY]"
die ersten zwei Werte sollen inr mapSizeX und mapSizeY geladen werden.

Das funktioniert auch, da ich genau die selbe Logik angewandt habe, um meine Map mittels Tiles zu gestalten.

Nun zu dem Problem:

mit folgender Methode:
Code:
void Collision:: PlatformCollision(BITMAP *buffer, Player &player)
{
   for (int i = 0; i < mapSizeX; i++)
   {
     for (int j = 0; j < mapSizeY; j++)
     {
       
       if(ColMapFile[i][j] != 0)
       {
         if(player.y+player.animation->h<j*BlockSize || player.x > i*BlockSize+BlockSize || player.y > j*BlockSize+BlockSize || player.x+player.animation->w < i* BlockSize)
         {
           player.Platform = false;
           
         }
         else
         {
           player.Platform = true;
           
         }
       }
     }
   }   
}
prüfe ich das o.g. Array auf einsen, wenn eine gefunden wird, soll die oben zusehende if-Abfrage durchgeführt werden usw.

Auch das funktioniert soweit, ich habe aus Testzwecken erstmals ein einziges Tile, also eine einzige 1, geladen, die Kollisions-Erkennung funktionierte dann auch einwandfrei, aber sobald ich eine zweite eins in die Map packe, wird nur eine eins erkannt und auf Kollision überprüft. Es scheint mir so als würde sich mein Code immer auf die eins festlegen, welche am nächsten zum Spieler spawn ist.

Syntaktischer oder logischer Fehler?

schonmal vielen lieben Dank im Vorraus,
mit freundlichen Grüßen,
Verteidiger
01/25/2015 15:18 dciimtN#2
Wenn die Map richtig geladen wurde, wie du sagst, wird es wohl an der fetten if-Abfrage liegen.
Ich hab da mal eine Stelle markiert.
Dort würde ich ansetzen:
-Hast du 2 Ausgaben für die 2 Einsen liegts am if darunter (oder der Weiterverarbeitung?)
-Hast du 1 Ausgabe für eine von zwei Einsen sollte es wohl doch die Map sein

PHP Code:
if(ColMapFile[i][j] != 0)
{
    
// <--- Ausgabe?
    
if(player.y+player.animation->h<j*BlockSize || player.i*BlockSize+BlockSize || player.j*BlockSize+BlockSize || player.x+player.animation->iBlockSize)
        {
            ... 
01/25/2015 15:29 Verteidiger#3
Tut mir leid, kann dir nicht ganz folgen, was meinst du mit Ausgaben?
01/25/2015 15:31 dciimtN#4
Entweder dir dort was ausgeben lassen oder breakpoint setzen um zu sehen wie oft du an der Stelle landest
01/25/2015 15:34 Verteidiger#5
Aber rein theoretisch müsste die if-Abfrage jedes Mal durchgeführt werden, da sie, als ich zu testzwecken die Map mit nur einer eins modeliert habe, immer die Variable player.Platform in den richtigen Zustand versetzt hat, also wenn ich die eins berührt habe, wurde die Variable true, und sobald ich sie nicht mehr berührt habe, wurde sie auch wieder auf false gesetzt.

Edit: hab mir mal ne Ausgabe rein gemacht, die rattert immer durch, ich komm also jedes mal an die stelle "//Ausgabe"

Edit_2: Und zur Weiterverarbeitung, zurzeit wird nur die Variable Platform in der Klasse Player true bzw. false gesetzt und wenn ich das ganze Debugge wird mir der Zustand von Platform angezeigt ( durch ausgeben von 1 = true und 0 = false)
01/25/2015 15:41 dciimtN#6
Und bei der zweiten 1 passiert nichts wenn du sie berührst aber du bist 100% sicher sie ist in der map?
01/25/2015 15:45 Verteidiger#7
Ja ich habe es so gemacht, das die Tile map, also das was sichtbar ist, die selbe .txt Datei ist wie die, die ich für die Kollision benutze.
Ich sehe die zwei Blöcke, da die Kollision die selbe Datei nutzt sind also auch die zwei einsen da und müssten abgefragt werden, es wird aber immer nur ein Block abgefragt, die restlichen werden garnicht beachtet, da bleibt player.Platform bei berührung immer false.
01/25/2015 16:04 dciimtN#8
Dann würde ich stark darauf setzen, dass bei der Logik der if-Abfrage irgendwas nicht hinhaut.

Ich weiß halt nicht was animation.h und .w oder BlockSize für Werte haben und was Platform aussagen soll deswegen ist das schwierig nachzurechnen für mich
01/25/2015 16:12 Verteidiger#9
also animation ist das BITMAP in der das jeweilige Bild des Spielercharakters geladen wird, die sind aber alle gleich groß. animation->h steht für die Höhe des Bildes in pixel, und und animation->w für die Breite...BlockSize ist 64 da ich Tiles der Größe 64x64 nutze. Und Platform soll nur aussagen ob sich eine Tile direkt vor bzw unter dem Spielercharakter befindet(=player.platform = true) oder ob nicht(=player.platform = false)
01/25/2015 17:04 dciimtN#10
Bewegt sich der Spieler pixelweise oder koordinatenweise also player.x zwischen 0 und 10?
und wie groß ist das Spielerbild auch 64x64?
01/25/2015 17:07 Verteidiger#11
also player.x gibt die x Koordinate an, an der das Spieler BITMAP geblittet werden soll, somit bewegt der Spieler sich koordinatenweise. das Spielerbild ist 64 pixel breit und 80 pixel hoch

EDIT: Was ich einfach nicht verstehen will, ist, warum es bei dem einen Block wunderbar klappt, aber bei dem Block(1) darüber, nicht :D
01/25/2015 17:47 dciimtN#12
Hmm also was ich sehe:
Code:
if(
       player.y+player.animation->h < j*BlockSize // ein + zwischen der koordinate und der höhe in pixeln?
    || player.x > i*BlockSize+BlockSize // kann nie true sein: x maximal 9 und +BlockSize immer mindestens 64
    || player.y > j*BlockSize+BlockSize // kann auch nie true sein: selber grund
    || player.x+player.animation->w < i* BlockSize // ein + zwischen der koordinate und der breite in pixeln?
)
01/25/2015 17:55 Verteidiger#13
Die if-Abfrage an sich ist korrekt, ich habe sie getestet, sie funktioniert, denn wenn man zu einer koordinate die höhe des bildes addiert, so erhält man eine ganz normal Zahl.beispiel:
der spieler ist auf der y koordinate 100, addiere ich nun die höhe von animation dazu, lande ich bei 180, und weil von oben nach unten y größer wird, muss player.y+player.animation->h kleiner als j*BlockSize sein, damit der spieler sich über dem geprüftem Block befindet.
Das hat schon alles seine richtigkeit, sonst würde es ja nicht bei dem einen Block einwandfrei funktionieren, meine Vermutung ist, dass wenn (ifColMapFile[i][j] != 0) ist, dass er zwar den Block usw prüft, aber dann nicht mehr rauskommt, also keine weiteren Stellen im Array überprüft...könnte mich aber auch irren :/
01/25/2015 18:00 dciimtN#14
Also ist der Wertebereich von player.x nun 0-9 oder 0-(9*64)?
Vllt hatte ich mich falsch ausgedrückt, bewegt der Spieler sich immer 1 Pixel oder immer 64?
01/25/2015 18:14 Verteidiger#15
während beispielsweise die "D" taste gedrückt ist erhöht sich die x-koordinate an der das Spieler BITMAp geblittet wird um 2. Der Spieler kann sich also "stufenlos" bewegen.

Code:
void Collision:: PlatformCollision(BITMAP *buffer, Player &player)
{
player.Platform = false;
   for (int i = 0; i < mapSizeX; i++)
   {
     for (int j = 0; j < mapSizeY; j++)
     {
       
       if(ColMapFile[i][j] != 0)
       {
         if(!(player.y+player.animation->h<j*BlockSize || player.x > i*BlockSize+BlockSize || player.y > j*BlockSize+BlockSize || player.x+player.animation->w < i* BlockSize))
         {
           player.Platform = true;
           
         }

       }
     }
   }   
}
tada die lösung :p
Danke für deine Hilfe :)