Recent Comments

counter



Free web hostingWeb hosting

Bab IV. Sprite 2D

Download BAB4-Sprite.zip (1.24 MB)

Pada bab ini, kita akan mempelajari mengenai sprite. Sprite sebagai komponen sebuah game, sangatlah penting untuk dipelajari. Didalam sebuah game, sprite dapat digunakan untuk splash-screen (layar pembuka), HUD (heads-up display), kursor mouse, maupun sebagai tombol bertekstur. Bab ini merupakan lanjutan dari bab sebelumnya, dimana source-code dari bab sebelumnya akan ditambahkan dengan kode-kode untuk pembuatan dan penggunaan sprite.

Jalankan VisualC++ dan buka file “Gameku.dsw” pada folder “\BAB4-Sprite\sebelum”. Hapus fungsi GameLoop() di dalam file “Gameku.cpp”.

4.1 Sprite 2D

Pada DirectX versi 8 ke atas, DirectDraw tidak digunakan lagi untuk penggambaran obyek dua dimensi. Fungsi untuk melakukan hal tersebut telah diambil alih oleh DirectXGraphics. Walaupun DirectX memiliki interface sendiri untuk proses penggambaran sprite pada layar, yaitu ID3DXSPRITE, namun saya tidak menggunakan interface tersebut di dalam bab ini. Mengapa? Karena dengan membuat class sprite sendiri, Anda dapat belajar tentang loading bitmap untuk tekstur, mengerti tentang penggunaan vertex di dalam pembuatan polygon dan proses penggambaran polygon beserta teksturnya pada back buffer.

image002

Perhatikan gambar di atas. Dalam pembuatan sprite, Anda membutuhkan empat buah vertex untuk membuat sebuah bujur sangkar. Bujur sangkar tersebut kemudian “diisi” dengan tekstur bergambar. Lebar dan tinggi bujur sangkar dibuat sama seperti lebar dan tinggi tekstur.

Dengan menggunakan metode Triangle Strips yang ada pada DirectX, Anda dapat membuat sebuah bujur sangkar dari dua buah polygon yang dibentuk oleh empat buah vertex. Polygon pertama dibentuk oleh vertex0, vertex1 dan vertex2. Polygon kedua dibentuk oleh vertex1, vertex2 dan vertex3.

Setiap vertex membutuhkan data posisi, warna, koordinat UV dan FVF yang digunakan. Anda pasti sudah mengerti maksud posisi dan warna vertex, tapi apa itu UV dan FVF. UV adalah koordinat tekstur yang menentukan bagaimana tekstur “ditempelkan” ke polygon (Lihat Dokumentasi DirectX mengenai Texture Wrapping), sedangkan FVF (Flexible Vertex Format) adalah format vertex untuk memberitahukan kepada sistem render bagaimana DirectX akan me-render vertex tersebut (Lihat Dokumentasi DirectX mengenai D3DFVF).

Posisi, warna, UV dan FVF vertex pembentuk sprite dinyatakan dalam sebuah struktur, yaitu SPRITEVERTEX. Ketikkan kode-kode yang ditebalkan dibawah ini untuk membuat struktur SPRITEVERTEX.

VOID HapusSemuaObyekDirectX()
{

}

struct SPRITEVERTEX
{
D3DXVECTOR4 p;
DWORD color;
FLOAT tu, tv;
static const DWORD FVF;
};
const DWORD SPRITEVERTEX::FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1;

DirectX memiliki berbagai FVF yang dapat digunakan. Tetapi penggunaan FVF perlu memperhatikan kemampuan kartu grafik saat memproses vertex-vertex dengan format tersebut. Untuk sprite, Anda hanya memerlukan tiga buah format saja yaitu D3DFVF_XYZRHW, D3DFVF_DIFFUSE dan D3DFVF_TEX1. Berikut keterangannya :

1. D3DFVF_XYZRHW

Posisi vertex dapat ditransformasikan.

2. D3DFVF_DIFFUSE

Menggunakan komponen warna.

3. D3DFVF_TEX1

Menggunakan tekstur koordinat nomor 1.

Sekarang Anda akan membuat sebuah class yang mewakili penggunaan sprite dalam aplikasi DirectX Anda. Ketikkan kode di bawah ini :

class ObyekSprite
{
public :
LPDIRECT3DVERTEXBUFFER9 SpriteVB;
LPDIRECT3DTEXTURE9 TeksturSprite;
D3DXIMAGE_INFO SpriteInfo;
SPRITEVERTEX* vSpriteVertex;

bool bPNGAlpha;

HRESULT InisialisasiSprite(LPDIRECT3DDEVICE9 m_pd3dDevice,LPCTSTR NamaFileBMP);
VOID HapusSprite();
VOID RenderSprite(LPDIRECT3DDEVICE9 m_pd3dDevice,float PosX, float PosY);
};

Dua interface DirectX digunakan yaitu IDirect3DVertexBuffer9 (ditunjuk oleh variabel SpriteVB) dan IDirect3DTexture9 (ditunjuk oleh variabel TeksturSprite). Struktur D3DXIMAGE_INFO digunakan untuk mengambil informasi bitmap sebagai tekstur sprite. Struktur SPRITEVERTEX telah dijelaskan sebelumnya. Variabel bPNGAlpha, digunakan untuk menentukan apakah tekstur sprite memiliki transparansi (format PNG) atau tidak memiliki transparansi (format BMP). Fungsi InisialisasiSprite akan melakukan tugas inisialisasi sprite dimana parameter yang diperlukan adalah device Direct3D dan nama file bitmap tekstur sprite.

HRESULT ObyekSprite::InisialisasiSprite(LPDIRECT3DDEVICE9 m_pd3dDevice,
LPCTSTR NamaFileBMP)
{
//buat vertex buffer
if( FAILED( m_pd3dDevice->CreateVertexBuffer( 4*sizeof(SPRITEVERTEX),
D3DUSAGE_WRITEONLY, SPRITEVERTEX::FVF,
D3DPOOL_MANAGED, &SpriteVB, NULL ) ) )
{
sprintf(temptext,”Gagal : Vertex Buffer Untuk \”%s\”.”,
NamaFileBMP);
MessageBox(NULL,temptext,NULL,MB_OK);
return E_FAIL;
}
else
{
// jika berhasil membuat vertex buffer, load bitmap untuk tekstur
if (FAILED(D3DXCreateTextureFromFileEx(
m_pd3dDevice,
NamaFileBMP,
0, 0, 0, 0, D3DFMT_A8R8G8B8,
D3DPOOL_MANAGED, D3DX_DEFAULT,
D3DX_DEFAULT, D3DCOLOR_XRGB(0,0,0),
NULL, NULL,
&TeksturSprite
)))
{
sprintf(temptext,”Gagal : Loading Bitmap \”%s\”.”,
NamaFileBMP);
MessageBox(NULL,temptext,NULL,MB_OK);
return E_FAIL;
}
else
{
// jika berhasil load bitmap, ambil informasi tentang bitmap tersebut
D3DXGetImageInfoFromFile(NamaFileBMP, &SpriteInfo);
}
}
bPNGAlpha = FALSE;
return S_OK;
}

Hal yang pertama Anda lakukan pada fungsi InisialisasiSprite() adalah membuat vertex buffer. Apa itu vertex buffer ? Vertex buffer adalah ruang memori yang menyimpan informasi vertex. Device Direct3D membuat vertex buffer melalui perintah CreateVertexBuffer. Berikut keterangan pengisian parameter perintah CreateVertexBuffer pada kode di atas:

No

Isi

Keterangan

1

4*sizeof(SPRITEVERTEX)

Karena hanya dibutuhkan empat vertex, maka besar vertex buffer adalah empat kali ukuran struktur SPRITEVERTEX.

2

D3DUSAGE_WRITEONLY

Vertex buffer hanya akan ditulisi. Lihat Dokumentasi DirectX mengenai D3DUSAGE.

3

SPRITEVERTEX::FVF

Format vertex untuk vertex buffer ini adalah fvf pada struktur SPRITEVERTEX

4

D3DPOOL_MANAGED

Vertex Buffer diletakkan di memori sistem komputer. Lihat Dokumentasi DirectX mengenai D3DPOOL.

5

&SpriteVB

Representasi vertex buffer yang akan dibuat.

6

NULL

Tidak digunakan lagi. Isi dengan NULL.

Bila vertex buffer berhasil dibuat, hal berikutnya adalah membuat tekstur sprite. Tekstur dibuat dari file bitmap melalui perintah D3DXCreateTextureFromFileEx. Perintah ini memiliki parameter yang cukup banyak untuk dijelaskan. Lihat dokumentasi DirectX tentang perintah tersebut.

Bila Vertex buffer dan tekstur telah berhasil dibuat di memori, hal berikutnya adalah mengambil informasi tekstur, kita memerlukan informasi panjang dan tinggi tekstur untuk menentukan panjang dan tinggi bujur sangkar.

Ketikkan kode berikut ini untuk membuat fungsi RenderSprite:

VOID ObyekSprite::RenderSprite(LPDIRECT3DDEVICE9 m_pd3dDevice,float PosX, float PosY)
{
SpriteVB->Lock( 0, 0, (void**)&vSpriteVertex, 0 );
for( UINT i=0; i<4; i ++ )
{ vSpriteVertex[i].p = D3DXVECTOR4( 0.0f, 0.0f, 0.9f, 1.0f );
vSpriteVertex[i].color = 0xffffffff;
}
// vertex 0 di kiri bawah
vSpriteVertex[0].p.x = PosX;
vSpriteVertex[0].p.y = PosY+SpriteInfo.Height;
// vertex 1 di kiri atas
vSpriteVertex[1].p.x = PosX;
vSpriteVertex[1].p.y = PosY;
// vertex 2 di kanan bawah
vSpriteVertex[2].p.x = PosX+SpriteInfo.Width;
vSpriteVertex[2].p.y = PosY+SpriteInfo.Height;
// vertex 3 di kanan atas
vSpriteVertex[3].p.x = PosX+SpriteInfo.Width;
vSpriteVertex[3].p.y = PosY;
//uv
vSpriteVertex[0].tu = 0.0f; vSpriteVertex[0].tv = 1.0f;
vSpriteVertex[1].tu = 0.0f; vSpriteVertex[1].tv = 0.0f;
vSpriteVertex[2].tu = 1.0f; vSpriteVertex[2].tv = 1.0f;
vSpriteVertex[3].tu = 1.0f; vSpriteVertex[3].tv = 0.0f;
SpriteVB->Unlock();

m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
if (bPNGAlpha == TRUE)
{
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
}

m_pd3dDevice->SetTexture( 0, TeksturSprite );
m_pd3dDevice->SetFVF( SPRITEVERTEX::FVF );
m_pd3dDevice->SetStreamSource( 0, SpriteVB, 0, sizeof(SPRITEVERTEX) );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP , 0, 2 );

m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, TRUE );
if (bPNGAlpha == TRUE)
{
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
}
}

Hmm… cukup panjang ya… sekarang udah hampir jam 3 pagi. Ngantuk juga nih… huammm… Dikarenakan fungsi ObyekSprite::RenderSprite() dapat menggambar sprite pada posisi yang diinginkan, maka setiap fungsi ini dipanggil, Anda perlu menentukan kembali posisi-posisi vertex pada layar monitor berdasarkan posisi sprite (PosX,PosY) terhadap kiri atas window. Posisi kiri atas sprite, yaitu vertex1, adalah posisi acuan penempatan sprite (Lihat Gambar). Dari gambar dapat dilihat bahwa posisi X vertex0 adalah PosX, posisi Y vertex0 adalah PosY+SpriteInfo.Height. Begitupula dengan posisi vertex-vertex lainnya. Perlu diingat, sebelum memindahkan posisi vertex di dalam vertex buffer, Anda diharuskan mengunci vertex buffer dengan perintah Lock.

image003

Perhatikan kode-kode berikut :

m_pd3dDevice->SetTexture( 0, TeksturSprite );
m_pd3dDevice->SetFVF( SPRITEVERTEX::FVF );
m_pd3dDevice->SetStreamSource( 0, SpriteVB, 0, sizeof(SPRITEVERTEX) );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP , 0, 2 );

Sebelum sprite digambar ke back buffer dengan perintah DrawPrimitive, Anda diharuskan memberitahu kepada device bahwa tekstur yang digunakan adalah TeksturSprite, FVF yang digunakan adalah SPRITEVERTEX::FVF, dan vertex buffer yang digunakan adalah SpriteVB.

Sprite 2D tidak membutuhkan penggunaan cahaya(light) dan kabut (fog), kecuali sprite 3D atau yang biasa disebut billboard. Bila tekstur sprite memiliki transparansi, maka D3DRS_ALPHABLENDENABLE di-set TRUE agar dapat menggunakan transparansi tersebut.

Dan fungsi ObyekSprite yang terakhir adalah ObyekSprite::HapusSprite().

VOID ObyekSprite::HapusSprite()
{
if (SpriteVB!=NULL)
{ SpriteVB->Release(); SpriteVB = NULL;}
if (TeksturSprite!=NULL)
{ TeksturSprite->Release(); TeksturSprite = NULL;}
}

4.2 Menggunakan Class ObyekSprite

Bagaimana cara menggunakan class ObyekSprite yang telah Anda buat bila Anda memiliki sebuah file BMP sebagai splash-screen dan sebuah file PNG sebagai kursor mouse?

image004
bitmap\splashscreen.bmp,
640×480 pixel
Tidak ada transparansi

image005
bitmap\kursor.png
20×20 pixel
Memiliki transparansi alpha

Bukalah file “Gameku.cpp”. Hal pertama yang harus Anda lakukan untuk menggunakan dua bitmap di atas sebagai sprite adalah mendeklarasikan dua variabel bertipe ObyekSprite. Kemudian di dalam fungsi InitObyekGame(), gunakan perintah ObyekSprite::InisialisasiSprite() dengan memasukkan nama file bitmap di atas pada parameter kedua dari tiap-tiap ObyekSprite. Atur nilai bPNGAlpha pada sprite kursor mouse agar bernilai TRUE. Di dalam fungsi HapusObyekGame(), gunakan perintah ObyekSprite::HapusSprite(). Kemudian di dalam fungsi Render(), gunakan perintah ObyekSprite::HapusSprite() untuk menggambar sprite pada back buffer. Ketikkan kode-kode dibawah ini untuk melakukan menggunakan ObyekSprite.

#include <windows.h>
#include “DirectXku.h”
bool bKeluar = FALSE;

ObyekSprite spSplashScreen;
ObyekSprite spKursorMouse;

VOID InitObyekGame()
{
// letakkan semua perintah inisialisasi obyek game di sini
spSplashScreen.InisialisasiSprite(Direct3DDevice,”bitmap/splashscreen.bmp”);
spKursorMouse.InisialisasiSprite(Direct3DDevice,”bitmap/kursor.png”);
spKursorMouse.bPNGAlpha = TRUE;
}

VOID HapusObyekGame()
{
spSplashScreen.HapusSprite();
spKursorMouse.HapusSprite();
}

VOID Render()
{
Direct3DDevice -> Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,0),1.0f,0);
Direct3DDevice -> BeginScene();

spSplashScreen.RenderSprite(Direct3DDevice,0,0);
spKursorMouse.RenderSprite(Direct3DDevice,200,200);

Direct3DDevice -> EndScene();
Direct3DDevice -> Present(NULL,NULL,NULL,NULL);
}

Pada fungsi Render() di atas, terlihat bahwa sebelum penggambaran ObyekSprite dilakukan, back buffer harus dibersihkan terlebih dahulu dengan perintah Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0),1.0f,0). Kemudian proses penggambaran ObyekSprite dilakukan di antara perintah BeginScene dan EndScene. Back Buffer ditampilkan ke layar monitor dengan perintah Present(NULL,NULL,NULL,NULL). Tidak terlalu rumit bukan ?

Compile dan Build aplikasi Anda. Berikut adalah gambar tampilan aplikasi Anda bila dijalankan.

image006

Perhatikan sprite kursor mouse (gambar panah berwarna merah), amati bahwa Anda telah menggunakan transparansi untuk menggambar sprite tersebut. Kursor tersebut belum dapat Anda gerakkan, pada bab berikutnya Anda akan mempelajari tentang hal tersebut dan sekaligus membuat tombol dan in-game menu.

Selamat !!! Anda telah dapat membuat dan menggambar sprite. Sebenarnya masih banyak fitur dari sprite yang dapat kita buat. Contohnya penggunaan sprite beranimasi, mengatur transparansi, menampilkan sprite untuk beberapa frame saja, sprite dengan skew dan merubah warna difuse sprite untuk pemain berbeda. Di lain waktu dan kesempatan, saya akan mencoba membuat tutorial lain untuk menguprade fitur-fitur sprite yang Anda buat pada bab ini.

4.3 FAQ (Frequently Asked Questions)

Semoga FAQ ini dapat membantu Anda bila mendapat kesulitan…

Tanya : Mengapa pada saat aplikasi melakukan inisialisasi sprite, muncul kotak pesan “Gagal : Vertex Buffer Untuk “Splash.BMP”. Mungkin memori penuh?” ?
Jawab : Karena pada fungsi ObyekSprite::InisialisasiSprite(), digunakan D3DPOOL_MANAGED untuk membuat vertex buffer, maka DirectX mengatur secara otomatis, apakah vertex buffer akan dibuat pada memori sistem atau memori kartu grafik. Kegagalan tersebut terjadi karena salah satu atau kedua memori tersebut telah penuh.

Tanya : Mengapa pada saat aplikasi melakukan inisialisasi sprite, muncul kotak pesan “Gagal : Loading Bitmap “Splash.BMP”.” ?
Jawab : Kegagalan tersebut terjadi karena aplikasi tidak dapat menemukan file “Splash.BMP” atau dapat juga terjadi karena memori sistem atau memori kartu grafik telah penuh.

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>