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

Swoerm

Alter Hase

  • »Swoerm« ist der Autor dieses Themas

Beiträge: 451

Wohnort: 127.0.0.1

  • Private Nachricht senden

1

23.08.2013, 14:22

[C++ & SDL] Problem bei Kollisionserkennung

Hi Community,

ich quäle mich seit Wochen mit einer einfachen Kollisionserkennung rum. :dead:
An sich musste der Code richtig sein (hab ihn aus einem Tutorial und leicht abgeändert).
Manchmal (!) findet er eine Kollision und manchmal findet er eine Kollision wo überhaupt kein Objekt ist.
Ich vermute den Fehler mal in den Funktionen: CStartGame::ProcessMoving CStartGame::m_bCheckCollision.


Hier der (ich denke der relevante) Code:


StartGame.hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#ifndef STARTGAME_HPP
#define STARTGAME_HPP

#include <list>

#include <SDL_Framework.hpp>
#include <SDL_Sprite.hpp>
#include <SDL_Logfile.hpp>
#include <SDL_Sound.hpp>

class CStartGame
{
public:

CStartGame ();

void Render ();
void ProcessMoving ();
void CalculateFields ();

private:

void SetPos ();

float PlayerSpeed;

list<CSprite> Fields;
list<CSprite>::iterator it;

CSprite Player, PlayerDown, PlayerLeft, PlayerUp;

enum ePLAYERSTATE
{
Left=1, Right=2, Down=3, Up=4
};

ePLAYERSTATE PlayerState;

enum eCOLLISIONSTATE
{
NONE=0, LEFT=1, RIGHT=2, DOWN=3, UP=4
};

eCOLLISIONSTATE m_bCollision;
eCOLLISIONSTATE m_bCheckCollision (CSprite Sprite);

};

#endif


StartGame.cpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#include "StartGame.hpp"

CStartGame::CStartGame ():
Player("Data/Images/Player.bmp", 50.0f, 50.0f, 50, 50), PlayerDown("Data/Images/PlayerDown.bmp", 50.0f, 50.0f, 50, 50), 
PlayerLeft("Data/Images/PlayerLeft.bmp", 50.0f, 50.0f, 50 , 50), PlayerUp("Data/Images/PlayerUp.bmp", 50.0f, 50.0f, 50, 50),
PlayerState(Right),
PlayerSpeed(0.8f),
m_bCollision(NONE)
{
CalculateFields ();
}

void CStartGame::Render ()
{

// Felder Rendern
it = Fields.begin ();

while( it != Fields.end ())
{
it->Render ();

it++;

}

// Position setzten
SetPos ();

// Spieler steuern
ProcessMoving ();

// Spieler Rendern
if( PlayerState == Right )
Player.Render ();
else if ( PlayerState == Down )
PlayerDown.Render ();
else if ( PlayerState == Left )
PlayerLeft.Render ();
else if ( PlayerState == Up )
PlayerUp.Render ();

}

void CStartGame::ProcessMoving ()
{

m_bCollision = m_bCheckCollision (Player);

if( g_pFramework->KeyDown (SDLK_LEFT) && Player.fXPos > 0 && m_bCollision != LEFT )
{
Player.fXPos -= PlayerSpeed;
PlayerState = Left;

}

if( g_pFramework->KeyDown (SDLK_RIGHT) && Player.fXPos + Player.Sprite->w < g_pFramework->m_pScreen->w && m_bCollision != RIGHT )
{
Player.fXPos += PlayerSpeed;
PlayerState = Right;
}

if( g_pFramework->KeyDown (SDLK_UP) && Player.fYPos > 0 && m_bCollision != UP )
{
Player.fYPos -= PlayerSpeed;
PlayerState = Up;
}

if( g_pFramework->KeyDown (SDLK_DOWN) && Player.fYPos + Player.Sprite->h < g_pFramework->m_pScreen->h && m_bCollision != DOWN )
{
Player.fYPos += PlayerSpeed;
PlayerState = Down;
}

}




void CStartGame::CalculateFields ()
{
int XPos=0, YPos=0;

for( int i=0; i<52; i++ )
{
// Randblöcke
//

// Links
if(i == 1)
YPos = 50;
else if(i == 2)
YPos = 100;
else if(i == 3)
YPos = 150;
else if(i == 4)
YPos = 200;
else if( i == 5 )
YPos = 250;
else if( i == 6 )
YPos = 300;
else if( i == 7 )
YPos = 350;
else if( i == 8 )
YPos = 400;
else if( i == 9 )
YPos = 450;
else if( i == 10 )
YPos = 500;
else if( i == 11 )
YPos = 550;

// Oben
else if( i == 12 )
{
XPos = 50;
YPos = 0;
}
else if( i == 13 )
XPos = 100;
else if( i == 14 )
XPos = 150;
else if( i == 15 )
XPos = 200;
else if( i == 16 )
XPos = 250;
else if( i == 17 )
XPos = 300;
else if( i == 18 )
XPos = 350;
else if( i == 19 )
XPos = 400;
else if( i == 20 )
XPos = 450;
else if( i == 21 )
XPos = 500;
else if( i == 22 )
XPos = 550;
else if( i == 23 )
XPos = 600;
else if( i == 24 )
XPos = 650;
else if( i == 25 )
XPos = 700;
else if( i == 26 )
XPos = 750;

// Rechts
else if( i == 27 )
YPos = 50;
else if( i == 28 )
YPos = 100;
else if( i == 29 )
YPos = 150;
else if( i == 30 )
YPos = 200;
else if( i == 31 )
YPos = 250;
else if( i == 32 )
YPos = 300;
else if( i == 33 )
YPos = 350;
else if( i == 34 )
YPos = 400;
else if( i == 35 )
YPos = 450;
else if( i == 36 )
YPos = 500;
else if( i == 37 )
YPos = 550;

// Unten
else if( i == 38 )
XPos = 50;
else if( i == 39 )
XPos = 100;
else if( i == 40 )
XPos = 150;
else if( i == 41 )
XPos = 200;
else if( i == 42 )
XPos = 250;
else if( i == 43 )
XPos = 300;
else if( i == 44 )
XPos = 350;
else if( i == 45 )
XPos = 400;
else if( i == 46 )
XPos = 450;
else if( i == 47 )
XPos = 500;
else if( i == 48 )
XPos = 550;
else if( i == 49 )
XPos = 600;
else if( i == 50 )
XPos = 650;
else if( i == 51 )
XPos = 700;



CSprite Field("Data/Images/Block.bmp", XPos, YPos, 50, 50);

Fields.push_back (Field);
}

g_pLogfile->WriteTopic ("Spiel", 2);
g_pLogfile->Textout (BLACK, "Felder generiert!");
}


void CStartGame::SetPos ()
{

PlayerLeft.fXPos = Player.fXPos;
PlayerLeft.fYPos = Player.fYPos;

PlayerDown.fXPos = Player.fXPos;
PlayerDown.fYPos = Player.fYPos;

PlayerUp.fXPos = Player.fXPos;
PlayerUp.fYPos = Player.fYPos;

}


CStartGame::eCOLLISIONSTATE CStartGame::m_bCheckCollision (CSprite Sprite)
{


double leftA, leftB;
double rightA, rightB;
double topA, topB;
double bottomA, bottomB;


leftA = Sprite.fXPos;
rightA = Sprite.fXPos + Sprite.GetWith();
topA = Sprite.fYPos;
bottomA = Sprite.fYPos + Sprite.GetHeight();

it = Fields.begin();

while ( it != Fields.end() )
{


leftB = it->XPos;
rightB = it->XPos + it->GetWith();
topB = it->YPos;
bottomB = it->YPos + it->GetHeight();


if( bottomA <= topB )
{
return DOWN;
}

if( topA >= bottomB )
{
return UP;
}

if( rightA <= leftB )
{
return RIGHT;
}

if( leftA >= rightB )
{
return LEFT;
}
}

return NONE;
}


Das Spiel soll einer Art Pacman werden.

Danke schon mal im voraus für die Bemühungen.

C-/C++-Quelltext

1
2
    /* Keep the compiler happy */
    return(0);

2

23.08.2013, 22:09


(Link)
"Theory is when you know something, but it doesn’t work. Practice is when something works, but you don’t know why. Programmers combine theory and practice: Nothing works and they don’t know why." - Anon

Swoerm

Alter Hase

  • »Swoerm« ist der Autor dieses Themas

Beiträge: 451

Wohnort: 127.0.0.1

  • Private Nachricht senden

3

23.08.2013, 22:24

Ich verstehe nicht ganz was du meinst. ?(
Diese Abfrage funktioniert auch mein Pacman kann nicht von unten durch die "Mauer", aber die anderen Abfragen funktionieren nicht, warum sie nicht funktionieren ist mir allerdings Schleierhaft.

C-/C++-Quelltext

1
2
    /* Keep the compiler happy */
    return(0);

FSA

Community-Fossil

  • Private Nachricht senden

4

23.08.2013, 23:23

Was soll das denn? Eine grottige Zeichnung hinklatschen ohne Erklärung? Was sich manche hier rausnehmen...

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

Swoerm

Alter Hase

  • »Swoerm« ist der Autor dieses Themas

Beiträge: 451

Wohnort: 127.0.0.1

  • Private Nachricht senden

5

23.08.2013, 23:27

Wirklich weitergeholfen hat mir das jetzt auch nicht (nicht böse gemeint).

C-/C++-Quelltext

1
2
    /* Keep the compiler happy */
    return(0);

Swoerm

Alter Hase

  • »Swoerm« ist der Autor dieses Themas

Beiträge: 451

Wohnort: 127.0.0.1

  • Private Nachricht senden

6

24.08.2013, 13:47

Ich Idiot habe vergessen in CheckCollisions den iterator zu erhöhen =>i++ :dash:
peinlich... :rolleyes:
Seltsamerweise lag dort nicht der Fehler, hat irgendeiner von euch noch eine Idee. :hmm:

C-/C++-Quelltext

1
2
    /* Keep the compiler happy */
    return(0);

7

24.08.2013, 16:18

Erstmal zu den if-Bedingungen: Warum so lang und umständlich? Viel zu viel Schreibarbeit

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
if(i < 12 || (i > 26 && i < 38))
    YPos = ((i<12) ? i : (i-26)) * 50;
else if(i == 12)
{
    YPos=0;
    XPos=50;
}
else if((i < 27 && i > 12) || (i > 37 && i < 52))
    XPos = ((i < 27) ? (i-11) : (i-37)) * 50;

Nun zur Kollisionserkennung. Mals dir mal auf. Mal dir mal auf, was du überprüfen willst. Am besten danach gleich direkt, was du überprüfst. Dann gehst du das ganz stur für verschiedene Fälle durch.
Block und Bleistift bieten sich da am ehesten an, es sei denn du hast ein Grafiktablet. ^^
Ich empfehle dir jedenfalls auch mal in folgendes Video reinzuschauen:


MfG
Check

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Checkmateing« (24.08.2013, 16:30)


Swoerm

Alter Hase

  • »Swoerm« ist der Autor dieses Themas

Beiträge: 451

Wohnort: 127.0.0.1

  • Private Nachricht senden

8

24.08.2013, 17:34

Erstmal danke für den Code und das Video :thumbsup: . Ich hab den Code eingebaut mir das Video angeschaut und wie du gesagt hast es mir aufgemalt.
Nun wird allerdings gar nichts mehr erkannt. :(


Hier der Code:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "StartGame.hpp"

CStartGame::CStartGame ():
Player("Data/Images/Player.bmp", 100.0f, 100.0f, 50, 50), PlayerDown("Data/Images/PlayerDown.bmp", 50.0f, 50.0f, 50, 50), 
PlayerLeft("Data/Images/PlayerLeft.bmp", 50.0f, 50.0f, 50 , 50), PlayerUp("Data/Images/PlayerUp.bmp", 50.0f, 50.0f, 50, 50),
PlayerState(Right),
PlayerSpeed(0.8f),
m_bCollisionLeft(false), m_bCollisionRight(false), m_bCollisionTop(false), m_bCollisionBottom(false)
{
    CalculateFields ();
}

void CStartGame::Render ()
{

    // Felder Rendern
    it = Fields.begin ();

    while( it != Fields.end ())
    {
        it->Render ();
        
        it++;
    
    }

    // Position setzten
    SetPos ();

    // Spieler steuern
    ProcessMoving ();

    // Spieler Rendern
    if( PlayerState == Right )
    Player.Render ();
    else if ( PlayerState == Down )
    PlayerDown.Render ();
    else if ( PlayerState == Left )
    PlayerLeft.Render ();
    else if ( PlayerState == Up )
    PlayerUp.Render ();

}

void CStartGame::ProcessMoving ()
{

    m_bCheckCollision (Player);
    
    if( g_pFramework->KeyDown (SDLK_LEFT)  && Player.fXPos > 0 && m_bCollisionLeft )
    {
    Player.fXPos -= PlayerSpeed;
    PlayerState = Left;

    }

    if( g_pFramework->KeyDown (SDLK_RIGHT) && Player.fXPos + Player.Sprite->w < g_pFramework->m_pScreen->w && m_bCollisionRight )
    {
    Player.fXPos += PlayerSpeed;
    PlayerState = Right;
    }

    if( g_pFramework->KeyDown (SDLK_UP) && Player.fYPos > 0 && m_bCollisionTop )
    {
        Player.fYPos -= PlayerSpeed;
        PlayerState = Up;
    }

    if( g_pFramework->KeyDown (SDLK_DOWN) && Player.fYPos + Player.Sprite->h < g_pFramework->m_pScreen->h && m_bCollisionBottom )
    {
        Player.fYPos += PlayerSpeed;
        PlayerState = Down;
    }

}




void CStartGame::CalculateFields ()
{
    int XPos=0, YPos=0;

    for( int i=0; i<52; i++ )
    {
            // Randblöcke
            //
            if(i < 12 || (i > 26 && i < 38))
            YPos = ((i<12) ? i : (i-26)) * 50;
            else if(i == 12)
            {
            YPos=0;
            XPos=50;
            }
            else if((i < 27 && i > 12) || (i > 37 && i < 52))
            XPos = ((i < 27) ? (i-11) : (i-37)) * 50;

    CSprite Field("Data/Images/Block.bmp", XPos, YPos, 50, 50);

    Fields.push_back (Field);
    }

    g_pLogfile->WriteTopic ("Spiel", 2);
    g_pLogfile->Textout (BLACK, "Felder generiert!");
}


void CStartGame::SetPos ()
{

    PlayerLeft.fXPos = Player.fXPos;
    PlayerLeft.fYPos = Player.fYPos;

    PlayerDown.fXPos = Player.fXPos;
    PlayerDown.fYPos = Player.fYPos;

    PlayerUp.fXPos = Player.fXPos;
    PlayerUp.fYPos = Player.fYPos;

}


void CStartGame::m_bCheckCollision (CSprite Sprite)
{


    double leftA, leftB;
    double rightA, rightB;
    double topA, topB;
    double bottomA, bottomB;
    
    leftA = Sprite.fXPos;
    rightA = Sprite.fXPos + Sprite.GetWith();
    topA = Sprite.fYPos;
    bottomA = Sprite.fYPos + Sprite.GetHeight();

    it = Fields.begin();

    while ( it != Fields.end() )
    {

        
        leftB = it->XPos;
        rightB = it->XPos + it->GetWith();
        topB = it->YPos;
        bottomB = it->YPos + it->GetHeight();
    
 
    if( rightB>leftA )
        m_bCollisionLeft = true;
    if( rightA>leftB )
        m_bCollisionRight = true;
    if( bottomB>topA )
        m_bCollisionTop = true;
    if( topB<bottomA )
        m_bCollisionBottom = true;

    it++;

    }
}

C-/C++-Quelltext

1
2
    /* Keep the compiler happy */
    return(0);

9

24.08.2013, 17:59

Jo.
Kleine Anmerkung: Relevant ist nur void CStartGame::m_bCheckCollision (CSprite Sprite)
Ich empfehle btw mal die Funktion von der ("fehlerhaften") ungarischen Notation zu befreien. :)
Du hast es also gezeichnet? Sieht mir nicht danach aus. Überleg doch mal! Debugge auch mal!
Hier mal ein Fallbeispiel für deine erste if-Bedingung:

(Link)
Jedoch keine Kollision!
Schau dir das Video noch einmal an. Dort ist nicht davon die Rede, dass eine Kollision stattfindet, wenn eine Bedingung richtig ist, sondern vier richtig sind.
Du möchtest ja auch wissen wo es kollidiert. Vergiss das und versuche erst einmal es so zu machen, dass es kollidiert. Wenn dann eine Kollision stattfand und nur wenn eine stattfand, sonst nicht, kannst du Nacharbeit leisten und erkennen lassen, wo es kollidierte. Das sollte mit deinem jetzigem Code schon stattfinden, zumindest das Erkennen, wie die Rechtecke zueinander stehen.

MfG
Check

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Checkmateing« (24.08.2013, 19:06)


Swoerm

Alter Hase

  • »Swoerm« ist der Autor dieses Themas

Beiträge: 451

Wohnort: 127.0.0.1

  • Private Nachricht senden

10

24.08.2013, 19:54

Hab's jetzt in einem Koordinatensystem aufgezeichnet und mal für beide Rechtecke die Werte (left, right etc.) ausgerechnet und wollte fragen ob das jetzt so stimmt (Datei im Anhang).
»Swoerm« hat folgendes Bild angehängt:
  • Whiteboard.JPG

C-/C++-Quelltext

1
2
    /* Keep the compiler happy */
    return(0);

Werbeanzeige