Отслеживам столкновения двух круглых областей в SDL

Эта статья наврядли научит вас правильно отслеживать столкновения, ведь спрайты редко бывают идеально круглыми..
.. но сейчас представим что в мире всё иначе и спрайты действительно только в форме круга.

Не буду описывать стандартные для sdl функции. Можете поискать информацию о них на єтом сайте ;)

Для отслеживания столкновения нужно ещё и считать:

#include <SDL/SDL.h>
#include <cmath>

Зададим размер и заголовок константами:

const int WINDOW_WIDTH = 640;
const int WINDOW_HEIGHT = 480;
const char* WINDOW_TITLE = "SDL HOWTO";

Оприделим функцию для обработки столкновений:

bool box(SDL_Rect one,SDL_Rect two);

В функции main:

int main(int argc, char **argv){

Стандартно для SDL приложения (подробнее в предыдущих статьях):

SDL_Init( SDL_INIT_VIDEO );
    SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH,
    WINDOW_HEIGHT, 0,
    SDL_HWSURFACE | SDL_DOUBLEBUF );
    SDL_WM_SetCaption( WINDOW_TITLE, 0 );
    SDL_ShowCursor(SDL_DISABLE);
    SDL_Surface* bitmap = SDL_LoadBMP("sprite.bmp");
    SDL_SetColorKey( bitmap, SDL_SRCCOLORKEY, SDL_MapRGB(bitmap->format,0, 0, 0) );

SDL_Rect source;
source.x = 0;
source.y = 0;
source.w = 120;
source.h = 120;

Всё также в цикле ожидания действий:

SDL_Event event;
bool run = true;
while(run) {
    while ( SDL_PollEvent(&event) ) {
        switch (event.type) {
            case SDL_MOUSEMOTION:
                    SDL_Rect fill;
                    fill.x = 0;
                    fill.y = 0;
                    fill.w = WINDOW_WIDTH;
                    fill.h = WINDOW_HEIGHT;
                    SDL_FillRect(screen,&fill,SDL_MapRGB(bitmap->format,0, 0, 0) );

                    SDL_Rect destination;
                    destination.x = event.motion.x - 60;
                    destination.y = event.motion.y - 60;
                    destination.w = 120;
                    destination.h = 120;  

После этого начинаются немного новые вещи:

Рисуем круг "враг". Он будет стоять на месте:

SDL_Rect target;
target.x = 100;
target.y = 100;
target.w = 120;
target.h = 120; 
SDL_BlitSurface(bitmap, &source, screen, &target);

Пользуемся нашей функцией для определения столкновения:

if (!box(destination,target)) {
                    SDL_BlitSurface(bitmap, &source, screen, &destination);
                    SDL_Flip(screen);
            }

Дальше опять всё стандартно:

 break;
            case SDL_QUIT:
                run = false;
        }
    }
    }
    SDL_FreeSurface(bitmap);
    SDL_Quit();
    return 0;
}

Старался не пропускать ничего, такчто извените за такие куски кода.

Теперь остановимся на функции box:

bool box(SDL_Rect one,SDL_Rect two) {
    int oneX,oneY,twoX,twoY;
    oneX = one.x + one.w/2;
    oneY = one.y + one.h/2;
   
    twoX = two.x + two.w/2;
    twoY = two.y + two.w/2;
   
    int width1 = one.w/2;
    int width2 = two.w/2;
    int rad = width1 + width2; //сумма радиусов
    int rad2 = sqrt(pow((oneX - twoX),2)+(pow((oneY - twoY),2)));  //расстояние между центрами
    if (rad > rad2)
        return true;
    else
        return false;
        printf("%d :: %d\n",rad,rad2    );
}

Её суть в том, что объекты (круги) сталкиваются если расстояние между их центрами (красный) меньше суммы их радиусов (синий/чёрный).

Будем считать, что радиус спрайта равен половине его ширины (width1 и width2), а центр находится путём добавления половины ширины спрайта к его Х координате и высоты к Y.
После нахождения координат центров находим расстояние между ними по школьной формулe:


В случае если объекты пересекаются будет возвращено true, иначе false.

Учтите, что это очень простая функция и вести себя адекватно она будет только с круглыми спрайтами и только при условии, что они касаются краями граници (тоесть ширина = 2 радиуса). В других условиях процедура похожа, но необходимо считать не радиусы, а ту часть спрайта (прямоугольника) которая является картинкой, а не пустым местом...

Скачать пример

Просмотров:   2114