Collision detection problem

Hi guys,

I'm having problems with collision detection in SDL, the ball seems to get stuck sometimes when I move the ball down and immediately after when I hit the down arrow key the ball down seems to go through the wall(which I don't want)

I've spent 3 hours trying to wrap my head around this trivial problem,

any hints to what it might be??

**Note the important functions are ballMove() and collision()

thanks


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

#include <iostream>
#include <vector>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

using namespace std;

vector<SDL_Texture*> players;

SDL_Window *window;
SDL_Renderer *renderer;

SDL_Texture *ball;
SDL_Texture *wall;
SDL_Surface* ballTemp;
SDL_Surface* wallTemp;

SDL_Rect* ballRecSrc;
SDL_Rect* ballRecDst;
SDL_Rect* wallRecSrc;
SDL_Rect* wallRecDst;

SDL_Event event;
const int SCREEN_WIDTH = 670;
const int SCREEN_HEIGHT = 600;

bool ballUp,ballDown,ballLeft,ballRight;
bool isCollisionUp,isCollisionDown;
int PlayerCount = 0;

bool gameInit(){

   if(SDL_Init(SDL_INIT_EVERYTHING) < 0){

     cout << "error" << endl;
     return false;
   }
   if(IMG_Init(IMG_INIT_PNG) < 0){

     cout << "error" << endl;
     return false;
   }

    window = SDL_CreateWindow("The GTG game",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,SCREEN_WIDTH,SCREEN_HEIGHT,SDL_WINDOW_RESIZABLE);
    renderer = SDL_CreateRenderer(window,-1,0);
  
    ballTemp = IMG_Load("BALL.png");
    wallTemp = IMG_Load("WALL.png");

    
    ball = SDL_CreateTextureFromSurface(renderer,ballTemp);
    wall = SDL_CreateTextureFromSurface(renderer,wallTemp);

    SDL_SetRenderDrawColor(renderer,255,255,255,255);
    
    ballRecDst = new SDL_Rect;
    wallRecDst = new SDL_Rect;

    ballRecDst->h = 80;
    ballRecDst->w = 80;
    ballRecDst->x = 450;
    ballRecDst->y = 0;

    wallRecDst->h = 90;
    wallRecDst->w = 95;
    wallRecDst->x = 500;
    wallRecDst->y = 100;

    ballUp = false;
    ballDown = true;
    ballLeft = false;
    ballRight = false;
    isCollisionUp = false;
    isCollisionDown = false;

    return true;
}

void render(){

  SDL_RenderClear(renderer);


  SDL_RenderCopy(renderer,ball,NULL,ballRecDst);
  SDL_RenderCopy(renderer,wall,NULL,wallRecDst);
  for(int i = 0; i < players.size(); i++){
  SDL_RenderCopy(renderer,players.at(i),NULL,destRecs.at(i));
  }

  SDL_RenderPresent(renderer);
}

void updateScreen(){

   for(int i = 0; i < destRecs.size();i++){

   if(destRecs.at(i)->y > SCREEN_HEIGHT-destRecs.at(i)->h){

       up[i] = true;
       down[i] = false;
   }
   if(destRecs.at(i)->y < 1){

       up[i] = false;
       down[i] = true;
   }
   if(down[i]){

   destRecs.at(i)->y += 5;
   SDL_Delay(5);
   }
   if(up[i]){

     destRecs.at(i)->y -= 5;
     SDL_Delay(5);
  }
   }
}



bool collision(){

  if(ballRecDst->y + ballRecDst->h <= wallRecDst->y){
    cout << "3::  :::: false" << endl;
    return false;
  }
//  if(ballRecDst->x >= wallRecDst->x + wallRecDst->w)  commented out lines 
//    return false;                                                     commented out until I get top and bottom working
//  if(ballRecDst->x + ballRecDst->w <= wallRecDst->x)
//    return false;
  if(ballRecDst->y >= wallRecDst->y + wallRecDst->h -10){
    cout << " 3:: low false" << endl;
    return false;
  }

  if(ballUp){
    cout << " 3:: COLLISION: UP" << endl;
    isCollisionUp = true;
  }
  if(ballDown){

    isCollisionDown = true;
  }

  return true;
}

void ballMove(){


      if(ballRecDst->y == SCREEN_HEIGHT - ballRecDst->h){

        ballDown = false;
        ballUp = true;
      }
      if(ballRecDst->y == 0){

        ballDown = true;
        ballUp = false;
      }
      if(ballRecDst->x == 0){

         ballLeft = false;
         ballRight = true;
      }
      if(ballRecDst->x > SCREEN_WIDTH-ballRecDst->w){


         ballRight = false;
         ballLeft = true;
      }


      if(ballDown){

      if(collision() && !isCollisionUp && isCollisionDown){

          cout << "4:: down colission" << endl;
          ballDown = false;
          ballUp = true;
          ballRecDst->y-=10;
          isCollisionDown = false;

          return;
      }

      ballRecDst->y+=5;
      }

      if(ballUp){

        if(collision() && !isCollisionDown){

            ballUp = false;
            ballDown = true;
            cout << "4 :: up collison" << endl;

            return;


        }

        cout << "ball up" << endl;

        ballRecDst->y-=5;
      }
      if(ballLeft){

        ballRecDst->x-=5;
      }
      if(ballRight){

        ballRecDst->x+=5;
      }

}
Last edited on
Too much code to unravel right this moment.

but consider these statements.
- if your collision detection only checks if your ball is touching your wall
- if your ball speed is greater than 1 ball diameter per iteration
- it is possible for the ball to go from one side of a wall to another in 1 iteration without touching it.

is that something your code might allow to happen? If so, the faster it moves, the more trouble you will have. To fix it, you can check to see which side of the wall it is on, and if that changes, you missed a collision and need to do something.

collision detection is the bane of graphics I think. Ive seen countless professional quality games where stuff clips into other objects. You are not alone, its a complicated topic.
Last edited on
First a note: you can have only one ball. That is a limit that you have set yourself. An unnecessary limit, even if you stay with one ball.


If you have the distance between wall and ball, then you can see whether the ball can move a whole D, or will it hit the wall before.
hi guys thanks for the replies :)

If you have the distance between wall and ball, then you can see whether the ball can move a whole D, or will it hit the wall before.


I'm misunderstanding,D stand for direction? but lets say my ball's y+h value is at 80 when it starts off(this will always hold in my case) and the walls y value will always be 100 so lets say I move down a few places (seems to always get stuck at when the balls y +h value is 105)

so 105 is greater than or equal to wall's y value 100,so my collision function returns true and since the down key was pressed last before it returns true it will set isCollisionDown to true.

So now the ball should not go down any further(and it doesn't) but next after I press the up key to bring the ball back up the ball does NOT go back up,instead gets stuck and the only way I can move the ball is downwards so then the ball goes straight through the wall,this should not happen.

so I traced my steps back lets say the collision position is at 105 at this point isCollisionDown is set to true and isCollisionUp is set to false,so in the ballMove() function the if(collision() && !isCollisionUp && isCollisionDown) gets executed, I set ballDown to false and ballUp to true so the ball can only be moved upwards immediately after I set the balls y position minus 10 so this will now give the ball y+h = 95(ballRecDst->y-=10;). I then set isCollisionDown back to false and the function returns.

now again If I press the up key the ballRecDst is at 95(or should be at 95 but my debugging statements still tell me its at 105) ballUp gets set to true and all the other bools down,right,left get set to false,now the ballMove() function gets called (I will include the code that calls the ballMove() function below) the ballUp condition is if statement is executed in the ballMove() function the nested if condition calls collision() to check for a collision since 95 is less than 95 it should return false hence this nested if statement is not executed,next I move the ball back up 5 places and the function ends.

so I can't see where my logic has gone wrong?


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


int SDL_main(int argc,char* argv[])
{

   bool quit = false;

   cout << "to add a new character press the down key" << endl;

   gameInit();

   while(!quit){

    SDL_PollEvent(&event);
    if(event.type == SDL_QUIT){

        quit = true;
    }


        if(event.type == SDL_KEYDOWN)
        {
            cout << " 1:: ball y + h : " <<  ballRecDst->y + ballRecDst->h << endl;
            cout << " 2:: wall y  : " << wallRecDst->y << endl;
            switch(event.key.keysym.sym)
            {

            case SDLK_DOWN:
                cout << "down" << endl;
                ballUp = false;
                ballLeft = false;
                ballRight = false;
                ballDown = true;
                ballMove();
                break;
            case SDLK_UP:
                cout << "up" << endl;
                ballDown = false;
                ballLeft = false;
                ballRight = false;
                ballUp = true;
                ballMove();
                break;
            case SDLK_LEFT:
                cout << "left" << endl;
                ballDown = false;
                ballUp = false;
                ballRight = false;
                ballLeft = true;
                ballMove();
                break;
            case SDLK_RIGHT:
                cout << "right" << endl;
                ballDown = false;
                ballUp = false;
                ballLeft = false;
                ballRight = true;
                ballMove();
                break;
            case SDLK_0:
                PlayerCount++;
                createPlayer();
                break;

            default:
                break;
            }
        }

    updateScreen();
    render();
   }
}


Last edited on
Ok guys fixed the bug (for now) it seems like the ball now responds to collision detection when SDL_Rect(ball) hits the other SDL_Rect(the ball) the ball bounces off the wall ,

the reason for the bug was I incremented and decremented after the collision detection I should have incremented and decremented before the collision detection then when a collision was detected increment or decrement the balls position

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

void ballMove()
{

    // these 4 ifs are for bounds checking

    if(ballRecDst->y == SCREEN_HEIGHT - ballRecDst->h)
    {

        ballDown = false;
        ballUp = true;
    }
    if(ballRecDst->y == 0)
    {

        ballDown = true;
        ballUp = false;
    }
    if(ballRecDst->x == 0)
    {

        ballLeft = false;
        ballRight = true;
    }
    if(ballRecDst->x > SCREEN_WIDTH-ballRecDst->w)
    {

        ballRight = false;
        ballLeft = true;
    }

    if(ballDown)
    {

        ballRecDst->y+=5;
        cout << " 1:: ball y + h(before pressed)): " <<  ballRecDst->y  + ballRecDst->h << endl;

        if(collision() && !isCollisionUp && isCollisionDown)
        {

            cout << "4:: down colission" << endl;
            ballDown = false;
            ballUp = true;
            ballRecDst->y-=10;
            isCollisionDown = false;
            return;
        }
    }

    if(ballUp)
    {

        ballRecDst->y-=5;
        cout << " 1:: ball y + h(after pressed)): " <<  ballRecDst->y  + ballRecDst->h << endl;

        if(collision() && !isCollisionDown && isCollisionUp)
        {

            ballUp = false;
            ballDown = true;
            cout << "4 :: up collison" << endl;
            ballRecDst->y+=10;
            isCollisionUp = false;
            return;
        }

        cout << "ball up" << endl;

    }
    if(ballLeft)
    {


        ballRecDst->x-=5;
    }
    if(ballRight)
    {

        ballRecDst->x+=5;

        if(collision() && isCollisionRight)
        {

            ballRight = false;
            ballLeft = true;
            ballRecDst->x-=10;
            isCollisionRight = false;
        }
    }
}
Last edited on
Lets assume that one step (D) is 10 and wall-ball-distance < 5 is "collision".

Start state: ball is 7 above wall and going down.

Approach A:
1. There is no collision
2. Move down by 10
3. Ball is now 3 below the wall

Approach B:
1. Move down by 10
2. There is collision: ball is now 3 below the wall

Approach C:
1. Distance is 7. 7 is less than 10
2. If the ball would move down, it would have 10-7=3 movement left on contact
3. Update ball position to 3 above the wall and set direction "up"
Topic archived. No new replies allowed.