SDL 2.0 Siklus Pelajaran: Pelajaran 5 - Mengiris Sprite Sheet

gambar

Dari penerjemah:

Ini adalah kelanjutan dari serangkaian terjemahan tutorial Twinklebear, tersedia dalam aslinya di sini . Terjemahan ini sebagian gratis dan mungkin berisi sedikit perubahan atau tambahan dari penerjemah. Terjemahan dari dua pelajaran pertama - kepengaranganPointer tidak validdan yang ketiga dan keempat untuk k1-801.


Daftar pelajaran:



Mengiris lembar sprite


Seringkali dalam gim 2D, mereka menggunakan satu gambar besar untuk menyimpan beberapa gambar yang lebih kecil, misalnya ubin dalam ubin bukan banyak gambar kecil untuk setiap ubin. Gambar semacam itu disebut sprite sheet dan sangat nyaman digunakan, karena kita tidak perlu mengubah tekstur yang ingin kita gambar, tetapi hanya menunjukkan bagian mana dari tekstur yang digunakan.

Dalam tutorial ini, kita akan melihat cara memilih bagian dari suatu tekstur menggunakan SDL_RenderCopy , serta sedikit tentang bagaimana mendeteksi peristiwa keystroke spesifik yang akan kita gunakan untuk memilih bagian mana dari tekstur yang akan digambar. Akan ada empat lingkaran warna-warni di sprite sheet:

gambar


Dalam tutorial ini, sprite sheet terdiri dari banyak sprite dengan ukuran yang sama, dalam hal mengiris tidak sulit. Jika tidak, untuk sprite dengan ukuran berbeda, kita akan memerlukan file metadata yang berisi informasi tentang lokasi bagian-bagian itu. Untuk tutorial ini kita akan menggunakan 4 sprite ukuran 100x100. Kode untuk pelajaran ini didasarkan pada pelajaran 4, jika Anda tidak memiliki kode untuk menulis, Anda bisa mendapatkannya dari Github .

Pemilihan bagian


Menggunakan SDL, sangat mudah untuk memilih bagian dari tekstur yang ingin Anda gambar. Dalam pelajaran 4, parameter SDL_RenderCopy yang tersisa dengan nilai NULL menunjukkan koordinat persegi panjang yang menentukan bagian mana dari tekstur yang ingin kita gambar. Ketika melewati nilai NULL, kami mengindikasikan bahwa kami membutuhkan seluruh tekstur, tetapi kami dapat dengan mudah menambahkan parameter dari persegi panjang dan hanya menggambar sebagian dari tekstur. Untuk melakukan ini, kami akan membuat perubahan pada fungsi renderTexture sehingga dapat mengambil area persegi panjang, tetapi masih menyimpan versi pendek sintaks dari versi lama untuk kenyamanan.

Ubah renderTexture


Agar tidak melampirkan lebih banyak parameter ke fungsi renderTexture kami dan pada saat yang sama menjaga kenyamanan nilai-nilai default, kami akan membaginya menjadi dua fungsi. Yang pertama hampir identik dengan memanggil SDL_RenderCopy, tetapi memberikan parameter daerah kliping dengan nilai nullptr. Versi renderTexture ini akan menerima lokasi dalam bentuk area persegi panjang, yang dapat kita konfigurasikan sendiri atau menggunakan salah satu fungsi renderTexture khusus kami yang lain. Fungsi render dasar baru menjadi sangat sederhana.

/**
*  SDL_Texture  SDL_Renderer   .
*     
* @param tex  ,   
* @param ren ,    
* @param dst     
* @param clip     ( )
*                 nullptr   
*/
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, SDL_Rect dst,
        SDL_Rect *clip = nullptr)
{
        SDL_RenderCopy(ren, tex, clip, &dst);
}

Untuk kenyamanan, kami akan menulis fungsi lain di mana kami tidak perlu membuat SDL_Rect untuk lokasi, tetapi hanya menyediakan x dan y dan membiarkan fungsi tampilan kami mengisi lebar dan tinggi tekstur. Kami akan membuat versi renderTexture yang kelebihan beban yang akan melakukan ini dengan beberapa pengaturan untuk menangani kliping. Tambahkan cut rectangle sebagai parameter dengan nilai default nullptr dan jika cut telah dilewati, kita akan menggunakan lebar dan tinggi dari cut sebagai ganti lebar dan tinggi tekstur. Dengan demikian, kita tidak akan meregangkan sprite kecil dengan ukuran sprite sheet yang berpotensi sangat besar ketika digambar. Fungsi ini merupakan modifikasi dari fungsi renderTexture asli dan terlihat sangat mirip.

/**
*  SDL_Texture  SDL_Renderer   x, y, 
*          
*    ,       
*          
* @param tex  ,   
* @param ren ,    
* @param x  x,    
* @param y  y,    
* @param clip     ( )
*                 nullptr   
*/
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y,
        SDL_Rect *clip = nullptr)
{
        SDL_Rect dst;
        dst.x = x;
        dst.y = y;
        if (clip != nullptr){
                dst.w = clip->w;
                dst.h = clip->h;
        }
        else {
                SDL_QueryTexture(tex, NULL, NULL, &dst.w, &dst.h);
        }
        renderTexture(tex, ren, dst, clip);
}

Tentukan kliping persegi panjang


Dalam kasus kami, sangat mudah untuk menghitung kliping persegi panjang menggunakan metode yang sangat mirip dengan metode ubin dari pelajaran 3 , namun, alih-alih pergi baris demi baris, kami akan pergi kolom demi kolom. Jadi, potongan pertama akan berwarna hijau, yang kedua akan menjadi merah, yang ketiga akan menjadi biru dan yang keempat akan menjadi kuning. Ide komputasi sama dengan dalam pelajaran 3, tetapi hanya alih-alih baris kita jalankan melalui kolom. Jadi koordinat y kita dihitung dengan mendapatkan sisanya ketika membagi indeks ubin dengan jumlah ubin (2), dan koordinat x dengan membagi indeks dengan jumlah ubin. Koordinat x dan y ini adalah indeks x dan y, jadi kami menerjemahkannya ke dalam koordinat piksel nyata dengan mengalikannya dengan lebar dan tinggi potongan, yang sama untuk semua ubin (100x100). Akhirnya, pilih potongan untuk menggambar, dalam hal ini yang pertama.

Kami juga ingin menggambar potongan kami di tengah layar, jadi kami menghitung koordinat x dan y ini menggunakan lebar dan tinggi ubin, bukan lebar dan tinggi tekstur.

//iW  iH    
//   ,     ,     
int iW = 100, iH = 100;
int x = SCREEN_WIDTH / 2 - iW / 2;
int y = SCREEN_HEIGHT / 2 - iH / 2;

//    
SDL_Rect clips[4];
for (int i = 0; i < 4; ++i){
        clips[i].x = i / 2 * iW;
        clips[i].y = i % 2 * iH;
        clips[i].w = iW;
        clips[i].h = iH;
}
//     
int useClip = 0;

Jika sebaliknya kita akan menggunakan sprite sheet yang lebih kompleks dengan sprite yang diputar dari berbagai ukuran yang dikemas bersama, kita perlu menyimpan informasi tentang lokasi mereka dan rotasi dalam beberapa file metadata sehingga kita dapat dengan mudah menemukan bagian-bagiannya.

Ubah gambar berdasarkan input


Untuk memeriksa semua bagian gambar yang kami buat, tambahkan pemrosesan input keyboard ke loop pemrosesan acara dan pilih bagian yang ditampilkan menggunakan tombol 1-4. Untuk menentukan apakah kunci telah ditekan, kita dapat memeriksa apakah acara tersebut bertipe SDL_KEYDOWN dan jika demikian, kita dapat mengetahui kunci mana yang ditekan dengan memeriksa kode kunci di dalam acara menggunakan e.key.keysym.sym. Daftar lengkap jenis acara , kode kunci, dan informasi lain tentang SDL_Event tersedia di wiki.

Ketika tombol ditekan, kita perlu mengubah nilai useClip ke jumlah bagian gambar yang ingin kita gambar. Dengan perubahan ini, loop acara terlihat seperti ini:

while (SDL_PollEvent(&e)){
        if (e.type == SDL_QUIT)
                quit = true;
        //       
        if (e.type == SDL_KEYDOWN){
                switch (e.key.keysym.sym){
                        case SDLK_1:
                                useClip = 0;
                                *break;
                        case SDLK_2:
                                useClip = 1;
                                *break;
                        case SDLK_3:
                                useClip = 2;
                                *break;
                        case SDLK_4:
                                useClip = 3;
                                *break;
                        case SDLK_ESCAPE:
                                quit = true;
                                *break;
                        default:
                                *break;
                }
        }
}

Buat gambar yang dipangkas


Hal terakhir yang harus dilakukan adalah mendapatkan bagian kanan gambar di layar! Kami akan melakukan ini dengan memanggil versi renderTexture kami yang lebih nyaman untuk menggambar bagian dari gambar tanpa penskalaan tambahan dan mentransfer bagian yang ingin kami gunakan (yang digunakan dalam useClip).

SDL_RenderClear(renderer);
renderTexture(image, renderer, x, y, &clips[useClip]);
SDL_RenderPresent(renderer);

Akhir pelajaran 5


Ketika Anda memulai program, Anda akan melihat bagian 0 (lingkaran hijau) di tengah layar dan dapat memilih bagian gambar yang berbeda menggunakan tombol angka. Jika Anda mengalami masalah, periksa kembali kode Anda dan / atau kirim email atau tweet ke penulis asli.

All Articles