Jumat, 24 Juli 2015

Deteksi Tabrakan Game Shoot Them Up

Deteksi Tabrakan Antara Objek Peluru dengan Pesawat dan Antara Pesawat dengan Pesawat


Selamat Pagi semuanya, ini adalah postingan terakhir sebelum event tanggal 25 dan 26 July  di Ubud, event yang sangat penting bagi ogut, jadi ogut akan berhenti nulis selama beberapa hari hingga event selesai.

Artikel kali ini akan membahas tentang deteksi tabrakan antara peluru dengan pesawat dan pesawat dengan pesawat, setelah sebelumnya ogut mengajarkan cara untuk membuat  peluru agar pesawat jagoan dengan pesawat musuh bisa saling baku tembak.


Peluru Versus Objek
Perhitungan yang ogut pakai untuk mendeteksi tabrakan sudah pernah dibahas pada postingan tentang vektor R2, jadi ogut ngak bakal ulang, klik ajak link artikelnya dan pelajari bagian skala proyeksi vektor.


Pada gambar dia atas rekan-rekan dapat melihat bahwa tabrakan antara peluru dengan objek terjadi bila keempat titik polygon peluru berada di dalam polygon pesawat atau musuh.

(project game ini adalah game pertama yang berhasil ogut buat, disini nih ada kelemahannya, seharusnya pakai titik tengah objek peluru saja ngak usah sampe 4 titik koordinat peluru atau rekan-rekan bisa memakai deteksi tabrakan radius. Ngak apa-apa ya ogut waktu itu belum tau)

Dengan dasar algoritma di atas ogut membuat deteksi tabrakan antara peluru dan objek, sedangkan skala proyeksi vektor ogut pakai untuk menyelesaikan masalah di atas.

Di bawah ini ogut lampirkan listing fungsi peluru versus objek untuk mendeteksi tabrakan antara peluru dan objek.

//object 1 adalah peluru
//object 2 yang ditabrak oleh peluru
void Cek_PeluruVsObject(Game_Object Object1[], int total_Obj1,
Game_Object Object2[], int total_Obj2,
Object_Api Api_Tertembak_p[], int total_api,
Object_Api Api_Terbakar1[], int total_terbakar1,
int &score_p)
{
int i, j;
Vektor2D V1, V2;
Vektor2D dot_vektor;
double temp_panjang1, temp_panjang2;
double skala_Vproyeksi1, skala_Vproyeksi2;

for (i = 0; i < total_Obj1; i++)
{
for (j = 0; j < total_Obj2; j++)
{
if ((Object1[i].Power != 0) && (Object2[j].Power != 0))
{
//mulai cek tabrakan 4 titik

//create vektor 1 dan 2
V1 = Vektor_dari_2_Vertex(Object2[j].X4, Object2[j].Y4,
Object2[j].X1, Object2[j].Y1);

V2 = Vektor_dari_2_Vertex(Object2[j].X2, Object2[j].Y2,
Object2[j].X1, Object2[j].Y1);

//hitung panjang vektor pangkat 2
temp_panjang1 = pow(Panjang_Vektor(V1), 2.0);
temp_panjang2 = pow(Panjang_Vektor(V2), 2.0);

//vektor titik 1
dot_vektor = Vektor_dari_2_Vertex(Object1[i].X1, Object1[i].Y1,
Object2[j].X1, Object2[j].Y1);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

//cek untuk titik pertama
if (((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0)))
{
//cek titik kedua
dot_vektor = Vektor_dari_2_Vertex(Object1[i].X2, Object1[i].Y2,
Object2[j].X1, Object2[j].Y1);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

if (((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0)))
{
//cek titik ketiga
dot_vektor = Vektor_dari_2_Vertex(Object1[i].X3, Object1[i].Y3,
Object2[j].X1, Object2[j].Y1);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

if (((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0)))
{
//cek titik ke empat
dot_vektor = Vektor_dari_2_Vertex(Object1[i].X4, Object1[i].Y4,
Object2[j].X1, Object2[j].Y1);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

if (((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0)))
{
//empat titik  object 1 
//berada di dalam
//polygon object 2


//jika object 2 adalah pesawat
//(peluru musuh tabrak pesawat)
if (Object2[j].Object_Type == 0)
{
Object2[j].Power -= Object1[i].Destruct;

Object1[i].Power = 0;
Aktifkan_Api_Tertembak(Api_Tertembak_p, total_api,
Object1[i], 30.0);

SoundEffect[2].Play(false);

if (Object2[j].Power <= 0)
{
//pesawat musnah
Object2[j].Power = 0;
Aktifkan_Api_Terbakar(Api_Terbakar1, total_terbakar1,
Object2[j], 80.0);

SoundEffect[4].Play(false);
}
}

//jika object 2 adalah musuh 
//(peluru pesawat tabrak musuh)
if ((Object2[j].Object_Type >= 1) && (Object2[j].Object_Type <= 99))
{
Object2[j].Power -= Object1[i].Destruct;

Object1[i].Power = 0;
Aktifkan_Api_Tertembak(Api_Tertembak_p, total_api,
Object1[i], 30.0);

SoundEffect[2].Play(false);

if (Object2[j].Power <= 0)
{
//musuh musnah
Object2[j].Power = 0;
Aktifkan_Api_Terbakar(Api_Terbakar1, total_terbakar1,
Object2[j], 80.0);

SoundEffect[3].Play(false);

//score jika berhasil memusnahkan musuh
score_p += Object2[j].Score;

}
}

}
}
}
}
}
}
}
}

Objek Versus Objek


Tidak seperti peluru menabrak objek yang memakai empat titik polygon, tabrakan antara objek dengan objek cukup memakai satu titik polygon saja, seperti tampak pada gambar di atas. Jika  satu titik polygon dari sebuah objek berada di dalam polygon objek yang lain maka tabrakan terjadi.

Listing dari fungsi objek versus objek adalah:

////////////////////////////////////////
//object 1 penabrak
//object 2 yang ditabrak
///////////////////////////////////////
void Cek_ObjectVsObject(Game_Object Object1[], int total_Obj1,
Game_Object Object2[], int total_Obj2,
Object_Api Api_Tertembak_p[], int total_api,
Object_Api Api_Terbakar1[], int total_terbakar1,
Object_Api Api_Terbakar2[], int total_terbakar2)
{
int i, j;
Vektor2D V1, V2;
Vektor2D dot_vektor;
double temp_panjang1, temp_panjang2;
double skala_Vproyeksi1, skala_Vproyeksi2;
bool tabrakan;


for (i = 0; i < total_Obj1; i++)
{
for (j = 0; j < total_Obj2; j++)
{

if ((Object1[i].Power != 0) && (Object2[j].Power != 0))
{
tabrakan = false;

//mulai cek tabrakan 1 titik

//create vektor 1 dan 2
V1 = Vektor_dari_2_Vertex(Object2[j].X4, Object2[j].Y4,
Object2[j].X1, Object2[j].Y1);

V2 = Vektor_dari_2_Vertex(Object2[j].X2, Object2[j].Y2,
Object2[j].X1, Object2[j].Y1);

//hitung panjang vektor pangkat 2
temp_panjang1 = pow(Panjang_Vektor(V1), 2.0);
temp_panjang2 = pow(Panjang_Vektor(V2), 2.0);

//vektor titik 1
dot_vektor = Vektor_dari_2_Vertex(Object1[i].X1, Object1[i].Y1,
Object2[j].X1, Object2[j].Y1);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

//cek untuk titik pertama
if (((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0)))
{
tabrakan = true;
}


//cek titik kedua
dot_vektor = Vektor_dari_2_Vertex(Object1[i].X2, Object1[i].Y2,
Object2[j].X1, Object2[j].Y1);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

if (((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0)))
{
tabrakan = true;
}


//cek titik ketiga
dot_vektor = Vektor_dari_2_Vertex(Object1[i].X3, Object1[i].Y3,
Object2[j].X1, Object2[j].Y1);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

if (((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0)))
{
tabrakan = true;
}


//cek titik ke empat
dot_vektor = Vektor_dari_2_Vertex(Object1[i].X4, Object1[i].Y4,
Object2[j].X1, Object2[j].Y1);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

if (((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0)))
{
tabrakan = true;
}



if (tabrakan)
{
//set kondisi tabrakan sesuai 
//dengan object type

if ((Object1[i].Object_Type >= 1) &&
(Object1[i].Object_Type <= 99) &&
(Object2[j].Object_Type == 0))
{
//jika musuh menabrak pesawat
//Object Type untuk musuh 
//bernilai 1 s/d 99

//penabrak musnah
Object1[i].Power = 0;

Aktifkan_Api_Tertembak(Api_Tertembak_p, total_api,
Object2[j], 30.0);

Aktifkan_Api_Terbakar(Api_Terbakar1, total_terbakar1,
Object1[i], 80.0);


SoundEffect[3].Play(false);

Object2[j].Power -= Object1[i].Destruct;

Object2[j].Score += Object1[i].Score;

if (Object2[j].Power <= 0)
{
//pesawat terbakar/musnah
Object2[j].Power = 0;

SoundEffect[4].Play(false);
Aktifkan_Api_Terbakar(Api_Terbakar2, total_terbakar2,
Object2[j], 80.0);
}
}
}
}
}
}
}

Api Tertembak Dan Api Terbakar
Pada saat terjadi tabrakan kita harus membuat suatu efek suara dan animasi untuk menambah nilai dari game yang kita buat supaya pemain lebih menikmati.

Efek api tertembak ogut buat jika tabrakan antara peluru dan objek terjadi akan timbul percikan api, sedangkan jika Power dari objek bernilai 0(nol) maka ogut membuat efek api terbakar.

Membuat efek ini caranya sama dengan membuat pesawat atau musuh, bahkan lebih sederhana. Struct yang ogut pakai untuk membuat efek ini adalah:

typedef struct
{
double X1, Y1; 
double X2, Y2;
double X3, Y3; 
double X4, Y4;

int Index_Image;
int Delay_II;
int Counter_II;
int Max_II;

int Active_Flag;

}Object_Api;

Sedangkan cara pemrogramannya tidak berbeda dengan membuat peluru, yang penting Active_Flag=1 untuk api yang akan ditampilkan di layar.

Berikut ini adalah fungsi-fungsi yang diperlukan untuk membuat api tertembak dan api terbakar.

bool Load_Object_Api(char *filename, Object_Api List_OA[])
{
int i = 0;   

ifstream OA_Dat;
   
OA_Dat.open(filename);
   
if(!OA_Dat)
{
MessageBox(NULL, filename, "File Error!", MB_OK);
return false;
}

while(!OA_Dat.eof())
{
OA_Dat >> List_OA[i].X1 >> List_OA[i].Y1
>> List_OA[i].X2 >> List_OA[i].Y2
>> List_OA[i].X3 >> List_OA[i].Y3
>> List_OA[i].X4 >> List_OA[i].Y4
>> List_OA[i].Index_Image 
>> List_OA[i].Delay_II 
>> List_OA[i].Counter_II 
>> List_OA[i].Max_II 
>> List_OA[i].Active_Flag;

i++;
}

return true;
}

void Aktifkan_Api_Tertembak(Object_Api  Api_Tertembak_p[], int total_Api, 
Game_Object My_Object, double delta_XY)
{
int i;
Vektor2D V_tengah;
double Xtengah, Ytengah;
//cara untuk mengaktifkan api
//dengan set Active_Flag = 1;
for (i = 0; i < total_Api; i++)
{
if (Api_Tertembak_p[i].Active_Flag == 0)
{
Api_Tertembak_p[i].Active_Flag = 1;
//posisi untuk percikan api
//dihitung disini

//cari titik tengah object 
V_tengah = Vektor_dari_2_Vertex(My_Object.X3, My_Object.Y3, My_Object.X1, My_Object.Y1);
V_tengah = Vektor_diskala(0.5, V_tengah);

Xtengah = V_tengah.i + My_Object.X1;
Ytengah = V_tengah.j + My_Object.Y1;

Api_Tertembak_p[i].X1 = Xtengah - delta_XY;
Api_Tertembak_p[i].X2 = Xtengah + delta_XY;
Api_Tertembak_p[i].X3 = Xtengah + delta_XY;
Api_Tertembak_p[i].X4 = Xtengah - delta_XY;

Api_Tertembak_p[i].Y1 = Ytengah - delta_XY;
Api_Tertembak_p[i].Y2 = Ytengah - delta_XY;
Api_Tertembak_p[i].Y3 = Ytengah + delta_XY;
Api_Tertembak_p[i].Y4 = Ytengah + delta_XY;

i = total_Api;
}
}
}

void Aktifkan_Api_Terbakar(Object_Api  Api_Terbakar_p[], int total_Api, 
Game_Object My_Object, double delta_XY)
{
int i;
//cara untuk mengaktifkan api
//dengan set Active_Flag = 1;
for (i = 0; i < total_Api; i++)
{
if (Api_Terbakar_p[i].Active_Flag == 0)
{
Api_Terbakar_p[i].Active_Flag = 1;
//hitung posisi tempat efek terbakar
//akan ditampilkan di layar
Api_Terbakar_p[i].X1 = My_Object.X1; 
Api_Terbakar_p[i].X2 = My_Object.X2;
Api_Terbakar_p[i].X3 = My_Object.X3;
Api_Terbakar_p[i].X4 = My_Object.X4;

Api_Terbakar_p[i].Y1 = My_Object.Y1;
Api_Terbakar_p[i].Y2 = My_Object.Y2;
Api_Terbakar_p[i].Y3 = My_Object.Y3;
Api_Terbakar_p[i].Y4 = My_Object.Y4;

i = total_Api;
}
}
}

void Display_Api_Tertembak(Object_Api  Api_Tertembak_p[], int total_Api,
unsigned int image_object[], 
unsigned int mask_object[])
{
int i;
//api akan ditampilkan di layar bila
//Active_Flag = 1
for (i = 0; i < total_Api; i++)
{
if (Api_Tertembak_p[i].Active_Flag == 1)
{
Api_Tertembak_p[i].Counter_II++;
if (Api_Tertembak_p[i].Counter_II == Api_Tertembak_p[i].Delay_II)
{
Api_Tertembak_p[i].Counter_II = 0;
Api_Tertembak_p[i].Index_Image++;
}

if (Api_Tertembak_p[i].Index_Image == Api_Tertembak_p[i].Max_II )
{
Api_Tertembak_p[i].Index_Image = 0;
Api_Tertembak_p[i].Active_Flag = 0;
}
else
{
glEnable(GL_BLEND);
glBlendFunc(GL_DST_COLOR, GL_ZERO);

glBindTexture(GL_TEXTURE_2D, mask_object[Api_Tertembak_p[i].Index_Image]);
glBegin(GL_POLYGON);
glTexCoord2d(0.0, 0.0);
glVertex2d( Api_Tertembak_p[i].X1, Api_Tertembak_p[i].Y1);

glTexCoord2d(1.0, 0.0);
glVertex2d( Api_Tertembak_p[i].X2, Api_Tertembak_p[i].Y2);
glTexCoord2d(1.0, 1.0);
glVertex2d( Api_Tertembak_p[i].X3, Api_Tertembak_p[i].Y3);

glTexCoord2d(0.0, 1.0);
glVertex2d( Api_Tertembak_p[i].X4, Api_Tertembak_p[i].Y4);
glEnd();

glBlendFunc(GL_ONE, GL_ONE);
glBindTexture(GL_TEXTURE_2D, image_object[Api_Tertembak_p[i].Index_Image]);
glBegin(GL_POLYGON);
glTexCoord2d(0.0, 0.0);
glVertex2d( Api_Tertembak_p[i].X1, Api_Tertembak_p[i].Y1);
glTexCoord2d(1.0, 0.0);
glVertex2d( Api_Tertembak_p[i].X2, Api_Tertembak_p[i].Y2);

glTexCoord2d(1.0, 1.0);
glVertex2d( Api_Tertembak_p[i].X3, Api_Tertembak_p[i].Y3);

glTexCoord2d(0.0, 1.0);
glVertex2d( Api_Tertembak_p[i].X4, Api_Tertembak_p[i].Y4);
glEnd();

glDisable(GL_BLEND);
}
}
}
}

void Display_Api_Terbakar(Object_Api  Api_Terbakar_p[], int total_Api,
unsigned int image_object[], 
unsigned int mask_object[])
{
int i;

//api akan ditampilkan di layar bila
//Active_Flag = 1
for (i = 0; i < total_Api; i++)
{
if (Api_Terbakar_p[i].Active_Flag == 1)
{
Api_Terbakar_p[i].Counter_II++;
if (Api_Terbakar_p[i].Counter_II == Api_Terbakar_p[i].Delay_II)
{
Api_Terbakar_p[i].Counter_II = 0;
Api_Terbakar_p[i].Index_Image++;
}

if (Api_Terbakar_p[i].Index_Image == Api_Terbakar_p[i].Max_II)
{
Api_Terbakar_p[i].Index_Image = 0;
Api_Terbakar_p[i].Active_Flag = 0;
}
else
{
glEnable(GL_BLEND);
glBlendFunc(GL_DST_COLOR, GL_ZERO);

glBindTexture(GL_TEXTURE_2D, mask_object[Api_Terbakar_p[i].Index_Image]);
glBegin(GL_POLYGON);
glTexCoord2d(0.0, 0.0);
glVertex2d( Api_Terbakar_p[i].X1, Api_Terbakar_p[i].Y1);

glTexCoord2d(1.0, 0.0);
glVertex2d( Api_Terbakar_p[i].X2, Api_Terbakar_p[i].Y2);

glTexCoord2d(1.0, 1.0);
glVertex2d( Api_Terbakar_p[i].X3, Api_Terbakar_p[i].Y3);

glTexCoord2d(0.0, 1.0);
glVertex2d( Api_Terbakar_p[i].X4, Api_Terbakar_p[i].Y4);
glEnd();

glBlendFunc(GL_ONE, GL_ONE);
glBindTexture(GL_TEXTURE_2D, image_object[Api_Terbakar_p[i].Index_Image]);
glBegin(GL_POLYGON);
glTexCoord2d(0.0, 0.0);
glVertex2d( Api_Terbakar_p[i].X1, Api_Terbakar_p[i].Y1);
glTexCoord2d(1.0, 0.0);
glVertex2d( Api_Terbakar_p[i].X2, Api_Terbakar_p[i].Y2);

glTexCoord2d(1.0, 1.0);
glVertex2d( Api_Terbakar_p[i].X3, Api_Terbakar_p[i].Y3);

glTexCoord2d(0.0, 1.0);
glVertex2d( Api_Terbakar_p[i].X4, Api_Terbakar_p[i].Y4);
glEnd();

glDisable(GL_BLEND);

//update posisi Y1 s/d Y4
Api_Terbakar_p[i].Y1 -= 5.0;
Api_Terbakar_p[i].Y2 -= 5.0;
Api_Terbakar_p[i].Y3 -= 5.0;
Api_Terbakar_p[i].Y4 -= 5.0;
}
}
}
}

Demikian rekan-rekan cara membuat deteksi tabrakan, sampai disini dulu yah dan doa-in moga-moga event yang ogut buat di Ubud sukses, terima kasih.

Salam Sukses Selalu


Heriady
heriady.yoh@gmail.com



Artikel terkait

Panduan Lengkap Membuat Game Perang Shoot Them Up

Deteksi Tabrakan dengan Panjang Vektor / Radius

Deteksi Tabrakan dengan Proyeksi Vektor

Vektor R2

Tidak ada komentar:

Posting Komentar