Tabrakan Lingkaran dan Persegi

Jika sebelumnya saya pernah membahas tentang cara mengecek tabrakan antara dua lingkaran dan dua persegi, sekarang saya akan membahas tentang cara  mengecek tabrakan lingkaran dan persegi / persegi panjang.

Pertama, kita akan membuat struct untuk menyimpan informasi tentang lingkaran. Struct tersebut berisi informasi tentang jari-jari, koordinat x dan y dari lingkaran. Untuk persegi atau persegi panjangnya, kalian bisa menggunakan SDL_Rect.
struct Lingkaran{
    int x;
    int y;
    int r;
};
Setelah membuat struct-nya, kita akan buat function untuk mengecek tabrakannya. Parameter function tersebut menggunakan pointer struct yang sudah kita buat di atas.
int cekTabrakan(Lingkaran *lk, SDL_Rect *rct){
int tabrakan=0;
int jarak, x, y, r, tmp;
    r=lk->r;

    if(lk->x > rct->x && lk->x < rct->x+rct->w){
        //jika lingkaran ada di atas atau di bawah garis sisi persegi
        tmp=rct->h/2;
        jarak=abs(rct->y+tmp-lk->y);
        if(tmp+r > jarak)tabrakan=1;
    }else if(lk->y > rct->y && lk->y < rct->y+rct->h){
        //jika lingkaran ada di kiri atau di kanan garis sisi persegi
        tmp=rct->w/2;
        jarak=abs(rct->x+tmp-lk->x);
        if(tmp+r > jarak)tabrakan=1;
    }else{
        x=lk->x-rct->x;
        y=lk->y-rct->y;
        jarak=x*x+y*y;
        if(jarak < r*r)tabrakan = 1;
 
        x=lk->x-(rct->x+rct->w);
        y=lk->y-rct->y;
        jarak=x*x+y*y;
        if(jarak < r*r)tabrakan = 1;
     
        x=lk->x-(rct->x);
        y=lk->y-(rct->y+rct->h);
        jarak=x*x+y*y;
        if(jarak < r*r)tabrakan = 1;
 
        x=lk->x-(rct->x+rct->w);
        y=lk->y-(rct->y+rct->h);
        jarak=x*x+y*y;
        if(jarak < r*r)tabrakan = 1;
    }

    return tabrakan;
}
Function untuk mengecek tabrakan tersebut mungkin cukup panjang. Tapi, kalau kalian mau menganalisanya, kalian akan bisa memahami cara kerjanya. Kita menggunakan tiga if untuk tiga kemungkinan posisi yang berbeda. Posisi pertama adalah saat titik pusat lingkaran ada di atas atau di bawah sisi persegi. Posisi kedua adalah saat titik pusat lingkaran ada di kiri atau di kanan sisi persegi. Else digunakan jika lingkaran berada di bagian diagonal persegi.

Selanjutnya, kita akan satukan function dengan kode program utamanya. Kita juga akan menggunakan function untuk menggambar lingkaran yang pernah saya tulis sebelum ini. Kode program di bawah ini akan menampilkan persegi dan lingkaran yang akan berubah warna saat bertabrakan dan berpisah.
#include <SDL2/SDL.h>
#include <math.h>
#define playar 640
#define tlayar 480

SDL_Renderer *trender=NULL;
struct Lingkaran{
    int x;
    int y;
    int r;
};

int cekTabrakan(Lingkaran *lk, SDL_Rect *rct){
int tabrakan=0;
int jarak, x, y, r, tmp;
    r=lk->r;

    if(lk->x > rct->x && lk->x < rct->x+rct->w){
        //jika lingkaran ada di atas atau di bawah garis sisi persegi
        tmp=rct->h/2;
        jarak=abs(rct->y+tmp-lk->y);
        if(tmp+r > jarak)tabrakan=1;
    }else if(lk->y > rct->y && lk->y < rct->y+rct->h){
        //jika lingkaran ada di kiri atau di kanan garis sisi persegi
        tmp=rct->w/2;
        jarak=abs(rct->x+tmp-lk->x);
        if(tmp+r > jarak)tabrakan=1;
    }else{
        x=lk->x-rct->x;
        y=lk->y-rct->y;
        jarak=x*x+y*y;
        if(jarak < r*r)tabrakan = 1;
 
        x=lk->x-(rct->x+rct->w);
        y=lk->y-rct->y;
        jarak=x*x+y*y;
        if(jarak < r*r)tabrakan = 1;
     
        x=lk->x-(rct->x);
        y=lk->y-(rct->y+rct->h);
        jarak=x*x+y*y;
        if(jarak < r*r)tabrakan = 1;
 
        x=lk->x-(rct->x+rct->w);
        y=lk->y-(rct->y+rct->h);
        jarak=x*x+y*y;
        if(jarak < r*r)tabrakan = 1;
    }

    return tabrakan;
}

int warnai_lingkaran(SDL_Renderer *trender, int xpos, int ypos, int r){
int tx, ty, i;
    for(i=0;i<r;i++){
        tx=i;
        ty=sqrt(r*r-i*i);
        SDL_RenderDrawLine(trender, xpos+tx, ypos+ty, xpos+tx, ypos-ty);
        SDL_RenderDrawLine(trender, xpos-tx, ypos+ty, xpos-tx, ypos-ty);
    }
    return 0;
}

int gambar_lingkaran(SDL_Renderer *trender, int xpos, int ypos, int r){
int tx1, ty1, tx2, ty2, i;
    for(i=0;i<r;i++){
        tx1=i;
        ty1=sqrt(r*r-tx1*tx1);
 
        tx2=i+1;
        ty2=sqrt(r*r-tx2*tx2);
        SDL_RenderDrawLine(trender, xpos+tx1, ypos+ty1, xpos+tx2, ypos+ty2);
        SDL_RenderDrawLine(trender, xpos-tx1, ypos+ty1, xpos-tx2, ypos+ty2);
        SDL_RenderDrawLine(trender, xpos+tx1, ypos-ty1, xpos+tx2, ypos-ty2);
        SDL_RenderDrawLine(trender, xpos-tx1, ypos-ty1, xpos-tx2, ypos-ty2);
    }
    return 0;
}

int main(int argc, char* args[]){
    SDL_Window* window = NULL;
    SDL_Event evt;
    Lingkaran lk;
    SDL_Rect rct, garis;
    
    rct.x=playar/3;
    rct.y=tlayar/3;
    rct.w=rct.x;
    rct.h=rct.y;
 
    garis.x=rct.x;
    garis.y=rct.y;
    garis.w=rct.w;
    garis.h=rct.h;
 
    lk.r=rct.y/2;
    lk.x=rct.x+(rct.x/2);
    lk.y=rct.y+(rct.y/2);

    if( SDL_Init( SDL_INIT_VIDEO ) < 0){
        printf( "Error: %s\n", SDL_GetError() );
    }else{
        window = SDL_CreateWindow( "SDLku", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, playar, tlayar, SDL_WINDOW_SHOWN );
        if( window == NULL ){
            printf( "Error : %s", SDL_GetError() );
        }else{
            trender = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
            
            while(evt.type!=SDL_QUIT){
                while(SDL_PollEvent(&evt)){
                    if(evt.type==SDL_KEYDOWN){
                        switch(evt.key.keysym.sym){
                            case SDLK_a:
                                rct.x-=2;
                                break;
                            case SDLK_d:
                                rct.x+=2;
                                break;
                            case SDLK_s:
                                rct.y+=2;
                                break;
                            case SDLK_w:
                                rct.y-=2;
                                break;
                            case SDLK_LEFT:
                                lk.x-=2;
                                break;
                            case SDLK_RIGHT:
                                lk.x+=2;
                                break;
                            case SDLK_DOWN:
                                lk.y+=2;
                                break;
                            case SDLK_UP:
                                lk.y-=2;
                                break;
                    
                        }
                    }

                    SDL_SetRenderDrawColor(trender, 0xFF, 0xFF, 0xFF, 0xFF);
                    SDL_RenderClear(trender);
            
                    if(cekTabrakan(&lk, &rct)!=0)SDL_SetRenderDrawColor(trender, 0x00, 0x00, 0xFF, 0xFF);
                    else SDL_SetRenderDrawColor(trender, 0x88, 0xFF, 0x00, 0xFF);
                    SDL_RenderFillRect(trender, &rct);
      
      
                    SDL_SetRenderDrawColor(trender, 0xFF, 0x00, 0x00, 0xFF);
                    warnai_lingkaran(trender, lk.x, lk.y, lk.r);
      
                    SDL_SetRenderDrawColor(trender, 0xFF, 0xFF, 0x00, 0xFF);
                    SDL_RenderDrawLine(trender, garis.x, 0, garis.x, tlayar);
                    SDL_RenderDrawLine(trender, garis.x+rct.w, 0, garis.x+garis.w, tlayar);
                    SDL_RenderDrawLine(trender, 0, garis.y, playar, garis.y);
                    SDL_RenderDrawLine(trender, 0, garis.y+garis.h, playar, garis.y+garis.h);
                    
                    SDL_RenderPresent(trender);
                }
            }
        }
    }

    SDL_DestroyWindow( window );
    SDL_Quit();

    return 0;
}

Coba gunakan tombol w, s, a, d, atau tombol panah untuk menggerakkan persegi atau lingkarannya. Saat lingkaran dan persegi bertabrakan, persegi panjang warnanya akan berbeda jika dibandingkan dengan saat keduanya sudah tidak saling menempel.