Saturday, 26 December 2009

SDL : Deteksi Tabrakan (1)

Hal yang paling vital dalam banyak program game adalah deteksi tabrakan/tubrukan. Dimana satu atau lebih objek bersentuhan secara visual, dan teknik yang paling mudah adalah dengan bentuk kotak (box). Berikut ini contoh program yang akan mengimplementasikannya :

/*
Source Code ini merupakan modifikasi
dari template SDL Code::Blocks dan
Source Code ini adalah bahan/materi
untuk blog:

http://membuatgamedengancpp.blogspot.com/

*/
#ifdef __cplusplus
    #include <cstdlib>
#else
    #include <stdlib.h>
#endif
#ifdef __APPLE__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
#include <string>

const int lebar_layar = 640;
const int tinggi_layar = 480;

/*membuat fungsi untuk memeriksa terjadinya tabrakan (collision)
    antara kotak pertama (A) dengan kotak kedua (B)
*/
bool f_PeriksaTabrakan(SDL_Rect A, SDL_Rect B)
{
    int kiriA, kiriB;
    int kananA, kananB;
    int atasA, atasB;
    int bawahA, bawahB;

    kiriA = A.x;
    kananA = A.x + A.w;
    atasA = A.y;
    bawahA = A.y + A.h;

    kiriB = B.x;
    kananB = B.x + B.w;
    atasB = B.y;
    bawahB = B.y + B.h;

    if (bawahA <= atasB) return false;
    if (atasA >= bawahB) return false;
    if (kananA <=kiriB) return false;
    if (kiriA >=kananB) return false;

    return true;
}

//clsKotak = class Kotak
class clsKotak
{
    SDL_Rect kotak;
    int red,green,blue;
    int kecX, kecY;

public:
    clsKotak(int,int,int,int,int);
    SDL_Rect getKotak();
    void bergerak(int,SDL_Rect O_[]);
    void tampil(SDL_Surface *_O);
};

//konstruktor kelas kotak
clsKotak::clsKotak(int _red, int _green, int _blue, int _X, int _Y)
{
    //variabel red, green, blue (rgb) untuk
    //membedakan warna dengan kotak yang lain
    red = _red;

    //diperiksa nilainya jika ada kesalahan
    if( red < 0) red = 0;
    else if( red > 255) red = 255;

    green = _green;
    if( green < 0 ) green = 0;
    else if( green > 255) green = 255;

    blue = _blue;
    if( blue < 0 ) blue = 0;
    else if( blue > 255) blue = 255;

    kecX = 5+_X%3;
    kecY = 5+_Y%3;

    kotak.x = _X;
    kotak.y = _Y;
    kotak.w = 20;
    kotak.h = 20;
}

SDL_Rect clsKotak::getKotak()
{
    return kotak;
}

void clsKotak::bergerak(int banyakKotak, SDL_Rect kotakLainnya[])
{
    //menggerakan kotak dengan sumbu x
    kotak.x += kecX;

    //memeriksa apakah sih kotak masih ada dilayar
    //atau sudah keluar dari layar
    if( kotak.x < 0){
        kotak.x = 0;
        kecX = -kecX;
    }
    else if( kotak.x + kotak.w > lebar_layar){
        kotak.x = lebar_layar - kotak.w;
        kecX = -kecX;
    }

    //pemeriksaan terhadap kotak lainnya
    for(int c=0;c<banyakKotak;c++)
    {
        if( f_PeriksaTabrakan( kotak, kotakLainnya[c]))
        {
            kecX = -kecX;
            kotak.x += kecX;
            break;
        }
    }

    //kali ini bergerak searah dengan sumbu Y
    kotak.y += kecY;

    if( kotak.y < 0){
        kotak.y = 0;
        kecY = -kecY;
    }
    else if( kotak.y + kotak.h > tinggi_layar){
        kotak.y = tinggi_layar - kotak.h;
        kecY = -kecY;
    }

    //pemeriksaan terhadap kotak lainnya
    for(int c=0;c<banyakKotak;c++)
    {
        if( f_PeriksaTabrakan( kotak, kotakLainnya[c]))
        {
            kecY = -kecY;
            kotak.y += kecY;
            break;
        }
    }
}

void clsKotak::tampil(SDL_Surface *_screen)
{
    red+=rand()%5;
    if( red>220) red = 0;

    green+=rand()%7;
    if( green>220) green = 0;

    blue+=rand()%9;
    if( blue>220) blue = 0;

    //warna diisi sesuai dengan variabel red, green, blue
    SDL_FillRect( _screen, &kotak, SDL_MapRGB( _screen->format, red, green, blue));
}

int main ( int argc, char** argv )
{
    srand((unsigned)time(NULL));

    // initialize SDL video
    if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "Unable to init SDL: %s\n", SDL_GetError() );
        return 1;
    }

    // make sure SDL cleans up before exit
    atexit(SDL_Quit);

    // create a new window
    SDL_Surface* screen = SDL_SetVideoMode(lebar_layar, tinggi_layar, 16,
                                           SDL_HWSURFACE|SDL_DOUBLEBUF);
    if ( !screen )
    {
        printf("Unable to set 640x480 video: %s\n", SDL_GetError());
        return 1;
    }

    //bykKotak = banyak Kotak
    const int bykKotak = 50;
    clsKotak *kotakKu[bykKotak];
    for( int c=0;c<bykKotak;c++){
        int X = c*30%(lebar_layar-40);
        kotakKu[c] = new clsKotak(c*200%255,150,c*100%255,X,c*2);
    }

    //membuat variabel fps (frame per second)
    //dan jumlah frame setiap detiknya adalah 24
    int fps = 0;
    const int frame_per_second = 24;

    // program main loop
    bool done = false;
    while (!done)
    {
        //memperoleh sekian milidetik dari SDL_GetTicks()
        fps = SDL_GetTicks();

        // message processing loop
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            // check for messages
            switch (event.type)
            {
                // exit if the window is closed
            case SDL_QUIT:
                done = true;
                break;

                // check for keypresses
            case SDL_KEYDOWN:
                {
                    // exit if ESCAPE is pressed
                    if (event.key.keysym.sym == SDLK_ESCAPE)
                        done = true;
                    break;
                }
            } // end switch
        } // end of message processing

        // DRAWING STARTS HERE

        // clear screen
        SDL_FillRect(screen, 0, SDL_MapRGB(screen->format,255,255,255));

        for( int b=0;b<bykKotak;b++){
            //_ktkLain = kotak lainnya
            SDL_Rect _ktkLain[bykKotak];
            for( int c=0;c<bykKotak;c++){
                if( c != b){
                    _ktkLain[c] = kotakKu[c]->getKotak();
                }
                else{
                    _ktkLain[c].x=0;
                    _ktkLain[c].y=0;
                    _ktkLain[c].w=0;
                    _ktkLain[c].h=0;
                }
            }

            kotakKu[b]->bergerak(bykKotak,_ktkLain);
        }

        for( int c=0;c<bykKotak;c++){
            kotakKu[c]->tampil(screen);
        }

        // DRAWING ENDS HERE

        // finally, update the screen :)
        SDL_Flip(screen);

        //perhitungan frame rate
        int getDetik = SDL_GetTicks() - fps;
        if( getDetik<(1000/frame_per_second)){
            SDL_Delay((1000/frame_per_second) - getDetik);
        }

    } // end main loop

    for( int c=0;c<bykKotak;c++){
        delete kotakKu[c];
    }

    // all is well ;)
    printf("Exited cleanly\n");
    return 0;
}

// - krofz
Atau download file dibawah ini yang berisi project (Code::Blocks) program diatas dan
hasil build/kompilasi-nya:

Link : http://www.mediafire.com/?nrki2l896hba2vs
Size : 132.17 KB

Program diatas nggak perlu gambar yang aneh-aneh dalam proses "Drawing-nya", cuma memanfaatkan "SDL_FillRect()" dan "SDL_Rect (ini yang penting)". Kotak-kotak tersebut akan memantul setelah tertabrak dengan kotak lain atau ingin keluar dari layar. Buat yang masih bingung , nanti penjelasan lengkapnya nyusul yah... hahaha....

Next Part 2
Update 18 April 2013
- krofz

12 comments:

  1. Mas, Linknya File not Found.

    :)

    ReplyDelete
  2. Ok, ini link barunya... http://www.ziddu.com/download/17035265/14_Deteksi_Tabrakan.7z.html - 132.17 KB

    :)

    belom bisa update artikelnya.. net dirumah lagi lelet... xD

    ReplyDelete
  3. Oh, ok.. thank you...

    ReplyDelete
  4. pas di jalanin kod ada error di header #include?
    trus headernya semua itu buat apa ya? bsa tolong di jelasin?

    ReplyDelete
    Replies
    1. Pastikan saat compile / build yang dijalankan adalah file project-nya (.cbp). Dan pastikan sudah setting SDL , langkah-langkah nya ada pada artikel berikut : http://membuatgamedengancpp.blogspot.com/2009/09/setting-sdl-di-codeblocks-v802-1.html

      Untuk file header di file project ini hanya ada :

      #ifdef __cplusplus
      #include <cstdlib> //untuk keperluan fungsi standar seperti srand() untuk nilai acak, dsb
      #else
      #include <stdlib.h>
      #endif
      #ifdef __APPLE__
      #include <SDL/SDL.h> //header wajib untuk pemanggilan library SDL, program memanggil header pada folder SDL
      #else
      #include <SDL.h> //jika tidak ada dalam folder include->SDL->SDL.h, maka pencarian diluar folder SDL, yaitu include->SDL.h
      #endif
      #include <string> // untuk keperluan std::string

      Delete
    2. maksudnya error di
      #include (sdl.h)

      filenya yang .cpp?

      Delete
    3. dan header yang lain,seperti #else,#endif apakah digunakan jika kita ingin menggunakan fungsi else dan endif?

      kenapa #else lebih dari sekali?


      lalu #ifdef_cplusplus,#ifdef_APPLE_ untuk apa?

      sorry kalo banyak nanya

      Delete
    4. Saya lupa ngasih tau kalau pada versi CB (Code::Blocks) terbaru kita harus menyertakan header "ctime" , jika terdapat pesan error pada baris srand((unsigned)time(NULL)). Sedangkan untuk header SDL harusnya tidak masalah jika sudah setting. Pastikan sudah menambahkan variabel pada Build Project -> Search Directories (lihat artikel setting SDL).

      #ifdef, #else, #endif merupakan preprocessor (lihat : http://www.cplusplus.com/doc/tutorial/preprocessor/ ) . Fungsinya sederhana untuk menghindari error karena pemanggilan dua kali, coba cek link yang saya kasih. _APPLE_ hanya nama buatan sendiri. Biar lebih jelas coba cek header guard di : http://en.wikipedia.org/wiki/Include_guard

      Delete
    5. oops sorry __APPLE__ juga termasuk macro, mungkin fungsinya untuk mendeteksi sistem operasi yg digunakan *IMHO

      http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system

      karena saya juga nggak pernah mempermasalahkan fungsinya (bawaan template CB) jadi infonya masih terbatas ... :v

      Delete
  5. class maksudnya apa y?(maklum cuman belajar struct)
    kalo gak salah kalo ada Public berarti sama aj kayak struct,tapi itu ada yang gak pake public?

    trus tanda :: maksudnya apa y?

    ReplyDelete
    Replies
    1. class adalah pengembangan dari struct dengan fitur-fitur lebih baik untuk urusan OOP (Object Oriented Programming).

      tanda :: , untuk mendefinisikan atau menjelaskan fungsi dalam kelas , untuk lebih jelasnya Class :D

      Delete

Maaf jika komentar anda lama terbitnya ^__^, penulis berusaha OL sesering mungkin. Komentar anda adalah semangat blog ini, dan juga semangat para blogger lainnya. You can use XHTML tags: <a href="" rel="link"> </a>, <strong> </strong>, <b> </b>, <em> </em>, <i> </i>.

Spesial character use :
&lt; for <
&gt; for >


Use Pastebin.com for alternative to display your code :) .

 

back to top

back to top