Rabu, 22 Juli 2015

Membuat Musuh / Lawan Tanding untuk Game Shoot Them Up

Membuat Musuh / Lawan Tanding pada Game Shoot Them Up


Selamat Pagi rekan-rekan...pada pagi ini kembali kita akan meneruskan obrolan tentang game shoot them up dan kali ini yang akan ogut bicarakan adalah musuh yang akan kita buat untuk menjadi lawan tanding bagi pemain game (user).

Membuat musuh tidak jauh berbeda dengan membuat pesawat, yang membedakan keduanya pesawat digerakkan oleh user atau pemain game sedangkan musuh harus diprogram agar memberi perlawanan.


Menggerakkan Musuh
Untuk menggerakkan musuh ogut memakai enam variabel yang dipakai untuk memproses setiap langkah musuh. Variabel-variabel tersebut adalah:

1. char String_Movement[100];
2. int Index_M;
3. int Total_M;
4. char Object_Action[1];
5. int Max_OA;
6. int Counter_OA;

Dengan menggunakan variabel-variabel di atas musuh dapat kita program sesuai dengan kehendak kita, seperti belok kiri, maju ke depan, menembak, putar balik arah, dan lain-lain. Gerakan dari musuh tersebut dapat dikembangkan terus sesuai dengan kehendak rekan-rekan.

Untuk memperjelas tentang gerakan musuh yang akan kita program, perhatikan gambar di bawah ini:


Gambar di atas adalah gambar delapan arah pergerakan musuh, sebagai contoh jika “A099E100” berarti musuh bergerak ke atas sebanyak 99 langkah dan turun ke bawah sebanyak 100 langkah. Selain delapan arah di atas ogut juga menambahkan gerakan R rotasi ke kanan, L rotasi ke kiri, serta I untuk musuh yang diam di tempat.

Karakteristik Musuh
Variabel-variabel yang harus diisi agar musuh memiliki karakter adalah:

Object_Type
Object_Type untuk musuh yang berwarna putih/abu-abu diisi dengan nilai 1.

Posisi
Menentukan posisi musuh sama seperti menentukan posisi pesawat, dan sebaiknya posisi awal dari musuh berada  di luar layar.

Texture
Texture untuk musuh lebih sedikit dari texture untuk pesawat, variabel yang harus diisi untuk menentukan texture dari musuh adalah:  Index_Image=0, Delay_II=5, Counter_II=0, Max_II=4.

X_Step dan Y_Step
Kedua variabel di atas diisi dengan nilai 4.

L_Degree dan R_Degree
Variabel ini dipakai untuk menentukan sudut putar musuh ke kanan atau ke kiri, keduanya diisi dengan 15.

Power
Power untuk musuh yang aktif (tampil di layar)  tidak boleh 0, dan pada saat loading  Power musuh diisi 0.

Destruct
Jika musuh menabrak pesawat variabel ini yang akan dipakai untuk mengurangi Power dari pesawat. Nilai dari variabel ini ogut tentukan 100.

Gerakan musuh
Seperti telah dijelaskan di atas, butuh enam variable untuk memprogram gerakan musuh di layar.

String_Movement = ”E500R012A500R012”
Index_M = 0
Total_M = 0
Object_Action = 0
Max_OA = 0
Counter_OA = 0

Musuh berada di dalam layar
Variabel ini digunakan untuk deteksi tabrakan yang akan dijelaskan pada artikel yang lain. Ada dua variabel yang harus diperhatikan Inside_Screen bernilai 0 jika musuh berada di luar layar dan bernilai 1 jika berada di dalam.
Type_IS bernilai 1 untuk musuh yang berada di luar layar tetapi tetap hidup (Power > 0) dan bernilai 0 untuk musuh atau object yang berada di luar layar akan mati. Contoh object yang jika berada di luar layar akan mati adalah peluru, karena peluru yang posisinya berada di luar layar tidak perlu dihitung dan ditampilkan di layar.

Score
Untuk memberi nilai kepada pesawat jika berhasil menembak jatuh atau menghancurkan musuh. Untuk musuh tipe ini ogut isi dengan 50.

Pemrograman
Teknik pemrograman untuk musuh hampir sama dengan pada saat kita membuat pesawat fighter, hanya ada sedikit perbedaan:

Vektor
Pada artikel terdahulu ogut telah menjelaskan tentang vektor R2 dan memberi contoh tentang kegunaan vektor untuk perhitungan pembuatan game ini.

typedef struct
{
double i;
double j;
}Vektor2D;

extern double My_Pi;

Vektor2D Vektor_dari_2_Vertex(double Xtujuan, double Ytujuan, double Xasal, double Yasal)
{
Vektor2D new_vektor;

new_vektor.i = Xtujuan - Xasal;
new_vektor.j = Ytujuan - Yasal;

return new_vektor;
}

Vektor2D Vektor_diskala(double skala, Vektor2D My_Vektor)
{
Vektor2D new_vektor;

new_vektor.i = skala * My_Vektor.i;
new_vektor.j = skala * My_Vektor.j;

return new_vektor;
}
//perkalian titik dua buah vektor
double DotProduct_2_Vektor(Vektor2D Vektor1, Vektor2D Vektor2)
{
double temp_dotprodut;

temp_dotprodut = (Vektor1.i * Vektor2.i) + (Vektor1.j * Vektor2.j);

return temp_dotprodut;
}

double Panjang_Vektor(Vektor2D Vektor)
{
double temp_panjang;

temp_panjang = pow(Vektor.i, 2.0) + pow(Vektor.j, 2.0);

return sqrt(temp_panjang);
}

File teks
Sama seperti pesawat digunakan sebuah file teks untuk menyimpan nilai-nilai karakteristik musuh. Pada contoh berikut ogut membuat empat buah musuh dan nilai karakteristik musuh disimpan pada file musuh_1.txt.

Load
Loading nilai-nilai karakteristik musuh ke array.

Tentukan posisi musuh di dalam atau di luar layar
Untuk mendeteksi suatu musuh berada di luar atau di dalam layar  ogut menggunakan cara skala proyeksi vektor.

void Cek_Inside_Screen(Game_Object &My_Object, double Xmax_P, double Ymax_P)
{
Vektor2D V1, V2;
Vektor2D dot_vektor;
double temp_panjang1, temp_panjang2;
double skala_Vproyeksi1, skala_Vproyeksi2;
bool inside = true;

if (My_Object.Power == 0)
return;

//create vektor 1 dan 2
V1 = Vektor_dari_2_Vertex(-Xmax_P, Ymax_P, -Xmax_P, -Ymax_P);
V2 = Vektor_dari_2_Vertex(Xmax_P, -Ymax_P, -Xmax_P, -Ymax_P);

//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(My_Object.X1, My_Object.Y1, -Xmax_P, -Ymax_P);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor,V2) / temp_panjang2;

//cek kondisi untuk titik pertama
if (!(((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0))))
{
//titik satu berada diluar layar/screen

//vektor titik 2
dot_vektor = Vektor_dari_2_Vertex(My_Object.X2, My_Object.Y2, -Xmax_P, -Ymax_P);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

//cek kondisi untuk titik kedua
if (!(((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0))))
{
//titik dua berada diluar layar

//vektor titik 3
dot_vektor = Vektor_dari_2_Vertex(My_Object.X3, My_Object.Y3, -Xmax_P, -Ymax_P);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;

skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

//cek kondisi untuk titik ketiga
if (!(((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0))))
{
//titik tiga berada diluar area/screen

//vektor titik 4
dot_vektor = Vektor_dari_2_Vertex(My_Object.X3, My_Object.Y3,
-Xmax_P, -Ymax_P);

skala_Vproyeksi1 = DotProduct_2_Vektor(dot_vektor, V1) / temp_panjang1;
skala_Vproyeksi2 = DotProduct_2_Vektor(dot_vektor, V2) / temp_panjang2;

//cek kondisi untuk titik keempat
if (!(((skala_Vproyeksi1 >= 0.0) &&
(skala_Vproyeksi1 <= 1.0)) &&
((skala_Vproyeksi2 >= 0.0) &&
(skala_Vproyeksi2 <= 1.0))))
{
//titik empat berada diluar screen

//empat titik berada diluar screen
inside = false;
}
}
}
}

// object berada di dalam screen
if (inside)
{
My_Object.Inside_Screen = 1;
}
else
{
My_Object.Inside_Screen = 0;

//object yang mati jika di luar area
if (My_Object.Type_IS == 0)
{
My_Object.Power = 0;
}
}
}

Musuh Digerakkan
Fungsi yang ogut buat untuk menggerakkan musuh adalah sebagai berikut:

void Move_The_Object(Game_Object &My_Object)
{
char temp_str1[100];
char temp_str2[100];

//memindahkan posisi musuh yang Power != 0
if (My_Object.Power == 0)
return;

if (My_Object.Counter_OA == 0)
{
My_Object.Index_M = My_Object.Index_M + 1;

if (My_Object.Index_M > My_Object.Total_M)
My_Object.Index_M = 1;
//operasi string yang berguna untuk
//menentukan pergerakan dari musuh
//contoh "A099"
//Object_Action = "A"
//Max_OA=99

strcpy_s(temp_str1,"");
strncat_s(temp_str1, My_Object.String_Movement, My_Object.Index_M * 4);
_strrev(temp_str1);

//kosongkan string
strcpy_s(temp_str2,"");

//nilai yang didapat Max_OA + tipe movement
strncat_s(temp_str2, temp_str1, 4);

strcpy_s(temp_str1,"");
strncat_s(temp_str1, temp_str2, 3);

//dapat Max_OA, tinggal di konversi ke integer
_strrev(temp_str1);
My_Object.Max_OA = atoi(temp_str1);

_strrev(temp_str2);
strcpy_s(temp_str1,"");
strncat_s(temp_str1, temp_str2, 1);
//dapat Object_Action
//strcpy_s(My_Object.Object_Action,temp_str1);
My_Object.Object_Action[0] = temp_str1[0];

My_Object.Counter_OA++;
}

if (strcmp(My_Object.Object_Action,"A") == 0)
Move_ke_Utara(My_Object);

if (strcmp(My_Object.Object_Action,"B") == 0)
{
Move_ke_Utara(My_Object);
Move_ke_Timur(My_Object);
}

if (strcmp(My_Object.Object_Action,"C") == 0)
Move_ke_Timur(My_Object);

if (strcmp(My_Object.Object_Action,"D") == 0)
{
Move_ke_Selatan(My_Object);
Move_ke_Timur(My_Object);
}

if (strcmp(My_Object.Object_Action,"E") == 0)
Move_ke_Selatan(My_Object);

if (strcmp(My_Object.Object_Action,"F") == 0)
{
Move_ke_Selatan(My_Object);
Move_ke_Barat(My_Object);
}

if (strcmp(My_Object.Object_Action,"G") == 0)
Move_ke_Barat(My_Object);

if (strcmp(My_Object.Object_Action,"H") == 0)
{
Move_ke_Utara(My_Object);
Move_ke_Barat(My_Object);
}

if (strcmp(My_Object.Object_Action,"R") == 0)
Rotasi_kekanan(My_Object);

if (strcmp(My_Object.Object_Action,"L") == 0)
Rotasi_kekiri(My_Object);

My_Object.Counter_OA++;
if (My_Object.Counter_OA > My_Object.Max_OA)
My_Object.Counter_OA = 0;
}

//A
void Move_ke_Utara(Game_Object &My_Object)
{
My_Object.Y1 += My_Object.Y_Step;
My_Object.Y2 += My_Object.Y_Step;
My_Object.Y3 += My_Object.Y_Step;
My_Object.Y4 += My_Object.Y_Step;
}

//C
void Move_ke_Timur(Game_Object &My_Object)
{
My_Object.X1 += My_Object.X_Step;
My_Object.X2 += My_Object.X_Step;
My_Object.X3 += My_Object.X_Step;
My_Object.X4 += My_Object.X_Step;
}

//E
void Move_ke_Selatan(Game_Object &My_Object)
{
My_Object.Y1 -= My_Object.Y_Step;
My_Object.Y2 -= My_Object.Y_Step;
My_Object.Y3 -= My_Object.Y_Step;
My_Object.Y4 -= My_Object.Y_Step;
}

//G
void Move_ke_Barat(Game_Object &My_Object)
{
My_Object.X1 -= My_Object.X_Step;
My_Object.X2 -= My_Object.X_Step;
My_Object.X3 -= My_Object.X_Step;
My_Object.X4 -= My_Object.X_Step;
}

//R
void Rotasi_kekanan(Game_Object &My_Object)
{
Vektor2D vektor_tengah;
double Xmid, Ymid;
double tempX1, tempY1;
double tempX2, tempY2;
double tempX3, tempY3;
double tempX4, tempY4;
double sudut_radian;

vektor_tengah =  Vektor_dari_2_Vertex(My_Object.X3, My_Object.Y3, My_Object.X1, My_Object.Y1);

vektor_tengah =  Vektor_diskala(0.5, vektor_tengah);

//cari titik tengah
Xmid = My_Object.X1 + vektor_tengah.i;
Ymid = My_Object.Y1 + vektor_tengah.j;

//kurangi original titik
//dengan titik tengah(titik  pusat)
tempX1 = My_Object.X1 - Xmid;
tempY1 = My_Object.Y1 - Ymid;

tempX2 = My_Object.X2 - Xmid;
tempY2 = My_Object.Y2 - Ymid;

tempX3 = My_Object.X3 - Xmid;
tempY3 = My_Object.Y3 - Ymid;

tempX4 = My_Object.X4 - Xmid;
tempY4 = My_Object.Y4 - Ymid;

//proses rotasi
//untuk rotasi kekanan sudut dinegatifkan

//konversi ke radian
sudut_radian = -(My_Object.R_Degree / 180.0) * My_Pi;

//rotasi titik dengan rumus
My_Object.X1 = (tempX1 * cos(sudut_radian)) - (tempY1 * sin(sudut_radian));
My_Object.Y1 = (tempX1 * sin(sudut_radian)) + (tempY1 * cos(sudut_radian));
My_Object.X2 = (tempX2 * cos(sudut_radian)) - (tempY2 * sin(sudut_radian));
My_Object.Y2 = (tempX2 * sin(sudut_radian)) + (tempY2 * cos(sudut_radian));
My_Object.X3 = (tempX3 * cos(sudut_radian)) - (tempY3 * sin(sudut_radian));
My_Object.Y3 = (tempX3 * sin(sudut_radian)) + (tempY3 * cos(sudut_radian));

My_Object.X4 = (tempX4 * cos(sudut_radian)) - (tempY4 * sin(sudut_radian));
My_Object.Y4 = (tempX4 * sin(sudut_radian)) + (tempY4 * cos(sudut_radian));

//kembalikan posisi titik ke posisi awal
My_Object.X1 += Xmid; My_Object.Y1 += Ymid;
My_Object.X2 += Xmid; My_Object.Y2 += Ymid;
My_Object.X3 += Xmid; My_Object.Y3 += Ymid;
My_Object.X4 += Xmid; My_Object.Y4 += Ymid;
}

//L
void Rotasi_kekiri(Game_Object &My_Object)
{
Vektor2D vektor_tengah;
double Xmid, Ymid;
double tempX1, tempY1;
double tempX2, tempY2;
double tempX3, tempY3;
double tempX4, tempY4;
double sudut_radian;

vektor_tengah =  Vektor_dari_2_Vertex(My_Object.X3, My_Object.Y3, My_Object.X1, My_Object.Y1);

vektor_tengah =  Vektor_diskala(0.5, vektor_tengah);

//cari titik tengah
Xmid = My_Object.X1 + vektor_tengah.i;
Ymid = My_Object.Y1 + vektor_tengah.j;

//kurangi original titik
//dengan titik tengah(titik  pusat)
tempX1 = My_Object.X1 - Xmid;
tempY1 = My_Object.Y1 - Ymid;

tempX2 = My_Object.X2 - Xmid;
tempY2 = My_Object.Y2 - Ymid;

tempX3 = My_Object.X3 - Xmid;
tempY3 = My_Object.Y3 - Ymid;

tempX4 = My_Object.X4 - Xmid;
tempY4 = My_Object.Y4 - Ymid;

//konversi dari derajat ke radian
sudut_radian = (My_Object.L_Degree / 180.0) * My_Pi;

My_Object.X1 = (tempX1 * cos(sudut_radian)) - (tempY1 * sin(sudut_radian));
My_Object.Y1 = (tempX1 * sin(sudut_radian)) + (tempY1 * cos(sudut_radian));

My_Object.X2 = (tempX2 * cos(sudut_radian)) - (tempY2 * sin(sudut_radian));
My_Object.Y2 = (tempX2 * sin(sudut_radian)) + (tempY2 * cos(sudut_radian));

My_Object.X3 = (tempX3 * cos(sudut_radian)) - (tempY3 * sin(sudut_radian));
My_Object.Y3 = (tempX3 * sin(sudut_radian)) + (tempY3 * cos(sudut_radian));

My_Object.X4 = (tempX4 * cos(sudut_radian)) - (tempY4 * sin(sudut_radian));
My_Object.Y4 = (tempX4 * sin(sudut_radian)) + (tempY4 * cos(sudut_radian));

//kembalikan posisi titik ke posisi awal
My_Object.X1 += Xmid; My_Object.Y1 += Ymid;
My_Object.X2 += Xmid; My_Object.Y2 += Ymid;
My_Object.X3 += Xmid; My_Object.Y3 += Ymid;
My_Object.X4 += Xmid; My_Object.Y4 += Ymid;
}

Tampilkan Musuh
Musuh yang ditampilkan adalah musuh yang mempunyai Power lebih besar dari 0. Untuk itu sebelum menampilkannya Power dari musuh harus diisi dengan nilai 500.

bool Starting_my_APP()
{
...


//aktifkan 4 buah musuh dengan cara set Power > 0
Enemy_1[0].Power = 500; Enemy_1[1].Power = 500;
Enemy_1[2].Power = 500; Enemy_1[3].Power = 500;



}

void Display_Object_Terbang(Game_Object &My_Object, unsigned int image_object[], unsigned int mask_object[])
{
//yang ditampilkan jika musuh
//mempunyai Power > 0 dan berada di dalam layar
if ((My_Object.Power != 0) && (My_Object.Inside_Screen == 1))
{

My_Object.Counter_II++;

if (My_Object.Counter_II > My_Object.Delay_II)
{
My_Object.Index_Image++;
My_Object.Counter_II = 0;
}

//Max_II = 4
if (My_Object.Index_Image == My_Object.Max_II)
My_Object.Index_Image = 0;
//Display dengan tehnik masking
glEnable(GL_BLEND);
glBlendFunc(GL_DST_COLOR, GL_ZERO);

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

glTexCoord2d(1.0, 0.0);
glVertex2d( My_Object.X2, My_Object.Y2);

glTexCoord2d(1.0, 1.0);
glVertex2d( My_Object.X3, My_Object.Y3);

glTexCoord2d(0.0, 1.0);
glVertex2d( My_Object.X4, My_Object.Y4);
glEnd();

glBlendFunc(GL_ONE, GL_ONE);

glBindTexture(GL_TEXTURE_2D, image_object[My_Object.Index_Image]);
glBegin(GL_POLYGON);
glTexCoord2d(0.0, 0.0);
glVertex2d( My_Object.X1, My_Object.Y1);

glTexCoord2d(1.0, 0.0);
glVertex2d( My_Object.X2, My_Object.Y2);

glTexCoord2d(1.0, 1.0);
glVertex2d( My_Object.X3, My_Object.Y3);

glTexCoord2d(0.0, 1.0);
glVertex2d( My_Object.X4, My_Object.Y4);
glEnd();

glDisable(GL_BLEND);
}
}

Ok rekan-rekan selesai sudah cerita tentang membuat musuh untuk game shoot them up, lain waktu ogut akan meneruskan cerita ini sehingga rekan-rekan bisa membuat game sejenis.

Salam Game Shoot Them Up


Heriady
heriady.yoh@gmail.com




Artikel terkait

Panduan Lengkap Membuat Game Perang Shoot Them Up

Contoh Program Direct Sound

Manfaat Sudut Vektor Untuk Missile

Membuat Pesawat Fighter