SlideShare a Scribd company logo
1 of 83
Download to read offline
CSH202 – Pemrograman Game Tetris Dengan C#
Pemgraman
Game Tetris
Dengan C#
(CSH202)
Zeddy Iskandar
Project Otak
2005
Project Otak – http://otak.csharpindonesia.net 2
CSH202 – Pemrograman Game Tetris Dengan C#
Project Otak
Project otak adalah project community yang bertujuan untuk menyediakan resources
tentang informasi teknologi .NET bagi orang-orang yang ingin belajar teknologi .NET.
Trademark Acknowledgements
Team project otak akan berusaha menyediakan informasi trademark termasuk semua
produk yang telah disebut didalam buku ini.
Windows, Framework .NET, C#, dan Visual Studio.NET adalah trademark dari Microsoft
Credits
Project Manager Secretary
Agus Kurniawan Dewi Maya
Technical Writer
Zeddy Iskandar
Editor
Agus Kurniawan
Cover Designer
Danni Afasyah
Version 1.0
Printed: 2 April 2005
Book Code: CSH202
Update E-Book : http://otak.csharpindonesia.net
Semua materi yang ada didalam buku ini adalah satu kesatuan. Tidak boleh sebagian
atau seluruh materi didalam buku ini diubah tanpa seijin team project otak.
Project Otak – http://otak.csharpindonesia.net 3
CSH202 – Pemrograman Game Tetris Dengan C#
Kata Pengantar
Saya ingin membuat e-book yang fun dan informatif. Bagi saya, menulis adalah
pekerjaan yang membosankan, kecuali bila topik yang kita tulis membuat kita antusias.
Begitulah, saya ingin membuat e-book yang saya sendiri senang menulisnya. Mudah-
mudahan bermanfaat.
Apa yang Dapat Dipelajari
Membuat elemen grafik untuk game.
Menggunakan Visual Studio .Net.
Membuat simple game semacam Tetris.
Mengerti konsep Windows Message seperti WM_PAINT.
Membuat game secara object-oriented.
Mengaplikasikan Design Pattern Factory.
Target Pembaca
Banyak programmer yang sebelum menyentuh komputer menyentuh permainan konsol
seperti Nintendo, Sega, PS, dsb. Ketika mereka belajar programming, biasanya mereka
tertarik untuk membuat game, tapi tidak tahu harus mulai dari mana. Buku ini bisa
dijadikan fondasi mereka untuk belajar tentang game-programming.
Pembaca HARUS sudah mengerti bahasa programming C#. Andaikan tidak, saya
sarankan untuk membaca e-book CSH101: Pengenalan Bahasa C# oleh Agus
Kurniawan dkk. di website Otak Project (http://otak.csharpindonesia.net)
Pembaca juga MINIMAL sudah pernah membuat project di Visual Studio dan pernah
menggunakan Graphics Editing Program semacam Adobe Photoshop atau bahkan
Microsoft Paint. Bukan berarti Anda harus jago graphics design atau Photoshop Expert,
tapi cukup tahu bagaimana membuat simple object semacam segi empat dsb.
Baiklah, tanpa banyak basa-basi, mari kita mulai perjalanan kita ke dunia game-
programming.
Zeddy Iskandar
Curtin University of Technology (Malaysia Campus)
Project Otak – http://otak.csharpindonesia.net 4
CSH202 – Pemrograman Game Tetris Dengan C#
Tentang Penulis
Zeddy Iskandar
Zeddy Iskandar, mahasiswa semester akhir Curtin
University of Technology (Malaysia Campus), mulai
belajar programming dengan GW-BASIC sewaktu
sekolah Primary 5 di Colombo International School,
Sri Lanka. Semenjak sahabatnya membeli computer
Compaq 486-DX 33Mhz, dia menjadi lebih tertarik
dengan dunia komputer. Sempat vakum dari dunia
komputer ketika di Singapura (karena komputer ibu
kost nya dipindahkan) dan SMA di Jakarta (karena
komputernya mengeluarkan asap dan orangtua
tidak mau memperbaikinya). Ketika sang Ayah
berangkat tugas lagi ke Brunei, dunia komputer
khususnya programming mulai diarungi kembali.
Mulai dengan Visual Basic berangsur-angsur ke C,
C++, PHP, Java, JSP,. Sekarang konsentrasi di
Microsoft .Net platform. Cita-citanya adalah
mengajar programming di sebuah universitas kelak.
Dia dapat dihubungi melalui email
zeddy.iskandar@gmail.com
Kupersembahkan ebook ini untuk kedua
orangtuaku, yang akhirnya menyadari potensi
anaknya di dunia komputer =) Especially sang
Ayah, yang kartu kreditnya sering dibobol untuk
membeli buku programming di Amazon.com. I’ll
repay you someday, Dad!
Project Otak – http://otak.csharpindonesia.net 5
CSH202 – Pemrograman Game Tetris Dengan C#
Daftar Isi
Project Otak .......................................................................................................3
Credits.................................................................................................................3
Kata Pengantar.....................................................................................................4
Tentang Penulis....................................................................................................5
Daftar Isi ...............................................................................................................6
1. Menyusun Blok-Blok Tetris ...............................................................................8
1.1 Data Struktur untuk Blok Tetris............................................................................... 8
1.2 Data Struktur Papan Permainan............................................................................... 9
1.3 Elemen untuk blok Tetris....................................................................................... 10
2. Design Klas Blok.............................................................................................14
2.1 UML Diagram........................................................................................................ 15
2.2 Visual Studio .Net.................................................................................................. 15
2.3 Klas Blok ............................................................................................................... 17
2.4 Klas BlokGaris....................................................................................................... 19
2.5 Klas BlokKotak...................................................................................................... 23
2.7 Klas BlokZNormal................................................................................................. 26
2.8 Klas BlokZTerbalik ............................................................................................... 27
2.9 Klas BlokLNormal................................................................................................. 28
2.10 Klas BlokLTerbalik ............................................................................................. 30
3. Papan Permainan ...........................................................................................33
3.1 Menambahkan fields.............................................................................................. 35
3.2 Menambahkan methods ......................................................................................... 36
3.3 Koordinat Pixel dan Grid Unit............................................................................... 37
4. Klas ImageBlok dan Menggambar di atas Canvas .........................................39
4.1 Klas ImageBlok ..................................................................................................... 39
4.2 Modifikasi Klas Blok............................................................................................. 40
4.3 Definisi Draw() di Klas Blok................................................................................. 41
5. Mengaplikasikan Factory Pattern...................................................................44
5.1 Klas BlokFactory ................................................................................................... 44
5.2 Method BuatBlokBaru() untuk klas PapanPermainan........................................... 46
6. Menggunakan Invalidate() ..............................................................................48
6.1 Penambahan method SetElemen() dan GetElemen()............................................. 49
6.2 Modifikasi klas Blok.............................................................................................. 50
6.3 Modifikasi PapanPermainan.BuatBlokBaru() ....................................................... 51
6.4 Sekilas tentang Invalidate().................................................................................... 51
7. Merespons Keyboard Event............................................................................54
7.1 Merespons key Bawah........................................................................................... 55
7.2 Merespons key Kiri................................................................................................ 56
7.3 Merespons Key Kanan........................................................................................... 56
8. Menumpuk Blok ..............................................................................................58
8.1 Modifikasi Klas Blok............................................................................................. 58
Project Otak – http://otak.csharpindonesia.net 6
CSH202 – Pemrograman Game Tetris Dengan C#
8.2 Mengkontrol Penurunan Blok................................................................................ 58
8.3 Mengkontrol Penggeseran Kiri.............................................................................. 59
8.4 Mengkontrol Penggeseran Kanan.......................................................................... 61
9. Merotasikan Blok ............................................................................................63
9.1 Menambahkan ICloneable ke klas Blok ................................................................ 63
9.2 Method BisaRotasi() untuk klas PapanPermainan................................................. 64
9.3 Modifikasi KeyPress-handler................................................................................. 66
10. Menghilangkan Baris Komplet ......................................................................68
10.1 Menampilkan “Blink” effect................................................................................ 70
11. Menggunakan Timer.....................................................................................74
11.1 Menambahkan Timer........................................................................................... 74
11.2 Kapan Game Over?.............................................................................................. 77
11.3 Dua Bugs lagi…................................................................................................... 78
PENUTUP Volum 1.............................................................................................79
Lampiran.............................................................................................................80
Strukutur Organisasi Project Otak 2005-2006 ....................................................81
Program Donatur Project Otak............................................................................83
Project Otak – http://otak.csharpindonesia.net 7
CSH202 – Pemrograman Game Tetris Dengan C#
1. Menyusun Blok-Blok Tetris
Ada banyak cara membuat program Tetris. Cara saya mungkin tidak efisien, tapi
setidaknya simple.
1.1 Data Struktur untuk Blok Tetris
Baiklah, kita mulai dari dasar. Bagaimana menggambar blok Tetris?
Bayangkan ARRAY 2-dimensi (dalam dunia .Net Framework dikenal dengan rectangular
array), dengan panjang-lebar 4x4:
Data struktur ini bisa digunakan untuk menyimpan definisi blok-blok Tetris yang ada.
Tapi tentunya menyimpan sebuah bitmap atau file grafik ke dalam array akan memakan
tempat. Lantas bagaimana implementasinya? Blok “Kros” diatas tadi dapat di-
implementasikan menggunakan array of boolean values. Jadi yang disimpan di array
adalah TRUE atau FALSE:
F F F F
F T F F
T T T F
F F F F
Kemudian, pada saatnya dibutuhkan untul ditampilkan, barulah kita ganti tiap-tiap TRUE
dengan sebuah image pixel berwarna.
Project Otak – http://otak.csharpindonesia.net 8
CSH202 – Pemrograman Game Tetris Dengan C#
1.2 Data Struktur Papan Permainan
Kita dapat menggunakan boolean array juga sebagi papan permainan dimana blok-blok
Tetris akan diletakkan. Misalnya dengan ukuran panjang-lebar 12x20:
Project Otak – http://otak.csharpindonesia.net 9
CSH202 – Pemrograman Game Tetris Dengan C#
1.3 Elemen untuk blok Tetris
Telah saya sebutkan bahwa sebuah blok Tetris disimpan sebagai 4x4 array dan
manakala ada value True, maka disitulah kita insert sebuah box grafik.
Buka Adobe Photoshop atau aplikasi grafik favorit Anda sekarang. Pertama saya buat
asumsi bahwa sebuah blok elemen akan memiliki pixel size 20x20. Sehingga di Adobe,
saya buat File→New dgn spesifikasi berikut:
Width = 240 karena 12 blok x 20 pixel width.
Height = 400 karena 20 blok x 20 pixel height.
RGB karena kita ingin tiap blok Tetris (garis, kros, kotak, dsb) mempunyai warna yg
berbeda.
Selanjutnya saya cek apakah papan permainan kelihatan pas (tidak terlalu besar atau
kecil):
Project Otak – http://otak.csharpindonesia.net 10
CSH202 – Pemrograman Game Tetris Dengan C#
Saya menggunakan opsi berikut di Adobe:
Edit→Preferences→Units & Rulers
Units::Rulers::Pixels
Edit→Preferences→Guides, Grid & Slices
Gridline every: 20 pixels
Subdivision: 1
View→Show→Grid
View→Rulers
Project Otak – http://otak.csharpindonesia.net 11
CSH202 – Pemrograman Game Tetris Dengan C#
Karena di monitor saya kelihatan OK, saya tentukan bahwa pixel width dan height = 20.
Misal ini kurang pas (apalagi Anda menggunakan resolusi 640x480 di jaman begini),
silahkan sesuaikan dengan monitor Anda, mungkin misalnya menjadi 12x12 pixel.
Sekarang kita buatkan blok elemen untuk 7 warna (karena akan ada 7 blok Tetris).
File→New:
Width: 20 pixels
Height: 20 pixels
Colour Mode: RGB
Gunakan Paint Bucket Tool untuk mewarnai pixel:
Buat 7 macam dengan spesifikasi warna berikut:
No. Warna RGB value
1. Merah R:255, G:0, B:0
2. Kuning R:255, G:255, B:0
3. Hijau R:0, G:255, B:0
4. Biru R:0, G:0, B:255
5. Magenta R:255, G:0, B:255
6. Cyan R:0, G:255, B:255
7. Coklat R: 198, G:156, B:109
Project Otak – http://otak.csharpindonesia.net 12
CSH202 – Pemrograman Game Tetris Dengan C#
Setelah itu, silahkan drag-n-drop masing-masing blok elemen berwarna untuk menyusun
blok-blok Tetris.
Bagaimana semangat Anda sekarang? Kita akan mulai menuliskan kode di bab
selanjutnya!
Project Otak – http://otak.csharpindonesia.net 13
CSH202 – Pemrograman Game Tetris Dengan C#
2. Design Klas Blok
Di sini saya definisikan apa yang dimaksud dengan Blok. Definisi ini akan dipakai
sampai akhir buku.
Blok adalah bentuk-bentuk (shape) yang harus disusun dalam game Tetris. Blok ini ada
7 macam:
1. Baris 5. ZTerbalik
2. Kotak 6. LNormal
3. Kros 7. LTerbalik
4. ZNormal
Inilah saatnya untuk menggunakan konsep inheritance dalam object-oriented
programming.
Project Otak – http://otak.csharpindonesia.net 14
CSH202 – Pemrograman Game Tetris Dengan C#
2.1 UML Diagram
KoordKiriAtas akan dijelaskan pada bab berikutnya.
Panjang dan Lebar adalah 4x4. Karena value ini tetap, maka saya menggunakan const
modifier. Dan karena ini konstan, kita boleh membuatnya public.
Draw() berisi kode untuk mengupdate gambar blok di atas papan permainan. Method ini
tidak virtrual karena kodenya sama untuk semua subclass.
RotateAtas() dsb adalah kode untuk mengubah posisi blok sesuai dengan tombol yang
ditekan user pada keyboard. Method ini virtual karena tiap-tiap blok jika di-rotasi akan
berbeda posisinya dari blok yang lain.
2.2 Visual Studio .Net
Sekarang saatnya untuk membuat VS.Net dan mulai menambahkan kode sedikit demi
sedikit.
Pilih File→New→Project:
Project Type: Visual C# Projects
Template: Windows Application
Name: dotTetrus
Location: Terserah
*Nama “Tetris” adalah hak intelektual seorang programmer Russia yang sekarang kaya
karena mendapatkan royalti dari game Tetris. Oleh karenanya, kita tidak boleh membuat
game dengan nama “Tetris” atau yang bunyinya mirip.
Project Otak – http://otak.csharpindonesia.net 15
CSH202 – Pemrograman Game Tetris Dengan C#
Untuk saat ini, kita ignore User Interface atau Windows Forms nya. Kita konsentrasi
membuat class dahulu.
Lihat Class View.
Right-click Project dotTetrus, pilih Add→Class.
Project Otak – http://otak.csharpindonesia.net 16
CSH202 – Pemrograman Game Tetris Dengan C#
Isi sesuai dgn di atas dan click Finish.
2.3 Klas Blok
Berikut kode untuk variabel-variabel konstan:
public class Blok
{
// Variabel-variabel konstan
public const int LEBAR = 4;
public const int PANJANG = 4;
// digunakan oleh BlokFactory nantinya
public const int BARIS = 0;
public const int KOTAK = 1;
public const int KROS = 2;
public const int ZNORMAL = 3;
public const int ZTERBALIK = 4;
public const int LNORMAL = 5;
public const int LTERBALIK = 6;
Sebelum menambahkan variabel-variabel private, kita harus Add Reference
System.Drawing dahulu agar bisa menggunakan struktur System.Drawing.Point.
Caranya klik Project→Add Reference, cari System.Drawing.dll dan klik Select:
Project Otak – http://otak.csharpindonesia.net 17
CSH202 – Pemrograman Game Tetris Dengan C#
Klik OK setelah itu.
Lalu kita tambahkan using statement di bagian atas file Blok.cs:
using System;
using System.Drawing;
Nah, sekarang kita bisa menggunakan struct Point di class Blok. Sambung dari kode
sebelumnya:
// Public karena tidak perlu validasi rvalue
public Point KoordKiriAtas;
// Variabel-variable hidden
protected bool[,] _elemen;
public Blok()
{
// init 4x4 bool array
_elemen = new bool[PANJANG,LEBAR];
}
protected void ResetElemen()
{
// set semua values array menjadi false
for (int i = 0; i < PANJANG; i++)
for (int j = 0; j < LEBAR; j++)
_elemen[i,j] = false;
}
public void Draw()
{
}
public virtual void RotateAtas()
{
}
public virtual void RotateBawah()
{
}
Project Otak – http://otak.csharpindonesia.net 18
CSH202 – Pemrograman Game Tetris Dengan C#
public virtual void RotateKanan()
{
}
public virtual void RotateKiri()
{
}
_koordKiriAtas dan _elemen perlu diakses dari subclass-subclass seperti BlokGaris,
oleh karena itu modifier mereka adalah protected dan bukan private.
Method Draw() adalah sama untuk semua blok, namun kita akan kembali setelah
mempelajari tentang Device Context.
Method-method yg virtual akan di override oleh masing-masing subclass nantinya.
ResetElemen() diperlukan untuk mereset semua elemen blok sebelum di-rotasi. Method
ini protected karena tidak boleh dipanggil dari luar class Blok, namun harus dapat
diakses oleh subclass seperti BlokGaris dsb.
2.4 Klas BlokGaris
Sekarang kita siap untuk membuat 7 subclass Blok. Pilih Class View, right-click
dotTetrus Project→Add Class:
Isi sesuai dengan bagan diatas, namun jangan klik OK terlebih dahulu.
Pilih opsi Base Class dari sebelah kiri:
Project Otak – http://otak.csharpindonesia.net 19
CSH202 – Pemrograman Game Tetris Dengan C#
Pilih Blok sebagai Base Class, dan klik Finish.
Nah, dalam subclass BlokGaris dan subclass-subclass berikutnya, kita hanya perlu
mengisi kode untuk constructor dan meng-override virtual methods dari base class Blok.
Berikut data struktur untuk BlokGaris:
Oleh karenanya kode untuk constructor nya adalah:
public BlokGaris() : base()
{
_elemen[0,0] = true;
_elemen[1,0] = true;
_elemen[2,0] = true;
_elemen[3,0] = true;
}
Statement base() adalah untuk memanggil base class konstruktor Blok() sebelum meng-
konstruk sebuah BlokGaris instance. Ini sangat essensial karena hanya di konstruktor
Blok() –lah kita meng-initialize array kita menjadi 4x4 boolean array!
Sekarang kita harus meng-override semua virtual methods dari Base Class Blok. Tidak
ingat? Caranya mudah dengan menggunakan Class View.
Di Class View, pilih class BlokGaris, klik tanda + pada Bases and Interfaces.
Right-click method RotateAtas() → pilih Add → Override.
Project Otak – http://otak.csharpindonesia.net 20
CSH202 – Pemrograman Game Tetris Dengan C#
Lakukan hal ini untuk RotateBawah(), RotateKanan(), RotateKiri().
Untuk RotateAtas() dan RotateBawah() tidak akan mengubah posisi elemen BlokGaris:
Maka kodenya pun sama dengan kode konstruktor:
public override void RotateAtas()
{
base.ResetElemen();
_elemen[0,0] = true;
_elemen[1,0] = true;
_elemen[2,0] = true;
_elemen[3,0] = true;
}
public override void RotateBawah()
{
this.RotateAtas();
}
*Tips: Karena kode di tiga method ini sama (konstruktor, RotateAtas dan RotateBawah),
maka dengan prinsip refactoring, seharusnya kode yang sama ini dipindah ke dalam
suatu method, dan method inilah yang harusnya dipanggil dari konstruktor, RotateAtas()
dan RotateBawah().
Jika di-rotasi ke kanan akan berubah menjadi:
Project Otak – http://otak.csharpindonesia.net 21
CSH202 – Pemrograman Game Tetris Dengan C#
Rotasi ke kanan dan kiri juga hasilnya akan sama, maka kode mereka menjadi:
public override void RotateKanan()
{
base.ResetElemen();
_elemen[3,0] = true;
_elemen[3,1] = true;
_elemen[3,2] = true;
_elemen[3,3] = true;
}
public override void RotateKiri()
{
this.RotateKanan();
}
*Sekarang saatnya Anda mengcompile semua .cs file. Ini diperlukan setiap selesai
menulis suatu class baru, untuk make sure error-error di kelas tersebut diperbaiki dahulu
sebelum menulis sebuah class lain.
Klik Build → Build Solution. Jika Anda menemui error, berarti Anda perlu meninjau
kembali kode Anda! Mohon cek lagi pelan-pelan dan sabar sebelum melanjutkan ke klas
berikutnya…
Project Otak – http://otak.csharpindonesia.net 22
CSH202 – Pemrograman Game Tetris Dengan C#
2.5 Klas BlokKotak
*Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right-
click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah!
Klas ini mungkin yang termudah karena semua rotasi tidak menghasilkan apa-apa.
Sehingga kode untuk method RotasiAtas(), RotasiBawah(), dsb adalah kosong.
Berikut bagan elemen ketika sebuah klas BlokKotak dibuat:
Oleh karenanya, kode untuk konstruktor-nya ialah:
public class BlokKotak : dotTetrus.Blok
{
public BlokKotak() : base()
{
_elemen[1,0] = true;
_elemen[1,1] = true;
_elemen[2,0] = true;
_elemen[2,1] = true;
}
…
Dan kosong untuk semua method Rotasi() nya:
public override void RotateAtas()
{
}
public override void RotateBawah()
{
}
public override void RotateKanan()
{
}
public override void RotateKiri()
{
}
Sekali lagi, tekan kombinasi tombol Ctrl – Shift – B untuk mem-build solution dan
perhatikan apakah ada error atau tidak!
Project Otak – http://otak.csharpindonesia.net 23
CSH202 – Pemrograman Game Tetris Dengan C#
2.6 Klas BlokKros
*Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right-
click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah!
Untuk klas ini, kita akan memiliki kode yang berbeda untuk masing-masing RotasiAtas(),
RotasiBawah(), RotasiKiri() dan RotasiKanan()
Pada saat dibentuk, BlokKros akan menghadap ke atas, oleh karenanya kode untuk
Constructor dan RotasiAtas menjadi sama:
public class BlokKros : dotTetrus.Blok
{
public BlokKros() : base()
{
this.RotateAtas();
}
public override void RotateAtas()
{
base.ResetElemen();
_elemen[1,1] = true;
_elemen[2,0] = true;
_elemen[2,1] = true;
_elemen[2,2] = true;
}
…
Untuk RotasiBawah() menjadi:
Project Otak – http://otak.csharpindonesia.net 24
CSH202 – Pemrograman Game Tetris Dengan C#
public override void RotateBawah()
{
base.ResetElemen();
_elemen[2,0] = true;
_elemen[2,1] = true;
_elemen[2,2] = true;
_elemen[3,1] = true;
}
Untuk RotasiKanan() menjadi:
public override void RotateKanan()
{
base.ResetElemen();
_elemen[1,1] = true;
_elemen[2,1] = true;
_elemen[3,1] = true;
_elemen[2,2] = true;
}
Untuk RotasiKiri() menjadi:
public override void RotateKiri()
{
base.ResetElemen();
_elemen[2,0] = true;
_elemen[1,1] = true;
_elemen[2,1] = true;
_elemen[3,1] = true;
}
Project Otak – http://otak.csharpindonesia.net 25
CSH202 – Pemrograman Game Tetris Dengan C#
2.7 Klas BlokZNormal
*Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right-
click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah!
Untuk klas ini, kita akan memiliki kode RotasiAtas() dan RotasiBawah() yang sama,
RotasiKiri() dan RotasiKanan() pun sama.
Pada saat dibentuk, BlokZNormal akan menghadap ke atas, oleh karenanya kode untuk
Constructor dan RotasiAtas menjadi sama:
public class BlokZNormal : dotTetrus.Blok
{
public BlokZNormal() : base()
{
this.RotateAtas();
}
public override void RotateAtas()
{
base.ResetElemen();
_elemen[3,0] = true;
_elemen[3,1] = true;
_elemen[2,1] = true;
_elemen[2,2] = true;
}
public override void RotateBawah()
{
this.RotateAtas();
}
…
Dan untuk RotasiKanan() dan RotasiKiri() menjadi:
public override void RotateKanan()
Project Otak – http://otak.csharpindonesia.net 26
CSH202 – Pemrograman Game Tetris Dengan C#
{
base.ResetElemen();
_elemen[1,0] = true;
_elemen[2,0] = true;
_elemen[2,1] = true;
_elemen[3,1] = true;
}
public override void RotateKiri()
{
this.RotateKanan();
}
2.8 Klas BlokZTerbalik
*Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right-
click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah!
Untuk klas ini, kita akan memiliki kode RotasiAtas() dan RotasiBawah() yang sama,
RotasiKiri() dan RotasiKanan() pun sama.
Pada saat dibentuk, BlokZTerbalik akan menghadap ke atas, oleh karenanya kode
untuk Constructor dan RotasiAtas menjadi sama:
public class BlokZTerbalik : dotTetrus.Blok
{
public BlokZTerbalik() : base()
{
this.RotateAtas();
}
public override void RotateAtas()
{
base.ResetElemen();
_elemen[2,0] = true;
_elemen[2,1] = true;
_elemen[3,1] = true;
_elemen[3,2] = true;
}
public override void RotateBawah()
{
this.RotateAtas();
}
…
Project Otak – http://otak.csharpindonesia.net 27
CSH202 – Pemrograman Game Tetris Dengan C#
Dan untuk RotateKanan() dan RotateKiri() menjadi:
public override void RotateKanan()
{
base.ResetElemen();
_elemen[2,1] = true;
_elemen[3,1] = true;
_elemen[1,2] = true;
_elemen[2,2] = true;
}
public override void RotateKiri()
{
this.RotateKanan();
}
2.9 Klas BlokLNormal
*Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right-
click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah!
Pada saat dibentuk, BlokLNormal akan menghadap ke atas, oleh karenanya kode untuk
Constructor dan RotasiAtas menjadi sama:
public class BlokLNormal : dotTetrus.Blok
{
public BlokLNormal() : base()
{
this.RotateAtas();
}
public override void RotateAtas()
{
base.ResetElemen();
Project Otak – http://otak.csharpindonesia.net 28
CSH202 – Pemrograman Game Tetris Dengan C#
_elemen[1,1] = true;
_elemen[2,1] = true;
_elemen[3,1] = true;
_elemen[3,2] = true;
}
…
Untuk RotateBawah() menjadi:
public override void RotateBawah()
{
base.ResetElemen();
_elemen[1,1] = true;
_elemen[1,2] = true;
_elemen[2,2] = true;
_elemen[3,2] = true;
}
Dan untuk RotateKanan() menjadi:
public override void RotateKanan()
{
base.ResetElemen();
_elemen[2,1] = true;
_elemen[2,2] = true;
_elemen[2,3] = true;
_elemen[3,1] = true;
}
Project Otak – http://otak.csharpindonesia.net 29
CSH202 – Pemrograman Game Tetris Dengan C#
Untuk RotateKiri() menjadi:
public override void RotateKiri()
{
base.ResetElemen();
_elemen[2,3] = true;
_elemen[3,1] = true;
_elemen[3,2] = true;
_elemen[3,3] = true;
}
2.10 Klas BlokLTerbalik
*Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right-
click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah!
Pada saat dibentuk, BlokLTerbalik akan menghadap ke atas, oleh karenanya kode untuk
Constructor dan RotasiAtas() menjadi sama:
public class BlokLTerbalik : dotTetrus.Blok
{
public BlokLTerbalik() : base()
{
this.RotateAtas();
}
public override void RotateAtas()
{
base.ResetElemen();
_elemen[1,2] = true;
_elemen[2,2] = true;
_elemen[3,2] = true;
_elemen[3,1] = true;
}
Project Otak – http://otak.csharpindonesia.net 30
CSH202 – Pemrograman Game Tetris Dengan C#
Dan untuk RotateBawah() menjadi:
public override void RotateBawah()
{
base.ResetElemen();
_elemen[1,1] = true;
_elemen[2,1] = true;
_elemen[3,1] = true;
_elemen[1,2] = true;
}
Untuk RotateKanan() menjadi:
public override void RotateKanan()
{
base.ResetElemen();
_elemen[3,1] = true;
_elemen[3,2] = true;
_elemen[3,3] = true;
_elemen[2,1] = true;
}
Dan untuk RotateKiri() menjadi:
Project Otak – http://otak.csharpindonesia.net 31
CSH202 – Pemrograman Game Tetris Dengan C#
public override void RotateKiri()
{
base.ResetElemen();
_elemen[2,1] = true;
_elemen[2,2] = true;
_elemen[2,3] = true;
_elemen[3,3] = true;
}
Dan kita selesai untuk semua klas blok, kecuali Blok.Draw(). Tekan Ctrl – Shift – B dan
pastikan tidak ada error sampai sejauh ini!
Project Otak – http://otak.csharpindonesia.net 32
CSH202 – Pemrograman Game Tetris Dengan C#
3. Papan Permainan
Kira-kira apa saja yang perlu diketahui oleh Papan Permainan?
1. Posisi tinggi terkini. Bila tinggi ini dibawah grid 0, maka kita tahu bahwa game over.
Grid 0 adalah grid paling atas.
2. Blok terkini yang sedang diturunkan. Kita juga harus me-respond command dari user
(atas, bawah, kiri, kanan) pada saat blok terkini sedang diturunkan.
3. Harus bisa mengecek apakah ada baris yang bisa dihilangkan.
4. Harus tahu warna tiap-tiap grid, sehingga tidak salah mewarnai grid.
UML untuk kelas PapanPermainan ialah:
Tentunya ini belum complete. Masih ada yang harus kita tambahkan nantinya.
Sekarang kita siapkan dulu klas PapanPermainan ini!
Pertama, klik nama Form1 di Class View, dan lihat Properties nya. Ganti namanya
menjadi PapanPermainan:
Project Otak – http://otak.csharpindonesia.net 33
CSH202 – Pemrograman Game Tetris Dengan C#
Kemudian, klik nama Form1 di Solution Explorer, dan lihat Properties nya. Ganti
filename nya menjadi PapanPermainan.cs
Sekarang kita ke Windows Forms Designer (PapanPermainan.cs [Design] tab), dan
ubah Properties nya:
Properties Values
BackColor Pilih Custom, lalu klik warna hitam.
Text dotTetrus
FormBorderStyle FixedSingle
Size::Width 240
Size::Height 400
MaximizeBox False
StartPosition CenterScreen
Kemudian, klik menu View → Code. Sebelum kita mulai lebih lanjut, kita harus me-
rename semua text Form1 menjadi PapanPermainan. Tekan tombol Ctrl – H:
Isi seperti diatas dan klik Replace All.
Project Otak – http://otak.csharpindonesia.net 34
CSH202 – Pemrograman Game Tetris Dengan C#
Sebelum mulai lebih lanjut, Build Solution (Ctrl – Shift – B) dan cek apakah ada build
error.
3.1 Menambahkan fields
Right-click PapanPermainan di Class View, pilih Add→Field.
Isi seperti di atas, lalu klik Finish.
Sekarang kita tahu lokasi di mana VS.Net menaruh variabel-variabel fields kita (paling
bawah), oleh karenanya selanjutnya kita tidak usah menggunakan wizard, cukup
menaruhnya di bagian bawah kode:
public const int TINGGI = 20;
public const int LEBAR = 12;
// Variabel-variabel hidden
private Blok _terkiniBlok;
private int _terkiniTinggiTumpukan;
private int[,] _elemen;
Sekarang kita lompat ke konstruktor PapanPermainan(), dan
tambahkan kode untuk initialize _elemen:
public PapanPermainan()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent
call
//
this._elemen = new int[TINGGI,LEBAR];
}
Kenapa int? Karena kita harus menyimpan value warna untuk tiap elemen (ada 7 warna
blok ditambah 1 warna background hitam).
Project Otak – http://otak.csharpindonesia.net 35
CSH202 – Pemrograman Game Tetris Dengan C#
3.2 Menambahkan methods
Right-click PapanPermainan di Class View sekali lagi, kali ini pilih Add→Method:
Isi seperti di atas dan klik Finish.
Inilah kode untuk CekBaris():
private void CekBaris()
{
// 1. Cek berapa baris yg harus dihilangkan
int jmlhBarisYgDitemukan = 0;
bool selesai = false;
for (int i = TINGGI-1;
i >= _terkiniTinggiTumpukan && !selesai; i--)
{ // cek dari bawah ke atas
for (int j = 0; j < LEBAR && !selesai; j++)
{
if (_elemen[i,j] == HITAM)
selesai = true;
}
if (!selesai)
++jmlhBarisYgDitemukan;
}
if (jmlhBarisYgDitemukan == 0)
return; // nggak perlu reDraw tumpukan
// Kode untuk me-reDraw tumpukan
…
Nanti kita akan selesaikan kode dalam method ini. Untuk sekarang, kita hanya perlu
berapa jumlah baris yang harus dihilangkan. Method ini mudah dimengerti, intinya kalau
suatu baris semuanya tidak berwarna hitam, maka increment jumlah baris yang harus
dihilangkan.
Apakah konstan HITAM diatas sudah kita definisikan? Kalau begitu, waktunya
menambahkan kode konstan warna di bagian fields:
// Konstan-konstan warna
public const int HITAM = 0;
public const int MERAH = 1;
public const int KUNING = 2;
public const int HIJAU = 3;
Project Otak – http://otak.csharpindonesia.net 36
CSH202 – Pemrograman Game Tetris Dengan C#
public const int BIRU = 4;
public const int MAGENTA = 5;
public const int CYAN = 6;
public const int COKLAT = 7;
dan menambahkan kode di konstruktor PapanPermainan():
this._elemen = new int[TINGGI,LEBAR];
for (int i = 0; i < TINGGI; i++)
for (int j = 0; j < LEBAR; j++)
_elemen[i,j] = HITAM;
Lanjut ke method TurunkanBlok()!
Sebelum berlanjut, kita tambahkan lagi satu konstan:
public const int OFFSETPIXEL = 20;
karena 1 grid = 20x20 pixels.
3.3 Koordinat Pixel dan Grid Unit
Semua drawing yang akan dilakukan di atas windows forms kita harus menggunakan
koordinat pixel. Akan tetapi, kita menyimpan data struktur _elemen PapanPermainan
sebagai 20x12 integer array. Bagaimana mengkonversi dari unit pixel ke unit grid dan
sebaliknya?
Lihat gambar diatas. Koordinat default windows forms menggunakan (0,0) sebagai titik
paling ujung kiri-atas. Mudah terlihat bahwa untuk mengubah koordinat (80,20) ke dalam
grid unit menjadi [1,4] adalah [y / 20, x / 20].
Sekarang kita dapat melanjutkan menulis method TurunkanBlok:
private void TurunkanBlok()
{
// 1. hitamkan baris bekas blok
int grid_i = _terkiniBlok.KoordKiriAtas.Y / OFFSETPIXEL;
int grid_j = _terkiniBlok.KoordKiriAtas.X / OFFSETPIXEL;
for (int i = grid_i, j = grid_j;
j < Blok.PANJANG; j++)
{
Project Otak – http://otak.csharpindonesia.net 37
CSH202 – Pemrograman Game Tetris Dengan C#
_elemen[i,j] = HITAM;
}
// 2. Turunkan blok 1 grid unit
System.Drawing.Point koordLama =
_terkiniBlok.KoordKiriAtas;
_terkiniBlok.KoordKiriAtas.Y += OFFSETPIXEL;
}
Apa yang kita lakukan di method ini? Lihat gambar di bawah untuk jelasnya:
Tentunya method ini belum complete karena saya belum memberitahukan bagaimana
mewarnai papan permainan dan menampilkan blok. Untuk bab-bab selanjutnya,
methods-methods PapanPermainan akan di-refine jadi pastikan tidak ada error dalam
kode anda sekarang (tekan Ctrl – Shift – B).
Project Otak – http://otak.csharpindonesia.net 38
CSH202 – Pemrograman Game Tetris Dengan C#
4. Klas ImageBlok dan Menggambar di atas
Canvas
Ingat 20x20 pixel berwarna yang kita buat di Bab 0 sebelumnya? Convert mereka ke
dalam file dengan format .GIF (Gunakan File → Save As) dan rename mereka menjadi
Merah.gif, Kuning.gif, dst.
Copy semua file *.gif ini ke dalam folder D:ProjectsdotNetdotTetrusbinDebug. Jika
Anda tidak memiliki folder Debug, pastikan anda telah mem-Build Solution terlebih
dahulu (Ctrl – Shift – B).
4.1 Klas ImageBlok
Gunakan Class View untuk Add→Class:
Isi data seperti di atas dan klik Finish.
Di atas klas ini, kita tambahkan using statement:
using System.Drawing;
Lantas isi dengan konstan berikut:
public class ImageBlok
{
public static Image MERAH;
public static Image KUNING;
public static Image HIJAU;
public static Image BIRU;
public static Image MAGENTA;
public static Image CYAN;
public static Image COKLAT;
Project Otak – http://otak.csharpindonesia.net 39
CSH202 – Pemrograman Game Tetris Dengan C#
static ImageBlok()
{
MERAH = Image.FromFile("Merah.gif");
KUNING = Image.FromFile("Kuning.gif");
HIJAU = Image.FromFile("Hijau.gif");
BIRU = Image.FromFile("Biru.gif");
MAGENTA = Image.FromFile("Magenta.gif");
CYAN = Image.FromFile("Cyan.gif");
COKLAT = Image.FromFile("Coklat.gif");
}
}
Kita menggunakan static constructor – static ImageBlok() untuk meng-initialize
variabel-variabel static kita. Perlu dicatat bahwa kita tidak dapat membuat variabel
MERAH dsb sebagai const karena mereka tidak dapat di-init pada waktu kompilasi.
Membuat mereka sebagai public memang menyalahi prinsip object-oriented
programming, jadi memang seharusnya dibuat private dan menggunakan Properties.
Hanya menurut saya untuk situasi ini terlihat overkill. Tergantung Anda seberapa jauh
ingin menerapkan OOP dalam program Anda.
Sekarang kita dapat mulai menggambar di atas window form kita!
4.2 Modifikasi Klas Blok
Kita perlu me-modifikasi klas Blok kita agar tiap-tiap subclass Blok (BlokGaris, dsb) tahu
dengan ImageBlok mana mereka harus menggambar.
// Variabel-variable hidden
protected bool[,] _elemen;
protected Image _warnaBlok;
Dan di tiap-tiap subclass, kita tentukan warnanya.
Di klas BlokGaris, tambahkan kode ke konstruktor:
public BlokGaris() : base()
{
_warnaBlok = ImageBlok.MERAH;
Di klas BlokKotak:
public BlokKotak() : base()
{
_warnaBlok = ImageBlok.KUNING;
Di klas BlokKros:
public BlokKros() : base()
{
_warnaBlok = ImageBlok.HIJAU;
Di klas BlokZNormal:
public BlokZNormal() : base()
{
_warnaBlok = ImageBlok.BIRU;
Di klas BlokZTerbalik:
public BlokZTerbalik() : base()
{
_warnaBlok = ImageBlok.MAGENTA;
Project Otak – http://otak.csharpindonesia.net 40
CSH202 – Pemrograman Game Tetris Dengan C#
Di klas BlokLNormal:
public BlokLNormal() : base()
{
_warnaBlok = ImageBlok.CYAN;
Di klas BlokLTerbalik:
public BlokLTerbalik() : base()
{
_warnaBlok = ImageBlok.COKLAT;
4.3 Definisi Draw() di Klas Blok
Karena kita telah mendapatkan image untuk digunakan menggambar di atas winforms,
sekarang kita definisikan method Draw() di Klas Blok sebagai berikut:
public void Draw()
{
Graphics g = PapanPermainan.ActiveForm.CreateGraphics();
for (int i = 0; i < PANJANG; i++)
for (int j = 0; j < LEBAR; j++)
{
if (_elemen[i,j] == true)
g.DrawImage(_warnaBlok, new Rectangle(
KoordKiriAtas.X + (j * PapanPermainan.OFFSETPIXEL),
KoordKiriAtas.Y + (i * PapanPermainan.OFFSETPIXEL),
PapanPermainan.OFFSETPIXEL,
PapanPermainan.OFFSETPIXEL));
}
g.Dispose();
}
Baris pertama adalah “mengambil” kanvas dari PapanPermainan.
Baris berikutnya, kita hanya menggambar warnaBlok jika data strukture _elemen kita
dinyatakan true. Lihat Bab 0 lagi jika Anda lupa bagaimana kita menyimpan sebuah blok
Tetris.
Lihat definisi DrawImage di CD-ROM MSDN Library. Klik View → Navigation → Index
dan ketik Graphics.DrawImage di field Look for, lalu dobel-klik Graphics.DrawImage
method di result box.
Project Otak – http://otak.csharpindonesia.net 41
CSH202 – Pemrograman Game Tetris Dengan C#
Di sini, saya menggunakan DrawImage dengan spesifikasi DrawImage(Image,
Rectangle).
Sedangkan spesifikasi Rectangle yang saya gunakan adalah
Rectangle( int koordKiriAtas.X,
int koordKiriAtas.Y,
int lebar rectangle,
int tinggi rectangle).
Lihat definisi Rectangle structure di CD-ROM MSDN Library Anda.
Yang menarik kenapa KoordKiriAtas.X ditambah dengan j, dan bukan i. Lihat Bab 2,
bagian 2.c lagi untuk melihat bagaiman konversi dari pixel ke grid unit.
Sudah tidak sabar melihat method Draw() beraksi?
Mari kita test method ini!
Anda harus ke Forms Designer, dan lakukan hal berikut di Properties Sheet:
Insert kode berikut:
private void PapanPermainan_KeyPress(object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
BlokGaris b1 = new BlokGaris();
b1.KoordKiriAtas = new Point(0,0);
b1.Draw();
BlokKros b2 = new BlokKros();
b2.KoordKiriAtas = new Point(80,0);
b2.Draw();
BlokZNormal b3 = new BlokZNormal();
b3.KoordKiriAtas = new Point(160,0);
b3.Draw();
}
Tekan tombol Ctrl – Shift – B untuk Build Solution. Lalu tekan Ctrl – F5.
Ketika Form PapanPermainan muncul, tekan tombol A.
Hasilnya akan seperti ini:
Project Otak – http://otak.csharpindonesia.net 42
CSH202 – Pemrograman Game Tetris Dengan C#
Jika sudah memastikan method Draw() bekerja, hapus kode test tadi dan lanjut ke bab
berikutnya!
Project Otak – http://otak.csharpindonesia.net 43
CSH202 – Pemrograman Game Tetris Dengan C#
5. Mengaplikasikan Factory Pattern
Jarang kita membuat program tanpa melihat-lihat buku patterns. Apakah penting? Tidak
juga, tapi patterns berisi resep-resep membuat program yang telah dipakai berulang-
ulang oleh para programmer veteran. Jadi mirip dengan mengimplementasikan fungsi
sorting sendiri atau menggunakan standard library yang telah ada.
Kita lihat apa yang dimaksud dengan Factory Pattern ini.
5.1 Klas BlokFactory
dotTetrus harus menampilkan blok secara random, jadi jangan sampai user tahu bahwa
setelah BlokBaris akan ada BlokKotak, dst. Kita bisa mengimplementasinya sbb:
int i = angka random antara 1-7.
switch (i)
{
case 1:
_terkiniBlok = new BlokGaris();
break;
case 2:
_terkiniBlok = new BlokKotak();
break;
...
}
Tapi secara design, apakah tugas PapanPermainan membuat instance-instance
BlokXXX? Kalau dilihat dalam real-life, sebuah pabrik (Factory) membuat berbagai
macam komponen. Kita tinggal memesan komponen sesuai dengan yang kita inginkan,
misalnya ban model offroad untuk dipasang di mobil kita. Jadi bukan mobil kita (Client)
yang seharusnya membuat ban atau kaca. Mobil kita memang menggunakan
komponen-komponen tersebut dan justru terdiri dari komponen-komponen tersebut,
akan tetapi bukan berarti mobil kita lah yang bertugas membuat ban, dsb.
Gunakan Class View untuk menciptakan klas baru: BlokFactory.
Project Otak – http://otak.csharpindonesia.net 44
CSH202 – Pemrograman Game Tetris Dengan C#
Isi seperti diatas lalu klik Finish.
*Perhatikan bahwa klas BlokFactory adalah Sealed class. Artinya klas ini tidak dapat di-
inherit, dan memang semestinya begitu karena hanya ada satu macam BlokFactory.
Dalam klas BlokFactory, hanya ada satu method, dan method ini static sehingga bisa
dipanggil tanpa membuat sebuah instance BlokFactory terlebih dahulu:
public static Blok BuatkanBlok(int spesifikasi)
{
Blok b = null;
switch (spesifikasi)
{
case Blok.BARIS:
b = new BlokGaris();
break;
case Blok.KOTAK:
b = new BlokKotak();
break;
case Blok.KROS:
b = new BlokKros();
break;
case Blok.ZNORMAL:
b = new BlokZNormal();
break;
case Blok.ZTERBALIK:
b = new BlokZTerbalik();
break;
case Blok.LNORMAL:
b = new BlokLNormal();
break;
case Blok.LTERBALIK:
b = new BlokLTerbalik();
break;
}
return b;
Project Otak – http://otak.csharpindonesia.net 45
CSH202 – Pemrograman Game Tetris Dengan C#
}
5.2 Method BuatBlokBaru() untuk klas PapanPermainan
PapanPermainan memerlukan satu method baru untuk “memesan” blok dari
BlokFactory.
Karena pembuatan blok baru ini harus dilakukan secara acak, tambahkan variabel
Random ke dalam data privat PapanPermainan:
// Variabel-variabel hidden
...
private Random _random;
Dan kita harus meng-init seed dari random generator di konstruktor PapanPermainan:
public PapanPermainan()
{
...
// init random generator
_random = new Random();
}
Sekarang kita siap mengisi kode untuk BuatBlokBaru:
private void BuatBlokBaru()
{
// antara 0-6 (termasuk 0 dan 6)
int spesifikasi = _random.Next(0, 7);
_terkiniBlok = BlokFactory.BuatkanBlok(spesifikasi);
_terkiniBlok.KoordKiriAtas = new Point(100,0);
// tengah atas
// Hitamkan area sebelum menampilkan Blok baru
Graphics g = this.CreateGraphics();
SolidBrush hitam = new SolidBrush(Color.Black);
int i_max =
_terkiniBlok.KoordKiriAtas.X +
(Blok.PANJANG * OFFSETPIXEL);
int j_max = _terkiniBlok.KoordKiriAtas.Y +
(Blok.LEBAR * OFFSETPIXEL);
for (int i = _terkiniBlok.KoordKiriAtas.X;
i < i_max; i += OFFSETPIXEL)
{
for (int j = _terkiniBlok.KoordKiriAtas.Y;
j < j_max; j += OFFSETPIXEL)
{
g.FillRectangle(hitam,
i, j, OFFSETPIXEL, OFFSETPIXEL);
}
}
// tampilkan blok baru
_terkiniBlok.Draw();
// dispose setelah dipakai
hitam.Dispose();
g.Dispose();
Project Otak – http://otak.csharpindonesia.net 46
CSH202 – Pemrograman Game Tetris Dengan C#
}
Lihat definisi Graphics.FillRectangle() di MSDN Library. Di sini saya menggunakan
FillRectangle(Brush warnaBrush,
int koordKiriAtas.X,
int koordKiriAtas.Y,
int lebar rectangle,
int tinggi rectangle)
Untuk menge-test method baru ini, kita buatkan agar dotTetrus membuat blok baru tiap
kali user mengetik huruf ‘M’ atau ‘m’:
private void PapanPermainan_KeyPress(object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
switch (e.KeyChar)
{
case 'M':
goto case 'm';
case 'm':
BuatBlokBaru();
break;
}
e.Handled = true;
}
Tekan tombol Ctrl – F5 untuk menampilkan dotTetrus, lalu tekan huruf ‘m’ di atas Papan
Permainan.
Project Otak – http://otak.csharpindonesia.net 47
CSH202 – Pemrograman Game Tetris Dengan C#
6. Menggunakan Invalidate()
Selama ini, kita menggambar blok di masing-masing method. Ini akan menimbulkan
redundancy atau kode yang sama di beberapa method. Ada satu problem dengan
approach kita selama ini. Coba jalankan aplikasi dotTetrus, tekan ‘m’ untuk
memunculkan blok baru, lalu minimize dotTetrus.
Sekarang kembalikan window dotTetrus. Apa yang terjadi?
Papan permainan menjadi hitam semua. Tentunya kita bisa saja melakukan trap atas
event Minimize, tapi ada cara yang lebih baik: menggunakan Event Paint.
Pindah view ke PapanPermainan.cs [Design], lihat Properties, dan pilih tombol
Events, lalu dobel-klik value Paint.
Isi dengan kode berikut:
private void PapanPermainan_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
Graphics g = e.Graphics;
SolidBrush hitam = new SolidBrush(Color.Black);
Image warnaBlok = null;
for (int i = 0; i < TINGGI; i++)
{
for (int j = 0; j < LEBAR; j++)
{
switch (_elemen[i,j])
{
case HITAM:
g.FillRectangle( hitam,
j * OFFSETPIXEL,
i * OFFSETPIXEL,
OFFSETPIXEL,
Project Otak – http://otak.csharpindonesia.net 48
CSH202 – Pemrograman Game Tetris Dengan C#
OFFSETPIXEL);
break;
case MERAH:
warnaBlok = ImageBlok.MERAH;
break;
case KUNING:
warnaBlok = ImageBlok.KUNING;
break;
case HIJAU:
warnaBlok = ImageBlok.HIJAU;
break;
case BIRU:
warnaBlok = ImageBlok.BIRU;
break;
case MAGENTA:
warnaBlok = ImageBlok.MAGENTA;
break;
case CYAN:
warnaBlok = ImageBlok.CYAN;
break;
case COKLAT:
warnaBlok = ImageBlok.COKLAT;
break;
} // end case
if (_elemen[i,j] > HITAM)
g.DrawImage(warnaBlok,
j * OFFSETPIXEL, // x-coord
i * OFFSETPIXEL, // y-coord
OFFSETPIXEL, // lebar
OFFSETPIXEL); // tinggi
} // end for j
} // end for i
} // end _Paint()
6.1 Penambahan method SetElemen() dan GetElemen()
Tambahkan method SetElemen() kepada PapanPermainan:
public void SetElemen(int i, int j, int warna)
{
_element[i,j] = warna;
}
Dan juga GetElemen() pada PapanPermainan:
public int GetElemen(int i, int j)
{
return _elemen[i,j];
}
Method ini diperlukan karena kita akan me-modifikasi method Blok.Draw()
Project Otak – http://otak.csharpindonesia.net 49
CSH202 – Pemrograman Game Tetris Dengan C#
6.2 Modifikasi klas Blok
Ubah tipe variabel _warnaBlok dari Image menjadi int.
// Variabel-variable hidden
protected bool[,] _elemen;
// protected Image _warnaBlok;
protected int _warnaBlok;
Dan di tiap-tiap subclass, ubah variabel ini.
Di klas BlokGaris:
public BlokGaris() : base()
{
_warnaBlok = PapanPermainan.MERAH;
Di klas BlokKotak:
public BlokKotak() : base()
{
_warnaBlok = PapanPermainan.KUNING;
Di klas BlokKros:
public BlokKros() : base()
{
_warnaBlok = PapanPermainan.HIJAU;
Di klas BlokZNormal:
public BlokZNormal() : base()
{
_warnaBlok = PapanPermainan.BIRU;
Di klas BlokZTerbalik:
public BlokZTerbalik() : base()
{
_warnaBlok = PapanPermainan.MAGENTA;
Di klas BlokLNormal:
public BlokLNormal() : base()
{
_warnaBlok = PapanPermainan.CYAN;
Di klas BlokLTerbalik:
public BlokLTerbalik() : base()
{
_warnaBlok = PapanPermainan.COKLAT;
Sekarang kita ubah method Blok.Draw() menjadi:
public void Draw(PapanPermainan papan)
{
int offset_i =
KoordKiriAtas.Y / PapanPermainan.OFFSETPIXEL;
int offset_j =
KoordKiriAtas.X / PapanPermainan.OFFSETPIXEL;
for (int i = 0; i < PANJANG; i++)
for (int j = 0; j < LEBAR; j++)
{
if (_elemen[i,j] == true)
papan.SetElemen(
offset_i + i,
offset_j + j, _warnaBlok);
Project Otak – http://otak.csharpindonesia.net 50
CSH202 – Pemrograman Game Tetris Dengan C#
}
}
*Perhatikan bahwa Blok.Draw() sekarang menerima sebuah parameter!
6.3 Modifikasi PapanPermainan.BuatBlokBaru()
Sesuaikan kode-nya dengan berikut:
private void BuatBlokBaru()
{
// antara 0-6 (termasuk 0 dan 6)
int spesifikasi = _random.Next(0, 7);
_terkiniBlok = BlokFactory.BuatkanBlok(spesifikasi);
_terkiniBlok.KoordKiriAtas = new Point(100,0);
// tengah atas
int i_max = _terkiniBlok.KoordKiriAtas.X +
(Blok.PANJANG * OFFSETPIXEL);
int j_max = _terkiniBlok.KoordKiriAtas.Y +
(Blok.LEBAR * OFFSETPIXEL);
for (int i = _terkiniBlok.KoordKiriAtas.X;
i < i_max; i += OFFSETPIXEL)
{
for (int j = _terkiniBlok.KoordKiriAtas.Y;
j < j_max; j += OFFSETPIXEL)
{
_elemen[j/OFFSETPIXEL, i/OFFSETPIXEL] = HITAM;
}
}
// tampilkan blok baru
_terkiniBlok.Draw(this);
// panggil Invalidate
Size s = new Size(Blok.PANJANG * OFFSETPIXEL,
Blok.LEBAR * OFFSETPIXEL);
this.Invalidate(new Rectangle(_terkiniBlok.KoordKiriAtas,
s));
}
Tekan tombol Ctrl – Shift – B, diikuti dengan Ctrl – F5 untuk menjalankan dotTetrus.
Tekan tombol M, lalu minimize window, dan restore. Seharusnya ketika di restore, blok
Tetris akan muncul kembali. Jika tidak, cek kode Anda!
6.4 Sekilas tentang Invalidate()
Bagi yang belum pernah membuat program dengan bahasa pemrograman C (Win32
API) atau dengan MFC Visual C++, akan saya jelaskan apa yang dilakukan dengan
memanggil Invalidate().
Project Otak – http://otak.csharpindonesia.net 51
CSH202 – Pemrograman Game Tetris Dengan C#
Dengan memanggil Invalidate(), kita menyalakan event PAINT. Event Paint ini menyala
setiap kali window harus di re-draw ulang. Contohnya, ketika di maximize, restore
setelah minimize, restore setelah ditutupi window lain diatasnya.
Dalam kata lain, kita memaksa program untuk menjalankan kode yang meng-handle
event Paint ini. Kode yang meng-handle event Paint dalam dotTetrus adalah:
private void PapanPermainan_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
Lantas kenapa memanggil Invalidate() dengan argumen Rectangle dan Size?
Lihat bagan di bawah ini:
Jadi kalau kita memanggil Invalidate() tanpa argumen, maka kita memaksa program
untuk me-redraw seluruh windows forms kita, dari koord (0,0) sampai (240,400)! Ini
tentunya lebih lama daripada hanya me-redraw sebagian area saja.
Memang kode PapanPermainan_Paint kita sebenarnya mengecek tiap grid dan
menggambar blok yang sesuai. Tapi ada hal yang magic: Windows tidak akan me-
redraw sesuatu diluar area yang diminta!
Lihat bagan diatas sekali lagi. Bila Invalidate() dipanggil dengan argumen r, maka kode
seperti:
g.DrawImage(image, 100,100, 20,20);
tidak akan dijalankan karena berada di luar area r (lihat kotak merah).
Ada baiknya sekarang Anda membuka MSDN library, dan membaca tentang
Control.Invalidate method (System.Windows.Forms).
Satu hal lagi, saya bisa menulis kode Invalidate() di BlokBaru() dengan gaya seperti
kode-kode sebelumnya:
this.Invalidate(new Rectangle(
_terkiniBlok.KoordKiriAtas.X,
_terkiniBlok.KoordKiriAtas.Y,
Blok.PANJANG * OFFSETPIXEL,
Blok.LEBAR * OFFSETPIXEL));
Project Otak – http://otak.csharpindonesia.net 52
CSH202 – Pemrograman Game Tetris Dengan C#
Tapi ada konstruktor Rectangle() yang menerima argumen Point dan Size. Dan saya
melihatnya lebih elegan dari kode diatas. Tergantung Anda mau menggunakan style
yang mana. Dan lebih penting lagi, jika ada konstruktor atau method yang belum terlihat
sebelumnya, lihat di MSDN Library dan periksa argumen-argumen apa saja yang bisa
diterima oleh konstruktor dan method tersebut.
Project Otak – http://otak.csharpindonesia.net 53
CSH202 – Pemrograman Game Tetris Dengan C#
7. Merespons Keyboard Event
Pada bab ini saya akan fokus koding untuk merespons tombol Bawah, Kiri, Kanan.
Sebelumnya, kita tambahkan satu lagi method ke klas Blok, yaitu HapusDariPapan():
public void HapusDariPapan(PapanPermainan papan)
{
int offset_i =
KoordKiriAtas.Y / PapanPermainan.OFFSETPIXEL;
int offset_j =
KoordKiriAtas.X / PapanPermainan.OFFSETPIXEL;
for (int i = 0; i < PANJANG; i++)
for (int j = 0; j < LEBAR; j++)
{
if (_elemen[i,j] == true)
papan.SetElemen(
offset_i + i,
offset_j + j,
PapanPermainan.HITAM);
}
}
Kode Blok.HapusDariPapan() adalah kebalikan dari kode Blok.Draw(), dan ini digunakan
untuk me-reset papan sebelum menggeser blok ke bawah, kiri atau kanan.
Kemudian, kita buat method untuk meng-handle event KeyDown, yaitu event yang akan
menyala ketika user memencet suatu tombol di keyboard. Pindah ke Properties Sheet
untuk PapanPermainan.cs [Design] dan ikuti bagan berikut:
Project Otak – http://otak.csharpindonesia.net 54
CSH202 – Pemrograman Game Tetris Dengan C#
7.1 Merespons key Bawah
Untuk merespons tombol arrow Bawah, kode yang akan digunakan adalah method
TurunkanBlok().
Pertama, tambahkan kode berikut ke dalam KeyDown-handler kita:
private void PapanPermainan_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Down:
TurunkanBlok();
break;
}
}
Dan method TurunkanBlok kita modifikasi seperti berikut:
private void TurunkanBlok()
{
// 1. Hapus bekas blok
_terkiniBlok.HapusDariPapan(this);
// 2. Turunkan blok 1 grid unit
System.Drawing.Point koordLama =
_terkiniBlok.KoordKiriAtas;
_terkiniBlok.KoordKiriAtas.Y += OFFSETPIXEL;
// 3. ReDraw Blok
_terkiniBlok.Draw(this);
Size s = new Size( (Blok.PANJANG * OFFSETPIXEL),
(Blok.LEBAR * OFFSETPIXEL) + OFFSETPIXEL);
this.Invalidate(new Rectangle(koordLama, s));
}
Project Otak – http://otak.csharpindonesia.net 55
CSH202 – Pemrograman Game Tetris Dengan C#
7.2 Merespons key Kiri
Kita buatkan method baru GeserKiriBlok() ke dalam klas PapanPermainan:
private void GeserKiriBlok()
{
// 1. Hapus bekas blok
_terkiniBlok.HapusDariPapan(this);
// 2. Geser kiri blok 1 grid unit
_terkiniBlok.KoordKiriAtas.X -= OFFSETPIXEL;
// 3. ReDraw Blok
_terkiniBlok.Draw(this);
Size s = new Size( (Blok.PANJANG * OFFSETPIXEL) +
OFFSETPIXEL,
(Blok.LEBAR * OFFSETPIXEL) );
this.Invalidate(new Rectangle(_terkiniBlok.KoordKiriAtas,
s));
}
Dan tambahkan kode di KeyDown-handler:
private void PapanPermainan_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
switch (e.KeyCode)
{
...
case Keys.Left:
GeserKiriBlok();
break;
7.3 Merespons Key Kanan
Kita buatkan method baru GeserKananBlok() ke dalam klas PapanPermainan:
private void GeserKananBlok()
{
// 1. Hapus bekas blok
_terkiniBlok.HapusDariPapan(this);
// 2. Geser kanan blok 1 grid unit
System.Drawing.Point koordLama =
_terkiniBlok.KoordKiriAtas;
Project Otak – http://otak.csharpindonesia.net 56
CSH202 – Pemrograman Game Tetris Dengan C#
_terkiniBlok.KoordKiriAtas.X += OFFSETPIXEL;
// 3. ReDraw Blok
_terkiniBlok.Draw(this);
Size s = new Size( (Blok.PANJANG * OFFSETPIXEL) +
OFFSETPIXEL,
(Blok.LEBAR * OFFSETPIXEL) );
this.Invalidate(new Rectangle(koordLama, s));
}
Dan tambahkan kode di KeyDown-handler:
private void PapanPermainan_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
switch (e.KeyCode)
{
...
case Keys.Right:
GeserKananBlok();
break;
}
}
Sekarang, Build Solution, dan jalankan dotTetrus. Tekan ‘m’ untuk memunculkan blok
baru, lalu gerakkan ke bawah, kiri, kanan.
Project Otak – http://otak.csharpindonesia.net 57
CSH202 – Pemrograman Game Tetris Dengan C#
8. Menumpuk Blok
Sampai sekarang sudah banyak kemajuan di program dotTetrus kita; memunculkan blok
baru secara random, menggeser kiri, menggeser kanan, dan menggeser ke bawah.
Akan tetapi, satu hal masih mengganjal. Kita belum dapat membuat tumpukan satu blok
di atas blok yang lain. Sekarang kita akan menangani masalah tersebut.
Sebelum kita mulai, ada satu bug yang harus ditangani.
Client Area kita (kanvas tempat kita menggambar blok Tetris) ternyata tidak memiliki
panjang 240 pixel dan tinggi 400 pixel.
Coba lihat kode InitializeComponent() di klas PapanPermainan:
this.ClientSize = new System.Drawing.Size(234, 369);
Ganti kode ini menjadi:
this.ClientSize = new System.Drawing.Size(240, 400);
8.1 Modifikasi Klas Blok
Ternyata kita harus menambahkan satu method baru di klas Blok, yaitu GetElemen(),
karena kita perlu membandingkan elemen di Blok dan elemen di PapanPermainan.
Tambahkan method ini di klas Blok:
public bool GetElemen(int i, int j)
{
return _elemen[i,j];
}
8.2 Mengkontrol Penurunan Blok
Tambahkan kode berikut di klas PapanPermainan:
private bool BisaDiturunkan()
{
// simulasi penurunan
Point koordBaru = new Point(
_terkiniBlok.KoordKiriAtas.X,
_terkiniBlok.KoordKiriAtas.Y + OFFSETPIXEL);
int offset_i = koordBaru.Y / OFFSETPIXEL;
int offset_j = koordBaru.X / OFFSETPIXEL;
// cari elemen terbawah dari blok
int barisTerbawah = Blok.LEBAR - 1;
bool found = false;
for (int i = barisTerbawah;
i >= 0 && !found;
i--)
{
Project Otak – http://otak.csharpindonesia.net 58
CSH202 – Pemrograman Game Tetris Dengan C#
for (int j = 0;
j < Blok.PANJANG && !found;
j++)
{
if ( _terkiniBlok.GetElemen(i,j) == true )
found = true;
}
if (!found)
--barisTerbawah;
}
for (int j = 0; j < Blok.PANJANG; j++)
{
// case 1: menyentuh lantai papan
if ( _terkiniBlok.GetElemen(barisTerbawah,j) == true
&& offset_i + barisTerbawah >=
PapanPermainan.TINGGI )
return false;
// case 2: menyentuh blok lain di bawahnya
if ( _terkiniBlok.GetElemen(barisTerbawah,j) == true
&& _elemen[offset_i + barisTerbawah,
offset_j + j] > HITAM)
{
return false;
}
}
// tidak menyentuh apa-apa
return true;
}
Dan modifikasi KeyDown-handler kita:
private void PapanPermainan_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Down:
if ( BisaDiturunkan() )
TurunkanBlok();
break;
...
Build Solution dan jalankan dotTetrus untuk memastikan kode ini bekerja dengan benar!
8.3 Mengkontrol Penggeseran Kiri
Tidak hanya menurunkan blok, kita pun harus memastikan bahwa ketika menggeser ke
kiri dan ke kanan, blok tidak akan keluar dari papan permainan.
Prinsipnya sama dengan kode BisaDiturunkan(), hanya untuk mengkontrol penggeseran
ke kiri, kita musti mencari elemen terkiri blok.
private bool BisaDigeserKiri()
{
// simulasi geser kiri
Point koordBaru = new Point(
_terkiniBlok.KoordKiriAtas.X - OFFSETPIXEL,
_terkiniBlok.KoordKiriAtas.Y);
Project Otak – http://otak.csharpindonesia.net 59
CSH202 – Pemrograman Game Tetris Dengan C#
int offset_i = koordBaru.Y / OFFSETPIXEL;
int offset_j = koordBaru.X / OFFSETPIXEL;
// cari elemen terkiri dari blok
int kolomTerkiri = 0;
bool found = false;
for (int i = kolomTerkiri;
i < Blok.PANJANG && !found;
i++)
{
for (int j = 0;
j < Blok.LEBAR && !found;
j++)
{
// hati-hati (j,i) BUKAN (i,j)!
if ( _terkiniBlok.GetElemen(j,i) == true )
found = true;
}
if (!found)
++kolomTerkiri;
}
for (int i = 0; i < Blok.PANJANG; i++)
{
// case 1: menyentuh pinggir kiri papan
if ( _terkiniBlok.GetElemen(i,kolomTerkiri) == true
&& (offset_j + kolomTerkiri) < 0 )
return false;
// case 2: menyentuh blok lain di sebelah kiri
if ( _terkiniBlok.GetElemen(i,kolomTerkiri) == true
&& _elemen[offset_i + i,
offset_j + kolomTerkiri] > HITAM)
{
return false;
}
}
// tidak menyentuh apa-apa
return true;
}
Dan modifikasi KeyDown-handler PapanPermainan:
private void PapanPermainan_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
switch (e.KeyCode)
{
...
case Keys.Left:
if ( BisaDigeserKiri() )
GeserKiriBlok();
break;
…
Mungkin untuk kode kali ini agak susah dicerna. Saya akan coba terangkan secara
visual:
Project Otak – http://otak.csharpindonesia.net 60
CSH202 – Pemrograman Game Tetris Dengan C#
Andaikan blok di bagan atas digeser ke kiri, maka:
koordBaru = ( -20, 20 )
offset_j = -20 / 20 = -1
offset_j + kolomTerkiri = -1 + 0 = -1 ( < 0 ! tidak bisa digeser lagi )
8.4 Mengkontrol Penggeseran Kanan
Kode ini akan lebih kurang sama dengan BisaDigeserKiri(), hanya kita harus mencari
kolom terkanan:
private bool BisaDigeserKanan()
{
// simulasi geser kanan
Point koordBaru = new Point(
_terkiniBlok.KoordKiriAtas.X + OFFSETPIXEL,
_terkiniBlok.KoordKiriAtas.Y);
int offset_i = koordBaru.Y / OFFSETPIXEL;
int offset_j = koordBaru.X / OFFSETPIXEL;
// cari elemen terkiri dari blok
int kolomTerkanan = Blok.PANJANG - 1;
bool found = false;
for (int i = kolomTerkanan;
i >= 0 && !found;
i--)
{
for (int j = 0;
j < Blok.LEBAR && !found;
j++)
{
// hati-hati (j,i) BUKAN (i,j)!
if ( _terkiniBlok.GetElemen(j,i) == true )
found = true;
}
if (!found)
--kolomTerkanan;
}
for (int i = 0; i < Blok.PANJANG; i++)
{
// case 1: menyentuh pinggir kanan papan
if ( _terkiniBlok.GetElemen(i,kolomTerkanan) == true
Project Otak – http://otak.csharpindonesia.net 61
CSH202 – Pemrograman Game Tetris Dengan C#
&& (offset_j + kolomTerkanan) >= PapanPermainan.LEBAR )
return false;
// case 2: menyentuh blok lain di sebelah kanan
if ( _terkiniBlok.GetElemen(i,kolomTerkanan) == true
&& _elemen[offset_i + i,
offset_j + kolomTerkanan] > HITAM)
{
return false;
}
}
// tidak menyentuh apa-apa
return true;
}
Dan modifikasi KeyDown-handler kita:
private void PapanPermainan_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
switch (e.KeyCode)
{
...
case Keys.Right:
if ( BisaDigeserKanan() )
GeserKananBlok();
break;
}
Sekali lagi, saya coba jelaskan secara visual:
Andaikan blok di bagan atas digeser ke kanan, maka:
koordBaru = ( 180, 20 )
offset_j = 180 / 20 = 9
offset_j + kolomTerkanan = 9 + 3 = 12 ( >= 12 ! tidak bisa digeser lagi )
Project Otak – http://otak.csharpindonesia.net 62
CSH202 – Pemrograman Game Tetris Dengan C#
9. Merotasikan Blok
Kita sudah dapat menurunkan blok, geser kiri dan geser kanan. Yang kurang hanyalah
merotasikan blok ke atas, bawah, kiri dan kanan.
9.1 Menambahkan ICloneable ke klas Blok
Tambahkan ICloneable interface ke deklarasi klas Blok:
public class Blok : ICloneable
*Ketika selesai mengetik ICloneable, VS.Net akan menyarankan memencet tombol Tab
untuk men-generate semua methods ICloneable secara otomatis. Tekan Tab dan
biarkan VS.Net melakukkanya.
Scroll ke bawah sekali, cari method Clone(). Mungkin VS.Net akan
menyembunyikannya di bawah region ICloneable Members:
Klik tanda ‘+’ pada ICloneable Members maka sekarang Anda akan melihat method
Klon(). Jika method ini disembunyikan isinya, klik tanda ‘+’ untuk melihat isinya.
Isi method Klon dengan kode berikut:
public object Clone()
{
Blok b = null;
// buat sesuai subklas
if (this is BlokGaris)
b = new BlokGaris();
else if (this is BlokKotak)
b = new BlokKotak();
else if (this is BlokKros)
b = new BlokKros();
else if (this is BlokZNormal)
b = new BlokZNormal();
else if (this is BlokZTerbalik)
b = new BlokZTerbalik();
else if (this is BlokLNormal)
b = new BlokLNormal();
else if (this is BlokLTerbalik)
b = new BlokLTerbalik();
// copy koord dan warnablok
Project Otak – http://otak.csharpindonesia.net 63
CSH202 – Pemrograman Game Tetris Dengan C#
b.KoordKiriAtas = this.KoordKiriAtas;
b._warnaBlok = this._warnaBlok;
// copy elemen
for (int i = 0; i < LEBAR; i++)
for (int j = 0; j < PANJANG; j++)
b._elemen[i,j] = this._elemen[i,j];
return b;
}
Sebaiknya kode untuk membuat blok jangan dimasukkan ke dalam if-then-else. Ingat
tugas membuat blok adalah urusan BlokFactory. Kode yang baik memang sebaiknya
// buat sesuai subklas
b = BlokFactory.BuatkanBlok(spesifikasi);
Akan tetapi ini berarti menambahkan satu variabel baru semacam kodeBlok atau
spesifikasi dan melakukan perubahan di tiap konstruktor subclass kita. Saya hanya
melakukannya seperti ini untuk mengingatkan bahwa potensi bad-coding semakin
besar ketika deadline semakin dekat dan program hampir selesai :P
OK, kenapa kita membuat klas Blok mengimplementasi ICloneable interface? Ini karena
semua method Rotasi (RotateAtas, RotateBawah, dsb) mengubah value Blok._elemen.
Sedangkan kita ingin dapat mengecek apakah rotasi bisa dilakukan seperti halnya kita
mengecek apakah blok bisa digeser kiri. Oleh karena itu kita harus bekerja dengan
sebuah copy dari blok terkini.
9.2 Method BisaRotasi() untuk klas PapanPermainan
Inilah kode BisaRotasi() yang fungsinya sama seperti BisaDigeserKiri,
BisaDigeserKanan dan BisaDiturunkan, yaitu untuk mengecek apakah sebuah rotasi
bisa dilakukan:
private bool BisaRotasi(char key)
{
// clone blok terkini
Blok b = (Blok) _terkiniBlok.Clone();
// rotasi sesuai keypress
switch (key)
{
case 'w':
b.RotateAtas();
break;
case 'a':
b.RotateKiri();
break;
case 's':
b.RotateBawah();
break;
case 'd':
b.RotateKanan();
break;
Project Otak – http://otak.csharpindonesia.net 64
CSH202 – Pemrograman Game Tetris Dengan C#
}
// cek apakah hasil rotasi menutupi blok lain
int offset_i = b.KoordKiriAtas.Y / OFFSETPIXEL;
int offset_j = b.KoordKiriAtas.X / OFFSETPIXEL;
for (int i = 0; i < Blok.LEBAR; i++)
for (int j = 0; j < Blok.PANJANG; j++)
if (
offset_j + j >= 0 &&
offset_j + j <= PapanPermainan.LEBAR - 1
&&
offset_i + i >= 0 &&
offset_i + i <= PapanPermainan.TINGGI - 1
&&
b.GetElemen(i,j) == true &&
_terkiniBlok.GetElemen(i,j) == false &&
_elemen[offset_i + i, offset_j + j] >
HITAM )
{
return false;
}
// hasil rotasi tidak menutupi blok lain
return true;
}
Tentunya kode yang harus Anda konsentrasi adalah kode di blok if…
Kode ini:
offset_j + j >= 0 &&
offset_j + j <= PapanPermainan.LEBAR - 1 &&
offset_i + i >= 0 &&
offset_i + i <= PapanPermainan.TINGGI - 1 &&
Memaksa rotasi hanya dilakukan di dalam client area atau di dalam papan permainan
atau di dalam area (0,0) → (240,400).
Kode ini:
b.GetElemen(i,j) == true &&
_terkiniBlok.GetElemen(i,j) == false &&
Hanya mengecek area baru yang dihasilkan oleh rotasi.
Lihat blok dibawah ini:
Project Otak – http://otak.csharpindonesia.net 65
CSH202 – Pemrograman Game Tetris Dengan C#
Setelah di RotateKanan() akan menghasilkan:
Area merah adalah area yang berbeda dari sebelum rotasi. Area inilah yang harus dicek
apakah menyentuh blok lain atau keluar dari papan permainan.
Sedangkan kode ini:
_elemen[offset_i + i, offset_j + j] > HITAM )
mengecek apakah area baru yang dihasilkan rotasi bersentuhan dengan blok lain.
Karena jika ada blok lain, maka value _elemen di papan permainan adalah MERAH,
KUNING, dsb.
9.3 Modifikasi KeyPress-handler
Kenapa KeyPress dan bukan KeyDown-handler yang dimodifikasi? Secara general,
gunakan aturan ini:
Character key seperti ‘a’, ‘b’, ‘c’, dsb di-handle di Keypress event. Sedangkan non-
character key seperti ArrowAtas, ArrowBawah, F1, dsb di-handle di Keydown event.
Pula, kita memerlukan sebuah char sebagai argumen untuk method BisaRotasi().
Karena kodenya lumayan panjang, saya paparkan semua isi method Keypress-handler:
private void PapanPermainan_KeyPress(object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
switch (e.KeyChar)
{
case 'M':
goto case 'm';
case 'm':
BuatBlokBaru();
break;
Project Otak – http://otak.csharpindonesia.net 66
CSH202 – Pemrograman Game Tetris Dengan C#
}
if (e.KeyChar == 'w' ||
e.KeyChar == 'a' ||
e.KeyChar == 's' ||
e.KeyChar == 'd')
{
// cek apakah bisa dirotasi
if ( !BisaRotasi(e.KeyChar) )
{
e.Handled = true;
return; // tidak bisa rotasi
}
// sampai sini berarti bisa dirotasi
_terkiniBlok.HapusDariPapan(this);
switch (e.KeyChar)
{
case 'w':
_terkiniBlok.RotateAtas();
break;
case 'a':
_terkiniBlok.RotateKiri();
break;
case 's':
_terkiniBlok.RotateBawah();
break;
case 'd':
_terkiniBlok.RotateKanan();
break;
}
_terkiniBlok.Draw(this);
Size s = new Size( Blok.PANJANG * OFFSETPIXEL,
Blok.LEBAR * OFFSETPIXEL );
this.Invalidate(new Rectangle(
_terkiniBlok.KoordKiriAtas, s));
} // end if key rotasi
e.Handled = true;
}
Sekarang Build Solution dan tes dotTetrus untuk memastikan semua kode Rotasi
bekerja!
Project Otak – http://otak.csharpindonesia.net 67
CSH202 – Pemrograman Game Tetris Dengan C#
10. Menghilangkan Baris Komplet
*** BUG ***
Sebelum Anda melanjutkan, saya baru saja menemukan bug pada method Blok.Draw().
Cara menampilkan bug tersebut:
Modify method PapanPermainan.BuatBlokBaru():
private void BuatBlokBaru()
{
// antara 0-6 (termasuk 0 dan 6)
int spesifikasi = _random.Next(0, 7);
//_terkiniBlok = BlokFactory.BuatkanBlok(spesifikasi);
_terkiniBlok = BlokFactory.BuatkanBlok(6);
Build Solution
Geser blok ke kanan sampai pol / tidak bisa digeser lagi.
Rotasi blok dengan tombol ‘a’
Dapat dilihat bahwa error ini disebabkan oleh:
index yang diluar range
Project Otak – http://otak.csharpindonesia.net 68
CSH202 – Pemrograman Game Tetris Dengan C#
yg menyebabkan error adalah call PapanPermainan.SetElemen()
yg berada di method Blok.Draw()
Modify PapanPermainan.SetElemen() menjadi:
public void SetElemen(int i, int j, int warna)
{
if (i >= 0 && i < TINGGI &&
j >= 0 && j < LEBAR)
_elemen[i,j] = warna;
}
*** Saya menulis e-book ini sembari menulis kode. Jadi memang tidak ada working
program sebelum menulis. Akibatnya bugs baru muncul setelah beberapa bab. Mohon
maaf kalau ada bugs-bugs yang lain :P
Pastikan Anda me-reset method BuatBlokBaru() sebelum melanjuti:
private void BuatBlokBaru()
{
// antara 0-6 (termasuk 0 dan 6)
int spesifikasi = _random.Next(0, 7);
_terkiniBlok = BlokFactory.BuatkanBlok(spesifikasi);
// untuk debug
//_terkiniBlok = BlokFactory.BuatkanBlok(6);
Project Otak – http://otak.csharpindonesia.net 69
CSH202 – Pemrograman Game Tetris Dengan C#
10.1 Menampilkan “Blink” effect
Sebelum menghilangkan baris-baris Tetris yang komplet, saya ingin menampilkan visual
cue (petunjuk visual) bahwa memang baris-baris tersebut komplet.
Idenya simple sekali:
hitamkan baris
sleep() untuk bbrp millisecond
kembalikan baris ke warna asal
Dan untuk lebih kelihatan, saya sengaja mem-blink nya dua kali. Ide yang simple ini
ternyata membutuhkan kode yang lumayan kompleks.
Pertama tambahkan deklarasi using ini diatas file PapanPermainan.cs
using System;
...
using System.Threading;
Kita perlu bekerja dengan Thread sekarang. Karena ketika kita mem-blink baris, kita
tidak ingin Paint-handler kita ikut berhenti.
Kedua, buat method baru CekTumpukan() di klas PapanPermainan:
private void CekTumpukan()
{
if (this._terkiniTinggiTumpukan >= PapanPermainan.TINGGI)
return; // lantai masih kosong
// mulai dari bawah
int barisYgDicek = PapanPermainan.TINGGI - 1;
int[] barisKomplet = new int[20];
int jmlhBarisKomplet = 0;
bool found;
do
{
found = false;
for (int j = 0;
j < PapanPermainan.LEBAR && !found;
j++)
{
if ( _elemen[barisYgDicek,j] == HITAM )
found = true;
}
if (!found)
{
barisKomplet[jmlhBarisKomplet++] =
barisYgDicek;
}
--barisYgDicek;
} while (barisYgDicek >=
this._terkiniTinggiTumpukan);
if (jmlhBarisKomplet == 0)
return;
Project Otak – http://otak.csharpindonesia.net 70
CSH202 – Pemrograman Game Tetris Dengan C#
// hitamkan sebentar untuk memunculkan
// "BLINK" effect
Graphics g = this.CreateGraphics();
SolidBrush brushHitam = new SolidBrush(Color.Black);
// blink effect!
for (int jmlhBlink = 0;
jmlhBlink < 2;
jmlhBlink++)
{
Thread.Sleep(100);
for (int baris = 0;
baris < jmlhBarisKomplet;
baris++)
{
int barisBlink = barisKomplet[baris];
// hitamkan baris ini
for (int i = 0; i < TINGGI; i++)
{
g.FillRectangle(brushHitam,
i * OFFSETPIXEL,
barisBlink * OFFSETPIXEL,
OFFSETPIXEL,
OFFSETPIXEL);
}
}
// tunggu 100ms
Thread.Sleep(100);
// Restore kembali
for (int baris = 0;
baris < jmlhBarisKomplet;
baris++)
{
int barisBlink = barisKomplet[baris];
// kembalikan warna semula
for (int j = 0; j < LEBAR; j++)
DrawElemen(barisBlink, j, g);
}
}
brushHitam.Dispose();
g.Dispose();
// delete baris2 komplet
int tinggiLama = this._terkiniTinggiTumpukan;
for (int i = jmlhBarisKomplet - 1;
i >= 0; i--)
{
int barisDel = barisKomplet[i];
// turunkan baris diatas barisDel
for (int baris = barisDel;
baris >= this._terkiniTinggiTumpukan;
baris--)
{
for (int j = 0; j < LEBAR; j++)
{
_elemen[baris,j] = _elemen[baris-1,j];
}
}
}
Project Otak – http://otak.csharpindonesia.net 71
CSH202 – Pemrograman Game Tetris Dengan C#
// update tinggi tumpukan
this.UpdateTerkiniTinggiTumpukan();
// reDraw
Point koord = new Point(0,
tinggiLama * OFFSETPIXEL);
Size s = new Size(LEBAR * OFFSETPIXEL,
(TINGGI - tinggiLama) * OFFSETPIXEL);
this.Invalidate(new Rectangle(koord, s));
}
Dan juga tambahkan method DrawElemen() di kelas PapanPermainan:
private void DrawElemen(int i, int j, Graphics g)
{
Image warnaBlok = null;
switch ( _elemen[i,j] )
{
case MERAH:
warnaBlok = ImageBlok.MERAH;
break;
case KUNING:
warnaBlok = ImageBlok.KUNING;
break;
case HIJAU:
warnaBlok = ImageBlok.HIJAU;
break;
case BIRU:
warnaBlok = ImageBlok.BIRU;
break;
case MAGENTA:
warnaBlok = ImageBlok.MAGENTA;
break;
case CYAN:
warnaBlok = ImageBlok.CYAN;
break;
case COKLAT:
warnaBlok = ImageBlok.COKLAT;
break;
} // end case
g.DrawImage(warnaBlok,
j * OFFSETPIXEL,
i * OFFSETPIXEL,
OFFSETPIXEL,
OFFSETPIXEL);
}
Project Otak – http://otak.csharpindonesia.net 72
CSH202 – Pemrograman Game Tetris Dengan C#
Sekarang, kita harus memanggil CekTumpukan setelah menurunkan Blok:
private void TurunkanBlok()
{
...
this.Invalidate(new Rectangle(koordLama, s));
// update terkiniTinggi
this.UpdateTerkiniTinggiTumpukan();
// cek tumpukan
Thread t = new Thread(new ThreadStart(CekTumpukan));
t.Start();
Ah, kita juga harus meng-update _terkiniTinggiTumpukan dengan method:
private void UpdateTerkiniTinggiTumpukan()
{
// misi kita adalah mencari satu baris yang
// berisi HITAM semua
// mulai dari bawah
int barisYgDicek = PapanPermainan.TINGGI - 1;
bool found;
do
{
found = true;
for (int j = 0;
j < PapanPermainan.LEBAR && found;
j++)
{
if ( _elemen[barisYgDicek,j] > HITAM )
found = false;
}
if (!found)
--barisYgDicek;
} while (barisYgDicek >= 0 && !found);
// terkiniTinggiTumpukan sekarang berada
// di bawah garis yg berisi HITAM semua
this._terkiniTinggiTumpukan = barisYgDicek + 1;
}
Lihat bagan di awal Bab 2 untuk mengingat apa fungsi _terkiniTinggiTumpukan.
Anda bisa mem-Build Solution dan lihat hasilnya.
Project Otak – http://otak.csharpindonesia.net 73
CSH202 – Pemrograman Game Tetris Dengan C#
11. Menggunakan Timer
Selama ini kita harus menekan tombol ‘m’ untuk membuat blok baru. Selazimnya,
seperti game Tetris yang kita mainkan, blok baru akan muncul setelah blok kita
menyentuh lantai atau berada di atas blok lain.
Kita akan menggunakan Timer untuk menurunkan blok setiap 1 detik. Ketika blok tidak
bisa lagi diturunkan, maka itulah saatnya untuk meng-update _terkiniTinggiTumpukan,
memanggil CekTumpukan(), dan membuat blok baru.
11.1 Menambahkan Timer
Klik View→Toolbox dan drag-n-drop sebuah Timer komponen ke atas form Papan
Permainan:
Pindah ke Properties Sheet untuk Timer. Ganti fields berikut:
Field Value
Name _timer
Interval 1000
Enabled False
Kemudian kita buat kode Tick-handler nya, yaitu event yang akan menyala setiap kali
interval telah terlewati:
Project Otak – http://otak.csharpindonesia.net 74
CSH202 – Pemrograman Game Tetris Dengan C#
private void _timer_Tick(object sender, System.EventArgs e)
{
// pertama kali
if ( _terkiniBlok == null )
BuatBlokBaru();
if ( BisaDiturunkan() )
TurunkanBlok();
else
{
// update terkini tinggi
this.UpdateTerkiniTinggiTumpukan();
// blink dan hilangkan baris komplet
Thread t = new Thread(new ThreadStart(CekTumpukan));
t.Start();
// buat blok baru
BuatBlokBaru();
}
}
Dan kita harus memodifikasi kode TurunkanBlok:
private void TurunkanBlok()
{
// 1. Hapus bekas blok
_terkiniBlok.HapusDariPapan(this);
// 2. Turunkan blok 1 grid unit
System.Drawing.Point koordLama =
_terkiniBlok.KoordKiriAtas;
_terkiniBlok.KoordKiriAtas.Y += OFFSETPIXEL;
// 3. ReDraw Blok
_terkiniBlok.Draw(this);
Size s = new Size( (Blok.PANJANG * OFFSETPIXEL),
(Blok.LEBAR * OFFSETPIXEL) + OFFSETPIXEL);
this.Invalidate(new Rectangle(koordLama, s));
// // hapus kode berikut
// this.UpdateTerkiniTinggiTumpukan();
// Thread t = new Thread(new ThreadStart(CekTumpukan));
// t.Start();
}
Project Otak – http://otak.csharpindonesia.net 75
CSH202 – Pemrograman Game Tetris Dengan C#
Disini kita tidak lagi mengecek apakah ada baris komplet di tumpukan, karena sudah di-
handle oleh Timer.
Terakhir, modify Keypress-handler kita:
private void PapanPermainan_KeyPress(object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
switch (e.KeyChar)
{
case 'M':
goto case 'm';
case 'm':
BuatBlokBaru();
_timer.Enabled = true;
break;
case 'P':
goto case 'p';
case 'p':
// pause dotTetrus
_timer.Enabled = false;
String s = "*** GAME PAUSED ***" +
"
nTekan 'm' untuk kembali main";
MessageBox.Show(s);
break;
}
…
Dan tambahkan sebuah Load-handler (cara cepat membuat Load-handler adalah men-
dobelClick form Papan Permainan di Form Designer):
private void PapanPermainan_Load(object sender, System.EventArgs
e)
{
String s = "*** dotTetrus by Zeddy *** " +
"n http://www.zedilabs.com" +
"nn Tekan 'm' untuk mulai!";
MessageBox.Show(s);
}
OK, sebenarnya yang terakhir ini tidak perlu… tapi biasakanlah memberi kredit kepada
orang yang mengajarkan :P (euww… programmer emang musti egomaniac yah)
Project Otak – http://otak.csharpindonesia.net 76
CSH202 – Pemrograman Game Tetris Dengan C#
11.2 Kapan Game Over?
Kita harus menentukan kapan Game berakhir, dan ini caranya mudah. Tinggal
bandingkan _terkiniTinggiTumpukan apakah sama dengan 0 (nol):
private void CekGameOver()
{
if ( this._terkiniTinggiTumpukan >= 1 )
return; // belum saatnya
// game over, reset semua elemen
_timer.Enabled = false;
for (int i = 0; i < TINGGI; i++)
for (int j = 0; j < LEBAR; j++)
_elemen[i,j] = HITAM;
String s = "*** GAME OVER ***"
+ "n Tekan 'm' untuk mulai lagi";
MessageBox.Show(s);
// invalidate semuanya!
this.Invalidate();
}
Agar lebih fair, kita modify BlokBaru() agar memunculkan blok baru dari atas papan:
Perhatikan bahwa koordinat-y nya adalah negatif, oleh karena itu kita harus
menambahkan extra kode agar tidak muncul index out-of-range error.
private void BuatBlokBaru()
{
...
_terkiniBlok.KoordKiriAtas = new Point(100,-60); //
tengah atas
for (int i = _terkiniBlok.KoordKiriAtas.X;
i < i_max; i += OFFSETPIXEL)
{
for (int j = _terkiniBlok.KoordKiriAtas.Y;
j < j_max; j += OFFSETPIXEL)
{
if (i >= 0 && j >= 0) // TAMBAHKAN ini!
_elemen[j/OFFSETPIXEL, i/OFFSETPIXEL] =
HITAM;
}
}
...
Project Otak – http://otak.csharpindonesia.net 77
CSH202 – Pemrograman Game Tetris Dengan C#
11.3 Dua Bugs lagi…
Ternyata ada 2 bugs lagi yang perlu ditangani. Cara me-replikanya adalah:
Tekan ‘m’ untuk mulai game baru
Langsung geser kiri atau kanan dengan menggunakan ArrowKiri dan ArrowKanan.
Index out of range error gara-gara kita memulai dari koordinat negatif!
Cara menanganinya:
Modify method BisaDigeserKanan():
private bool BisaDigeserKanan()
{
...
// case 2: menyentuh blok lain di sebelah kanan
if ( _terkiniBlok.GetElemen(i,kolomTerkanan) == true
&& offset_i + i >= 0 && // TAMBAHKAN ini!
_elemen[offset_i + i,
offset_j + kolomTerkanan] > HITAM)
{
return false;
}
...
Dan juga method BisaDigeserKiri():
private bool BisaDigeserKiri()
{
...
// case 2: menyentuh blok lain di sebelah kiri
if ( _terkiniBlok.GetElemen(i,kolomTerkiri) == true
&& offset_i + i >= 0 && // TAMBAHKAN ini!
_elemen[offset_i + i,
offset_j + kolomTerkiri] > HITAM)
{
return false;
}
...
Build Solution dan jalankan dotTetrus!
Be proud of your first game!
Project Otak – http://otak.csharpindonesia.net 78
CSH202 – Pemrograman Game Tetris Dengan C#
PENUTUP Volum 1
Saya akan menutup perjumpaan kita sampai disini dulu. Memang banyak yang masih
perlu dilakukan, seperti:
test secara intensif untuk bugs
mengintegrasi sistem skor dan level
graphics yang lebih baik (sekarang Anda tahu cara menggambar image di canvas form
dengan DrawImage, maka mohon dibuat lebih bagus ImageBlok nya)
banyak kode yang mirip dan harus di-refactor agar terlihat lebih apik.
Kenapa ditutup sampai sini?
Karena saya sudah memberikan basic training nya. Sekarang Anda seharusnya bisa
mengimprovisasi program dotTetrus tanpa bimbingan saya. Dengan begitu, Anda bisa
belajar improvisasi, tidak tergantung “nyontek” kode orang lain :P
Kemudian alasan kedua adalah komitmen. Saya tidak bisa janji kapan akan ada Volum
2. Bahkan mungkin diantara Anda, ada yang sukses mengimprovisasi program
dotTetrus dan mau membagi pengalaman untuk menulis Volum 2-nya.
e-Book kecil ini ditulis dalam 5 hari, mulai Sabtu 19 Maret 2005 sampai dengan 23 Maret
2005. Ide-nya dari pengen nulis sebuah e-book yang fun (harus fun agar saya tidak
bosan menulis dan agar pembaca tertarik). Dalam proses penulisan ini, banyak yang
ditelantarkan; cucian dan setrikaan numpuk, makan telat, lupa belajar untuk kuliah hari
berikutnya, dan uang kost lupa dibayar. Alhamdulillah selesai, jadi saya bisa back to my
normal life :P
Salam,
Zeddy Iskandar.
www.zedilabs.com
Project Otak – http://otak.csharpindonesia.net 79
CSH202 – Pemrograman Game Tetris Dengan C#
Lampiran
MSDN Connection
MSDN Connection adalah komunitas developer .NET di Indonesia. Komunitas ini
bertujuan meningkatkan pemahaman dan pengalaman anda tentang .NET
Dengan bergabung bersama kami, anda otomatis mendapatkan update secara berkala
mengenai perkembangan teknologi .NET langsung dari Microsoft Indonesia.
Jika anda ingin bergabung dengan kami, caranya mudah. Hanya dengan mengklik url
http://www.msdnconnection.com/indonesia dan masukkan data-data anda.
Komunitas C# Indonesia
Komunitas C# Indonesia merupakan bagian dari komunitas .NET Indonesia (INDC) yang
berfokus kebidang teknologi .NET dengan menggunakan bahasa C#
Komunitas C# Indonesia dapat dijumpai di url www.csharpindonesia.net dan anda dapat
bergabung di site ini.
Komunitas .NET Indonesia (INDC)
Komunitas .NET Indonesia merupakan official dari komunitas-komunitas di Indonesia
yang berbasis .NET. Anda bisa bertemu dengan beberapa aktivis komunitas .NET
diseluruh wilayah Indonesia.
Anda dapat bergabung kedalam komunitas ini dengan masuk ke url
www.netindonesia.net dan dapat juga bergabung ke milis DOTNET dengan cara
mengirim email kosong ke dotnet-subscribe@netindonesia.net
Project Otak – http://otak.csharpindonesia.net 80
CSH202 – Pemrograman Game Tetris Dengan C#
Strukutur Organisasi Project Otak 2005-2006
Secara umum:
Semua team adalah Technical Writer
Semau Technical Writer harus mentaati semua aturan yang dibuat oleh Technical
Writer Leader pada setiap project yang diikuti
Semua wajib menyukseskan semua project yang ada di project otak
Project Manager
Manajemen semua departemen dan kegiatannya
Interface antara team project otak dengan publik
Memastikan semua kegiatan berjalan sesuai dengan scenario dan fungsinya.
Secretary
Mengatur semua administrasi project otak
Manajemen keanggotaan team project otak
Resource, Information, and Technology Department
Diketuai oleh seorang Kepala Department ( Department Head)
Tugas
o Manajemen resource technical writer termasuk alokasi timing
o Mengontrol semua project yang sedang berjalan agar berjalan sesuai
dengan schedule
Didalam departemen ini terdiri dari semua technical writer
Setiap project e-book akan dikepalai oleh Technical Writer Leader yang
bertanggung jawab ke Department Head
Project Otak – http://otak.csharpindonesia.net 81
CSH202 – Pemrograman Game Tetris Dengan C#
QA Department
Diketuai oleh seorang Kepala Department ( Department Head)
Tugas
o Manajemen resource Technical Editor
o Menguji semua materi yang ada sesuai dengan standard dan template
Planning, Strategic, and Finance Department
Diketuai oleh seorang Kepala Department ( Department Head)
Tugas
o Membuat planning dan strategi dalam hal pengembangan dan peningkatan
project otak baik materi, resource maupun member
o Mencari sumber dana baik dari bentuk kerja sama maupun sponsorship
Publication and Marketing Department
Diketuai oleh seorang Kepala Department ( Department Head)
Tugas
o Membuat publikasi dan marketing ke publik tentang project otak
Berikut ini susunan pengurus project otak yang baru dan berlaku sejak
tanggal 3 Desember 2004
Project Manager : Agus Kurniawan (agusasia@yahoo.com)
Secretary : Clementine Katarina Dewi Maya (demayac@yahoo.com)
Resource, Information, and
Technology Department Head
: M Fathur Rahman (fatur@inforsys.co.id )
QA Department Head : Panji Aryaputra (paputra@gmail.com )
Planning, Strategic, and Finance
Department Head
: Risman Adnan (rismana@microsoft.com )
Publication and Marketing
Department Head
: Kunarto (ch03n@yahoo.com )
Untuk pengurus diatas, program kerja nya bisa dimulai pada tanggal 3 Desember 2004
Agus Kurniawan
Project Manager of Project Otak
Project Otak – http://otak.csharpindonesia.net 82
CSH202 – Pemrograman Game Tetris Dengan C#
Program Donatur Project Otak
Untuk kemajuan dan kelangsungan project otak, kami dari team project otak
mengundang para participant yang peduli atas kemajuan project ini dan resource
teknologi .NET untuk menyumbang dana ke project ini.
Program donatur ini terbagi menjadi 2 jenis yaitu
Program donatur untuk kategori personal. Program ini dapat diikuti oleh masing-
masing individu yang peduli pada project ini.
Program donatur untuk kategori perusahan/institusi/lembaga. Program ini dapat
diikuti oleh perusahan/institusi/lembaga
Jika anda atau perusahan/institusi/lembaga anda tertarik untuk menyumbangkan dana
ke project otak ini maka bisa menghubungi project manager, Agus Kurniawan, via email
yaitu: agusasia@yahoo.com
Project Otak – http://otak.csharpindonesia.net 83

More Related Content

What's hot

Cara membuka microsoft power point
Cara membuka microsoft power pointCara membuka microsoft power point
Cara membuka microsoft power point
Reychando
 
Materi Pengujian dan Implementasi Sistem.pptx
Materi Pengujian dan Implementasi Sistem.pptxMateri Pengujian dan Implementasi Sistem.pptx
Materi Pengujian dan Implementasi Sistem.pptx
RizqiIrawan2
 
Contoh analisis-kuesioner
Contoh analisis-kuesionerContoh analisis-kuesioner
Contoh analisis-kuesioner
Abdul Manap
 
Proposal penawaran pembuatan website baru
Proposal penawaran pembuatan website baruProposal penawaran pembuatan website baru
Proposal penawaran pembuatan website baru
Tysar Budirianto
 
Laporan Makalah Pembuatan Website E-Commerce-Basis Data
Laporan Makalah Pembuatan Website E-Commerce-Basis DataLaporan Makalah Pembuatan Website E-Commerce-Basis Data
Laporan Makalah Pembuatan Website E-Commerce-Basis Data
Shofura Kamal
 
Soal uas bhs indonesia kelas 1 smtr 1
Soal uas bhs indonesia  kelas 1 smtr 1Soal uas bhs indonesia  kelas 1 smtr 1
Soal uas bhs indonesia kelas 1 smtr 1
May Aza
 

What's hot (20)

Informatika (BK).pptx
Informatika (BK).pptxInformatika (BK).pptx
Informatika (BK).pptx
 
Latihan soal uts pai kelas 1 sd semester 1
Latihan soal uts pai kelas 1 sd semester 1Latihan soal uts pai kelas 1 sd semester 1
Latihan soal uts pai kelas 1 sd semester 1
 
Soal PTS Ganjil Bahasa Inggris Kelas IX
Soal PTS Ganjil Bahasa Inggris Kelas IXSoal PTS Ganjil Bahasa Inggris Kelas IX
Soal PTS Ganjil Bahasa Inggris Kelas IX
 
Cara membuka microsoft power point
Cara membuka microsoft power pointCara membuka microsoft power point
Cara membuka microsoft power point
 
Soal bahasa inggris personal pronoun as object and subject
Soal bahasa inggris personal pronoun as object and subjectSoal bahasa inggris personal pronoun as object and subject
Soal bahasa inggris personal pronoun as object and subject
 
Merumuskan tujuan penelitian
Merumuskan tujuan penelitianMerumuskan tujuan penelitian
Merumuskan tujuan penelitian
 
Materi Pengujian dan Implementasi Sistem.pptx
Materi Pengujian dan Implementasi Sistem.pptxMateri Pengujian dan Implementasi Sistem.pptx
Materi Pengujian dan Implementasi Sistem.pptx
 
Soal uas pai kelas 2 sd semester 2 dan kunci jawabaan(1)
Soal uas pai kelas 2 sd semester 2 dan kunci jawabaan(1)Soal uas pai kelas 2 sd semester 2 dan kunci jawabaan(1)
Soal uas pai kelas 2 sd semester 2 dan kunci jawabaan(1)
 
Contoh analisis-kuesioner
Contoh analisis-kuesionerContoh analisis-kuesioner
Contoh analisis-kuesioner
 
Proposal penawaran pembuatan website baru
Proposal penawaran pembuatan website baruProposal penawaran pembuatan website baru
Proposal penawaran pembuatan website baru
 
Laporan Makalah Pembuatan Website E-Commerce-Basis Data
Laporan Makalah Pembuatan Website E-Commerce-Basis DataLaporan Makalah Pembuatan Website E-Commerce-Basis Data
Laporan Makalah Pembuatan Website E-Commerce-Basis Data
 
Soal uas bhs indonesia kelas 1 smtr 1
Soal uas bhs indonesia  kelas 1 smtr 1Soal uas bhs indonesia  kelas 1 smtr 1
Soal uas bhs indonesia kelas 1 smtr 1
 
SOAL EVALUASI KELAS 2 TEMA 1 HIDUP RUKUN (REVISI 2017)
SOAL EVALUASI KELAS 2 TEMA 1 HIDUP RUKUN (REVISI 2017)SOAL EVALUASI KELAS 2 TEMA 1 HIDUP RUKUN (REVISI 2017)
SOAL EVALUASI KELAS 2 TEMA 1 HIDUP RUKUN (REVISI 2017)
 
Pts pkn kelas 3
Pts pkn kelas 3Pts pkn kelas 3
Pts pkn kelas 3
 
Slideshow PowerPoint Software Testing
Slideshow PowerPoint Software TestingSlideshow PowerPoint Software Testing
Slideshow PowerPoint Software Testing
 
materi-pengenalan-komputer-untuk-sekolah-dasar-sd.pptx
materi-pengenalan-komputer-untuk-sekolah-dasar-sd.pptxmateri-pengenalan-komputer-untuk-sekolah-dasar-sd.pptx
materi-pengenalan-komputer-untuk-sekolah-dasar-sd.pptx
 
Manajemen Perencanaan Proyek
Manajemen Perencanaan ProyekManajemen Perencanaan Proyek
Manajemen Perencanaan Proyek
 
soal PLBJ kelas 3.docx
soal PLBJ kelas 3.docxsoal PLBJ kelas 3.docx
soal PLBJ kelas 3.docx
 
Berpikir komputasional Kelas 7
Berpikir komputasional Kelas 7Berpikir komputasional Kelas 7
Berpikir komputasional Kelas 7
 
3 Contoh Prototype
3 Contoh Prototype3 Contoh Prototype
3 Contoh Prototype
 

Similar to Pemrograman game tetris C#

Pemrograman Game Tetris Dengan C#
Pemrograman Game Tetris Dengan C#Pemrograman Game Tetris Dengan C#
Pemrograman Game Tetris Dengan C#
Robby Angryawan
 
In office training
In office trainingIn office training
In office training
Fauzan Andi
 
soal tkj mm kelas x sabtu 7 juni 2014
soal tkj mm kelas x sabtu 7 juni 2014soal tkj mm kelas x sabtu 7 juni 2014
soal tkj mm kelas x sabtu 7 juni 2014
safiqnda
 
Soal try out rpl 2014
Soal try out rpl 2014Soal try out rpl 2014
Soal try out rpl 2014
Rose Athy
 
Microsoft project 2007 tutorial
Microsoft project 2007   tutorialMicrosoft project 2007   tutorial
Microsoft project 2007 tutorial
Muhammad Umari
 

Similar to Pemrograman game tetris C# (20)

Pemrograman Game Tetris Dengan C#
Pemrograman Game Tetris Dengan C#Pemrograman Game Tetris Dengan C#
Pemrograman Game Tetris Dengan C#
 
In office training
In office trainingIn office training
In office training
 
Pengenalan android ndk
Pengenalan android ndkPengenalan android ndk
Pengenalan android ndk
 
Game tetris menggunakan_arduino
Game tetris menggunakan_arduinoGame tetris menggunakan_arduino
Game tetris menggunakan_arduino
 
Dasar Kompetensi Keahlian TKJ - SMK
Dasar Kompetensi Keahlian TKJ - SMKDasar Kompetensi Keahlian TKJ - SMK
Dasar Kompetensi Keahlian TKJ - SMK
 
Modul-Gambar-Teknik-Mesin-2.pdf
Modul-Gambar-Teknik-Mesin-2.pdfModul-Gambar-Teknik-Mesin-2.pdf
Modul-Gambar-Teknik-Mesin-2.pdf
 
soal tkj mm kelas x sabtu 7 juni 2014
soal tkj mm kelas x sabtu 7 juni 2014soal tkj mm kelas x sabtu 7 juni 2014
soal tkj mm kelas x sabtu 7 juni 2014
 
Scratch 2.0 Id
Scratch 2.0 Id Scratch 2.0 Id
Scratch 2.0 Id
 
Ebook Belajar Mengoperasikan Microsoft Project
Ebook Belajar Mengoperasikan Microsoft ProjectEbook Belajar Mengoperasikan Microsoft Project
Ebook Belajar Mengoperasikan Microsoft Project
 
Soal try out rpl 2014
Soal try out rpl 2014Soal try out rpl 2014
Soal try out rpl 2014
 
Melakukan Perawatan PC
Melakukan Perawatan PCMelakukan Perawatan PC
Melakukan Perawatan PC
 
Program kerja tkj_2020-2021
Program kerja tkj_2020-2021Program kerja tkj_2020-2021
Program kerja tkj_2020-2021
 
IDCamp X Madrasah: Pengenalan Computational Thinking
IDCamp X Madrasah: Pengenalan Computational ThinkingIDCamp X Madrasah: Pengenalan Computational Thinking
IDCamp X Madrasah: Pengenalan Computational Thinking
 
Profil D3RPLA Universitas Telkom
Profil D3RPLA Universitas TelkomProfil D3RPLA Universitas Telkom
Profil D3RPLA Universitas Telkom
 
Struktur sketch.pdf
Struktur sketch.pdfStruktur sketch.pdf
Struktur sketch.pdf
 
Silabus simdig psmk
Silabus simdig psmkSilabus simdig psmk
Silabus simdig psmk
 
Instalasi python 3 dan ide atau anaconda distribution pada windows 10
Instalasi python 3 dan ide atau anaconda distribution pada windows 10Instalasi python 3 dan ide atau anaconda distribution pada windows 10
Instalasi python 3 dan ide atau anaconda distribution pada windows 10
 
CARA BIJAK KUASAI TOPIK BERKAITAN MIKROPENGAWAL.pdf
CARA BIJAK KUASAI TOPIK BERKAITAN MIKROPENGAWAL.pdfCARA BIJAK KUASAI TOPIK BERKAITAN MIKROPENGAWAL.pdf
CARA BIJAK KUASAI TOPIK BERKAITAN MIKROPENGAWAL.pdf
 
Microsoft project 2007 tutorial
Microsoft project 2007   tutorialMicrosoft project 2007   tutorial
Microsoft project 2007 tutorial
 
28 tik motion graphic art 280 jp_2021
28 tik motion graphic art 280 jp_202128 tik motion graphic art 280 jp_2021
28 tik motion graphic art 280 jp_2021
 

Pemrograman game tetris C#

  • 1.
  • 2. CSH202 – Pemrograman Game Tetris Dengan C# Pemgraman Game Tetris Dengan C# (CSH202) Zeddy Iskandar Project Otak 2005 Project Otak – http://otak.csharpindonesia.net 2
  • 3. CSH202 – Pemrograman Game Tetris Dengan C# Project Otak Project otak adalah project community yang bertujuan untuk menyediakan resources tentang informasi teknologi .NET bagi orang-orang yang ingin belajar teknologi .NET. Trademark Acknowledgements Team project otak akan berusaha menyediakan informasi trademark termasuk semua produk yang telah disebut didalam buku ini. Windows, Framework .NET, C#, dan Visual Studio.NET adalah trademark dari Microsoft Credits Project Manager Secretary Agus Kurniawan Dewi Maya Technical Writer Zeddy Iskandar Editor Agus Kurniawan Cover Designer Danni Afasyah Version 1.0 Printed: 2 April 2005 Book Code: CSH202 Update E-Book : http://otak.csharpindonesia.net Semua materi yang ada didalam buku ini adalah satu kesatuan. Tidak boleh sebagian atau seluruh materi didalam buku ini diubah tanpa seijin team project otak. Project Otak – http://otak.csharpindonesia.net 3
  • 4. CSH202 – Pemrograman Game Tetris Dengan C# Kata Pengantar Saya ingin membuat e-book yang fun dan informatif. Bagi saya, menulis adalah pekerjaan yang membosankan, kecuali bila topik yang kita tulis membuat kita antusias. Begitulah, saya ingin membuat e-book yang saya sendiri senang menulisnya. Mudah- mudahan bermanfaat. Apa yang Dapat Dipelajari Membuat elemen grafik untuk game. Menggunakan Visual Studio .Net. Membuat simple game semacam Tetris. Mengerti konsep Windows Message seperti WM_PAINT. Membuat game secara object-oriented. Mengaplikasikan Design Pattern Factory. Target Pembaca Banyak programmer yang sebelum menyentuh komputer menyentuh permainan konsol seperti Nintendo, Sega, PS, dsb. Ketika mereka belajar programming, biasanya mereka tertarik untuk membuat game, tapi tidak tahu harus mulai dari mana. Buku ini bisa dijadikan fondasi mereka untuk belajar tentang game-programming. Pembaca HARUS sudah mengerti bahasa programming C#. Andaikan tidak, saya sarankan untuk membaca e-book CSH101: Pengenalan Bahasa C# oleh Agus Kurniawan dkk. di website Otak Project (http://otak.csharpindonesia.net) Pembaca juga MINIMAL sudah pernah membuat project di Visual Studio dan pernah menggunakan Graphics Editing Program semacam Adobe Photoshop atau bahkan Microsoft Paint. Bukan berarti Anda harus jago graphics design atau Photoshop Expert, tapi cukup tahu bagaimana membuat simple object semacam segi empat dsb. Baiklah, tanpa banyak basa-basi, mari kita mulai perjalanan kita ke dunia game- programming. Zeddy Iskandar Curtin University of Technology (Malaysia Campus) Project Otak – http://otak.csharpindonesia.net 4
  • 5. CSH202 – Pemrograman Game Tetris Dengan C# Tentang Penulis Zeddy Iskandar Zeddy Iskandar, mahasiswa semester akhir Curtin University of Technology (Malaysia Campus), mulai belajar programming dengan GW-BASIC sewaktu sekolah Primary 5 di Colombo International School, Sri Lanka. Semenjak sahabatnya membeli computer Compaq 486-DX 33Mhz, dia menjadi lebih tertarik dengan dunia komputer. Sempat vakum dari dunia komputer ketika di Singapura (karena komputer ibu kost nya dipindahkan) dan SMA di Jakarta (karena komputernya mengeluarkan asap dan orangtua tidak mau memperbaikinya). Ketika sang Ayah berangkat tugas lagi ke Brunei, dunia komputer khususnya programming mulai diarungi kembali. Mulai dengan Visual Basic berangsur-angsur ke C, C++, PHP, Java, JSP,. Sekarang konsentrasi di Microsoft .Net platform. Cita-citanya adalah mengajar programming di sebuah universitas kelak. Dia dapat dihubungi melalui email zeddy.iskandar@gmail.com Kupersembahkan ebook ini untuk kedua orangtuaku, yang akhirnya menyadari potensi anaknya di dunia komputer =) Especially sang Ayah, yang kartu kreditnya sering dibobol untuk membeli buku programming di Amazon.com. I’ll repay you someday, Dad! Project Otak – http://otak.csharpindonesia.net 5
  • 6. CSH202 – Pemrograman Game Tetris Dengan C# Daftar Isi Project Otak .......................................................................................................3 Credits.................................................................................................................3 Kata Pengantar.....................................................................................................4 Tentang Penulis....................................................................................................5 Daftar Isi ...............................................................................................................6 1. Menyusun Blok-Blok Tetris ...............................................................................8 1.1 Data Struktur untuk Blok Tetris............................................................................... 8 1.2 Data Struktur Papan Permainan............................................................................... 9 1.3 Elemen untuk blok Tetris....................................................................................... 10 2. Design Klas Blok.............................................................................................14 2.1 UML Diagram........................................................................................................ 15 2.2 Visual Studio .Net.................................................................................................. 15 2.3 Klas Blok ............................................................................................................... 17 2.4 Klas BlokGaris....................................................................................................... 19 2.5 Klas BlokKotak...................................................................................................... 23 2.7 Klas BlokZNormal................................................................................................. 26 2.8 Klas BlokZTerbalik ............................................................................................... 27 2.9 Klas BlokLNormal................................................................................................. 28 2.10 Klas BlokLTerbalik ............................................................................................. 30 3. Papan Permainan ...........................................................................................33 3.1 Menambahkan fields.............................................................................................. 35 3.2 Menambahkan methods ......................................................................................... 36 3.3 Koordinat Pixel dan Grid Unit............................................................................... 37 4. Klas ImageBlok dan Menggambar di atas Canvas .........................................39 4.1 Klas ImageBlok ..................................................................................................... 39 4.2 Modifikasi Klas Blok............................................................................................. 40 4.3 Definisi Draw() di Klas Blok................................................................................. 41 5. Mengaplikasikan Factory Pattern...................................................................44 5.1 Klas BlokFactory ................................................................................................... 44 5.2 Method BuatBlokBaru() untuk klas PapanPermainan........................................... 46 6. Menggunakan Invalidate() ..............................................................................48 6.1 Penambahan method SetElemen() dan GetElemen()............................................. 49 6.2 Modifikasi klas Blok.............................................................................................. 50 6.3 Modifikasi PapanPermainan.BuatBlokBaru() ....................................................... 51 6.4 Sekilas tentang Invalidate().................................................................................... 51 7. Merespons Keyboard Event............................................................................54 7.1 Merespons key Bawah........................................................................................... 55 7.2 Merespons key Kiri................................................................................................ 56 7.3 Merespons Key Kanan........................................................................................... 56 8. Menumpuk Blok ..............................................................................................58 8.1 Modifikasi Klas Blok............................................................................................. 58 Project Otak – http://otak.csharpindonesia.net 6
  • 7. CSH202 – Pemrograman Game Tetris Dengan C# 8.2 Mengkontrol Penurunan Blok................................................................................ 58 8.3 Mengkontrol Penggeseran Kiri.............................................................................. 59 8.4 Mengkontrol Penggeseran Kanan.......................................................................... 61 9. Merotasikan Blok ............................................................................................63 9.1 Menambahkan ICloneable ke klas Blok ................................................................ 63 9.2 Method BisaRotasi() untuk klas PapanPermainan................................................. 64 9.3 Modifikasi KeyPress-handler................................................................................. 66 10. Menghilangkan Baris Komplet ......................................................................68 10.1 Menampilkan “Blink” effect................................................................................ 70 11. Menggunakan Timer.....................................................................................74 11.1 Menambahkan Timer........................................................................................... 74 11.2 Kapan Game Over?.............................................................................................. 77 11.3 Dua Bugs lagi…................................................................................................... 78 PENUTUP Volum 1.............................................................................................79 Lampiran.............................................................................................................80 Strukutur Organisasi Project Otak 2005-2006 ....................................................81 Program Donatur Project Otak............................................................................83 Project Otak – http://otak.csharpindonesia.net 7
  • 8. CSH202 – Pemrograman Game Tetris Dengan C# 1. Menyusun Blok-Blok Tetris Ada banyak cara membuat program Tetris. Cara saya mungkin tidak efisien, tapi setidaknya simple. 1.1 Data Struktur untuk Blok Tetris Baiklah, kita mulai dari dasar. Bagaimana menggambar blok Tetris? Bayangkan ARRAY 2-dimensi (dalam dunia .Net Framework dikenal dengan rectangular array), dengan panjang-lebar 4x4: Data struktur ini bisa digunakan untuk menyimpan definisi blok-blok Tetris yang ada. Tapi tentunya menyimpan sebuah bitmap atau file grafik ke dalam array akan memakan tempat. Lantas bagaimana implementasinya? Blok “Kros” diatas tadi dapat di- implementasikan menggunakan array of boolean values. Jadi yang disimpan di array adalah TRUE atau FALSE: F F F F F T F F T T T F F F F F Kemudian, pada saatnya dibutuhkan untul ditampilkan, barulah kita ganti tiap-tiap TRUE dengan sebuah image pixel berwarna. Project Otak – http://otak.csharpindonesia.net 8
  • 9. CSH202 – Pemrograman Game Tetris Dengan C# 1.2 Data Struktur Papan Permainan Kita dapat menggunakan boolean array juga sebagi papan permainan dimana blok-blok Tetris akan diletakkan. Misalnya dengan ukuran panjang-lebar 12x20: Project Otak – http://otak.csharpindonesia.net 9
  • 10. CSH202 – Pemrograman Game Tetris Dengan C# 1.3 Elemen untuk blok Tetris Telah saya sebutkan bahwa sebuah blok Tetris disimpan sebagai 4x4 array dan manakala ada value True, maka disitulah kita insert sebuah box grafik. Buka Adobe Photoshop atau aplikasi grafik favorit Anda sekarang. Pertama saya buat asumsi bahwa sebuah blok elemen akan memiliki pixel size 20x20. Sehingga di Adobe, saya buat File→New dgn spesifikasi berikut: Width = 240 karena 12 blok x 20 pixel width. Height = 400 karena 20 blok x 20 pixel height. RGB karena kita ingin tiap blok Tetris (garis, kros, kotak, dsb) mempunyai warna yg berbeda. Selanjutnya saya cek apakah papan permainan kelihatan pas (tidak terlalu besar atau kecil): Project Otak – http://otak.csharpindonesia.net 10
  • 11. CSH202 – Pemrograman Game Tetris Dengan C# Saya menggunakan opsi berikut di Adobe: Edit→Preferences→Units & Rulers Units::Rulers::Pixels Edit→Preferences→Guides, Grid & Slices Gridline every: 20 pixels Subdivision: 1 View→Show→Grid View→Rulers Project Otak – http://otak.csharpindonesia.net 11
  • 12. CSH202 – Pemrograman Game Tetris Dengan C# Karena di monitor saya kelihatan OK, saya tentukan bahwa pixel width dan height = 20. Misal ini kurang pas (apalagi Anda menggunakan resolusi 640x480 di jaman begini), silahkan sesuaikan dengan monitor Anda, mungkin misalnya menjadi 12x12 pixel. Sekarang kita buatkan blok elemen untuk 7 warna (karena akan ada 7 blok Tetris). File→New: Width: 20 pixels Height: 20 pixels Colour Mode: RGB Gunakan Paint Bucket Tool untuk mewarnai pixel: Buat 7 macam dengan spesifikasi warna berikut: No. Warna RGB value 1. Merah R:255, G:0, B:0 2. Kuning R:255, G:255, B:0 3. Hijau R:0, G:255, B:0 4. Biru R:0, G:0, B:255 5. Magenta R:255, G:0, B:255 6. Cyan R:0, G:255, B:255 7. Coklat R: 198, G:156, B:109 Project Otak – http://otak.csharpindonesia.net 12
  • 13. CSH202 – Pemrograman Game Tetris Dengan C# Setelah itu, silahkan drag-n-drop masing-masing blok elemen berwarna untuk menyusun blok-blok Tetris. Bagaimana semangat Anda sekarang? Kita akan mulai menuliskan kode di bab selanjutnya! Project Otak – http://otak.csharpindonesia.net 13
  • 14. CSH202 – Pemrograman Game Tetris Dengan C# 2. Design Klas Blok Di sini saya definisikan apa yang dimaksud dengan Blok. Definisi ini akan dipakai sampai akhir buku. Blok adalah bentuk-bentuk (shape) yang harus disusun dalam game Tetris. Blok ini ada 7 macam: 1. Baris 5. ZTerbalik 2. Kotak 6. LNormal 3. Kros 7. LTerbalik 4. ZNormal Inilah saatnya untuk menggunakan konsep inheritance dalam object-oriented programming. Project Otak – http://otak.csharpindonesia.net 14
  • 15. CSH202 – Pemrograman Game Tetris Dengan C# 2.1 UML Diagram KoordKiriAtas akan dijelaskan pada bab berikutnya. Panjang dan Lebar adalah 4x4. Karena value ini tetap, maka saya menggunakan const modifier. Dan karena ini konstan, kita boleh membuatnya public. Draw() berisi kode untuk mengupdate gambar blok di atas papan permainan. Method ini tidak virtrual karena kodenya sama untuk semua subclass. RotateAtas() dsb adalah kode untuk mengubah posisi blok sesuai dengan tombol yang ditekan user pada keyboard. Method ini virtual karena tiap-tiap blok jika di-rotasi akan berbeda posisinya dari blok yang lain. 2.2 Visual Studio .Net Sekarang saatnya untuk membuat VS.Net dan mulai menambahkan kode sedikit demi sedikit. Pilih File→New→Project: Project Type: Visual C# Projects Template: Windows Application Name: dotTetrus Location: Terserah *Nama “Tetris” adalah hak intelektual seorang programmer Russia yang sekarang kaya karena mendapatkan royalti dari game Tetris. Oleh karenanya, kita tidak boleh membuat game dengan nama “Tetris” atau yang bunyinya mirip. Project Otak – http://otak.csharpindonesia.net 15
  • 16. CSH202 – Pemrograman Game Tetris Dengan C# Untuk saat ini, kita ignore User Interface atau Windows Forms nya. Kita konsentrasi membuat class dahulu. Lihat Class View. Right-click Project dotTetrus, pilih Add→Class. Project Otak – http://otak.csharpindonesia.net 16
  • 17. CSH202 – Pemrograman Game Tetris Dengan C# Isi sesuai dgn di atas dan click Finish. 2.3 Klas Blok Berikut kode untuk variabel-variabel konstan: public class Blok { // Variabel-variabel konstan public const int LEBAR = 4; public const int PANJANG = 4; // digunakan oleh BlokFactory nantinya public const int BARIS = 0; public const int KOTAK = 1; public const int KROS = 2; public const int ZNORMAL = 3; public const int ZTERBALIK = 4; public const int LNORMAL = 5; public const int LTERBALIK = 6; Sebelum menambahkan variabel-variabel private, kita harus Add Reference System.Drawing dahulu agar bisa menggunakan struktur System.Drawing.Point. Caranya klik Project→Add Reference, cari System.Drawing.dll dan klik Select: Project Otak – http://otak.csharpindonesia.net 17
  • 18. CSH202 – Pemrograman Game Tetris Dengan C# Klik OK setelah itu. Lalu kita tambahkan using statement di bagian atas file Blok.cs: using System; using System.Drawing; Nah, sekarang kita bisa menggunakan struct Point di class Blok. Sambung dari kode sebelumnya: // Public karena tidak perlu validasi rvalue public Point KoordKiriAtas; // Variabel-variable hidden protected bool[,] _elemen; public Blok() { // init 4x4 bool array _elemen = new bool[PANJANG,LEBAR]; } protected void ResetElemen() { // set semua values array menjadi false for (int i = 0; i < PANJANG; i++) for (int j = 0; j < LEBAR; j++) _elemen[i,j] = false; } public void Draw() { } public virtual void RotateAtas() { } public virtual void RotateBawah() { } Project Otak – http://otak.csharpindonesia.net 18
  • 19. CSH202 – Pemrograman Game Tetris Dengan C# public virtual void RotateKanan() { } public virtual void RotateKiri() { } _koordKiriAtas dan _elemen perlu diakses dari subclass-subclass seperti BlokGaris, oleh karena itu modifier mereka adalah protected dan bukan private. Method Draw() adalah sama untuk semua blok, namun kita akan kembali setelah mempelajari tentang Device Context. Method-method yg virtual akan di override oleh masing-masing subclass nantinya. ResetElemen() diperlukan untuk mereset semua elemen blok sebelum di-rotasi. Method ini protected karena tidak boleh dipanggil dari luar class Blok, namun harus dapat diakses oleh subclass seperti BlokGaris dsb. 2.4 Klas BlokGaris Sekarang kita siap untuk membuat 7 subclass Blok. Pilih Class View, right-click dotTetrus Project→Add Class: Isi sesuai dengan bagan diatas, namun jangan klik OK terlebih dahulu. Pilih opsi Base Class dari sebelah kiri: Project Otak – http://otak.csharpindonesia.net 19
  • 20. CSH202 – Pemrograman Game Tetris Dengan C# Pilih Blok sebagai Base Class, dan klik Finish. Nah, dalam subclass BlokGaris dan subclass-subclass berikutnya, kita hanya perlu mengisi kode untuk constructor dan meng-override virtual methods dari base class Blok. Berikut data struktur untuk BlokGaris: Oleh karenanya kode untuk constructor nya adalah: public BlokGaris() : base() { _elemen[0,0] = true; _elemen[1,0] = true; _elemen[2,0] = true; _elemen[3,0] = true; } Statement base() adalah untuk memanggil base class konstruktor Blok() sebelum meng- konstruk sebuah BlokGaris instance. Ini sangat essensial karena hanya di konstruktor Blok() –lah kita meng-initialize array kita menjadi 4x4 boolean array! Sekarang kita harus meng-override semua virtual methods dari Base Class Blok. Tidak ingat? Caranya mudah dengan menggunakan Class View. Di Class View, pilih class BlokGaris, klik tanda + pada Bases and Interfaces. Right-click method RotateAtas() → pilih Add → Override. Project Otak – http://otak.csharpindonesia.net 20
  • 21. CSH202 – Pemrograman Game Tetris Dengan C# Lakukan hal ini untuk RotateBawah(), RotateKanan(), RotateKiri(). Untuk RotateAtas() dan RotateBawah() tidak akan mengubah posisi elemen BlokGaris: Maka kodenya pun sama dengan kode konstruktor: public override void RotateAtas() { base.ResetElemen(); _elemen[0,0] = true; _elemen[1,0] = true; _elemen[2,0] = true; _elemen[3,0] = true; } public override void RotateBawah() { this.RotateAtas(); } *Tips: Karena kode di tiga method ini sama (konstruktor, RotateAtas dan RotateBawah), maka dengan prinsip refactoring, seharusnya kode yang sama ini dipindah ke dalam suatu method, dan method inilah yang harusnya dipanggil dari konstruktor, RotateAtas() dan RotateBawah(). Jika di-rotasi ke kanan akan berubah menjadi: Project Otak – http://otak.csharpindonesia.net 21
  • 22. CSH202 – Pemrograman Game Tetris Dengan C# Rotasi ke kanan dan kiri juga hasilnya akan sama, maka kode mereka menjadi: public override void RotateKanan() { base.ResetElemen(); _elemen[3,0] = true; _elemen[3,1] = true; _elemen[3,2] = true; _elemen[3,3] = true; } public override void RotateKiri() { this.RotateKanan(); } *Sekarang saatnya Anda mengcompile semua .cs file. Ini diperlukan setiap selesai menulis suatu class baru, untuk make sure error-error di kelas tersebut diperbaiki dahulu sebelum menulis sebuah class lain. Klik Build → Build Solution. Jika Anda menemui error, berarti Anda perlu meninjau kembali kode Anda! Mohon cek lagi pelan-pelan dan sabar sebelum melanjutkan ke klas berikutnya… Project Otak – http://otak.csharpindonesia.net 22
  • 23. CSH202 – Pemrograman Game Tetris Dengan C# 2.5 Klas BlokKotak *Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right- click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah! Klas ini mungkin yang termudah karena semua rotasi tidak menghasilkan apa-apa. Sehingga kode untuk method RotasiAtas(), RotasiBawah(), dsb adalah kosong. Berikut bagan elemen ketika sebuah klas BlokKotak dibuat: Oleh karenanya, kode untuk konstruktor-nya ialah: public class BlokKotak : dotTetrus.Blok { public BlokKotak() : base() { _elemen[1,0] = true; _elemen[1,1] = true; _elemen[2,0] = true; _elemen[2,1] = true; } … Dan kosong untuk semua method Rotasi() nya: public override void RotateAtas() { } public override void RotateBawah() { } public override void RotateKanan() { } public override void RotateKiri() { } Sekali lagi, tekan kombinasi tombol Ctrl – Shift – B untuk mem-build solution dan perhatikan apakah ada error atau tidak! Project Otak – http://otak.csharpindonesia.net 23
  • 24. CSH202 – Pemrograman Game Tetris Dengan C# 2.6 Klas BlokKros *Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right- click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah! Untuk klas ini, kita akan memiliki kode yang berbeda untuk masing-masing RotasiAtas(), RotasiBawah(), RotasiKiri() dan RotasiKanan() Pada saat dibentuk, BlokKros akan menghadap ke atas, oleh karenanya kode untuk Constructor dan RotasiAtas menjadi sama: public class BlokKros : dotTetrus.Blok { public BlokKros() : base() { this.RotateAtas(); } public override void RotateAtas() { base.ResetElemen(); _elemen[1,1] = true; _elemen[2,0] = true; _elemen[2,1] = true; _elemen[2,2] = true; } … Untuk RotasiBawah() menjadi: Project Otak – http://otak.csharpindonesia.net 24
  • 25. CSH202 – Pemrograman Game Tetris Dengan C# public override void RotateBawah() { base.ResetElemen(); _elemen[2,0] = true; _elemen[2,1] = true; _elemen[2,2] = true; _elemen[3,1] = true; } Untuk RotasiKanan() menjadi: public override void RotateKanan() { base.ResetElemen(); _elemen[1,1] = true; _elemen[2,1] = true; _elemen[3,1] = true; _elemen[2,2] = true; } Untuk RotasiKiri() menjadi: public override void RotateKiri() { base.ResetElemen(); _elemen[2,0] = true; _elemen[1,1] = true; _elemen[2,1] = true; _elemen[3,1] = true; } Project Otak – http://otak.csharpindonesia.net 25
  • 26. CSH202 – Pemrograman Game Tetris Dengan C# 2.7 Klas BlokZNormal *Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right- click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah! Untuk klas ini, kita akan memiliki kode RotasiAtas() dan RotasiBawah() yang sama, RotasiKiri() dan RotasiKanan() pun sama. Pada saat dibentuk, BlokZNormal akan menghadap ke atas, oleh karenanya kode untuk Constructor dan RotasiAtas menjadi sama: public class BlokZNormal : dotTetrus.Blok { public BlokZNormal() : base() { this.RotateAtas(); } public override void RotateAtas() { base.ResetElemen(); _elemen[3,0] = true; _elemen[3,1] = true; _elemen[2,1] = true; _elemen[2,2] = true; } public override void RotateBawah() { this.RotateAtas(); } … Dan untuk RotasiKanan() dan RotasiKiri() menjadi: public override void RotateKanan() Project Otak – http://otak.csharpindonesia.net 26
  • 27. CSH202 – Pemrograman Game Tetris Dengan C# { base.ResetElemen(); _elemen[1,0] = true; _elemen[2,0] = true; _elemen[2,1] = true; _elemen[3,1] = true; } public override void RotateKiri() { this.RotateKanan(); } 2.8 Klas BlokZTerbalik *Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right- click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah! Untuk klas ini, kita akan memiliki kode RotasiAtas() dan RotasiBawah() yang sama, RotasiKiri() dan RotasiKanan() pun sama. Pada saat dibentuk, BlokZTerbalik akan menghadap ke atas, oleh karenanya kode untuk Constructor dan RotasiAtas menjadi sama: public class BlokZTerbalik : dotTetrus.Blok { public BlokZTerbalik() : base() { this.RotateAtas(); } public override void RotateAtas() { base.ResetElemen(); _elemen[2,0] = true; _elemen[2,1] = true; _elemen[3,1] = true; _elemen[3,2] = true; } public override void RotateBawah() { this.RotateAtas(); } … Project Otak – http://otak.csharpindonesia.net 27
  • 28. CSH202 – Pemrograman Game Tetris Dengan C# Dan untuk RotateKanan() dan RotateKiri() menjadi: public override void RotateKanan() { base.ResetElemen(); _elemen[2,1] = true; _elemen[3,1] = true; _elemen[1,2] = true; _elemen[2,2] = true; } public override void RotateKiri() { this.RotateKanan(); } 2.9 Klas BlokLNormal *Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right- click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah! Pada saat dibentuk, BlokLNormal akan menghadap ke atas, oleh karenanya kode untuk Constructor dan RotasiAtas menjadi sama: public class BlokLNormal : dotTetrus.Blok { public BlokLNormal() : base() { this.RotateAtas(); } public override void RotateAtas() { base.ResetElemen(); Project Otak – http://otak.csharpindonesia.net 28
  • 29. CSH202 – Pemrograman Game Tetris Dengan C# _elemen[1,1] = true; _elemen[2,1] = true; _elemen[3,1] = true; _elemen[3,2] = true; } … Untuk RotateBawah() menjadi: public override void RotateBawah() { base.ResetElemen(); _elemen[1,1] = true; _elemen[1,2] = true; _elemen[2,2] = true; _elemen[3,2] = true; } Dan untuk RotateKanan() menjadi: public override void RotateKanan() { base.ResetElemen(); _elemen[2,1] = true; _elemen[2,2] = true; _elemen[2,3] = true; _elemen[3,1] = true; } Project Otak – http://otak.csharpindonesia.net 29
  • 30. CSH202 – Pemrograman Game Tetris Dengan C# Untuk RotateKiri() menjadi: public override void RotateKiri() { base.ResetElemen(); _elemen[2,3] = true; _elemen[3,1] = true; _elemen[3,2] = true; _elemen[3,3] = true; } 2.10 Klas BlokLTerbalik *Lakukan step yang sama untuk membuat template class BlokGaris sebelumnya (right- click dotTetrus Project → Add Class, dsb) sebelum membaca ke bawah! Pada saat dibentuk, BlokLTerbalik akan menghadap ke atas, oleh karenanya kode untuk Constructor dan RotasiAtas() menjadi sama: public class BlokLTerbalik : dotTetrus.Blok { public BlokLTerbalik() : base() { this.RotateAtas(); } public override void RotateAtas() { base.ResetElemen(); _elemen[1,2] = true; _elemen[2,2] = true; _elemen[3,2] = true; _elemen[3,1] = true; } Project Otak – http://otak.csharpindonesia.net 30
  • 31. CSH202 – Pemrograman Game Tetris Dengan C# Dan untuk RotateBawah() menjadi: public override void RotateBawah() { base.ResetElemen(); _elemen[1,1] = true; _elemen[2,1] = true; _elemen[3,1] = true; _elemen[1,2] = true; } Untuk RotateKanan() menjadi: public override void RotateKanan() { base.ResetElemen(); _elemen[3,1] = true; _elemen[3,2] = true; _elemen[3,3] = true; _elemen[2,1] = true; } Dan untuk RotateKiri() menjadi: Project Otak – http://otak.csharpindonesia.net 31
  • 32. CSH202 – Pemrograman Game Tetris Dengan C# public override void RotateKiri() { base.ResetElemen(); _elemen[2,1] = true; _elemen[2,2] = true; _elemen[2,3] = true; _elemen[3,3] = true; } Dan kita selesai untuk semua klas blok, kecuali Blok.Draw(). Tekan Ctrl – Shift – B dan pastikan tidak ada error sampai sejauh ini! Project Otak – http://otak.csharpindonesia.net 32
  • 33. CSH202 – Pemrograman Game Tetris Dengan C# 3. Papan Permainan Kira-kira apa saja yang perlu diketahui oleh Papan Permainan? 1. Posisi tinggi terkini. Bila tinggi ini dibawah grid 0, maka kita tahu bahwa game over. Grid 0 adalah grid paling atas. 2. Blok terkini yang sedang diturunkan. Kita juga harus me-respond command dari user (atas, bawah, kiri, kanan) pada saat blok terkini sedang diturunkan. 3. Harus bisa mengecek apakah ada baris yang bisa dihilangkan. 4. Harus tahu warna tiap-tiap grid, sehingga tidak salah mewarnai grid. UML untuk kelas PapanPermainan ialah: Tentunya ini belum complete. Masih ada yang harus kita tambahkan nantinya. Sekarang kita siapkan dulu klas PapanPermainan ini! Pertama, klik nama Form1 di Class View, dan lihat Properties nya. Ganti namanya menjadi PapanPermainan: Project Otak – http://otak.csharpindonesia.net 33
  • 34. CSH202 – Pemrograman Game Tetris Dengan C# Kemudian, klik nama Form1 di Solution Explorer, dan lihat Properties nya. Ganti filename nya menjadi PapanPermainan.cs Sekarang kita ke Windows Forms Designer (PapanPermainan.cs [Design] tab), dan ubah Properties nya: Properties Values BackColor Pilih Custom, lalu klik warna hitam. Text dotTetrus FormBorderStyle FixedSingle Size::Width 240 Size::Height 400 MaximizeBox False StartPosition CenterScreen Kemudian, klik menu View → Code. Sebelum kita mulai lebih lanjut, kita harus me- rename semua text Form1 menjadi PapanPermainan. Tekan tombol Ctrl – H: Isi seperti diatas dan klik Replace All. Project Otak – http://otak.csharpindonesia.net 34
  • 35. CSH202 – Pemrograman Game Tetris Dengan C# Sebelum mulai lebih lanjut, Build Solution (Ctrl – Shift – B) dan cek apakah ada build error. 3.1 Menambahkan fields Right-click PapanPermainan di Class View, pilih Add→Field. Isi seperti di atas, lalu klik Finish. Sekarang kita tahu lokasi di mana VS.Net menaruh variabel-variabel fields kita (paling bawah), oleh karenanya selanjutnya kita tidak usah menggunakan wizard, cukup menaruhnya di bagian bawah kode: public const int TINGGI = 20; public const int LEBAR = 12; // Variabel-variabel hidden private Blok _terkiniBlok; private int _terkiniTinggiTumpukan; private int[,] _elemen; Sekarang kita lompat ke konstruktor PapanPermainan(), dan tambahkan kode untuk initialize _elemen: public PapanPermainan() { // // Required for Windows Form Designer support // InitializeComponent(); // // TODO: Add any constructor code after InitializeComponent call // this._elemen = new int[TINGGI,LEBAR]; } Kenapa int? Karena kita harus menyimpan value warna untuk tiap elemen (ada 7 warna blok ditambah 1 warna background hitam). Project Otak – http://otak.csharpindonesia.net 35
  • 36. CSH202 – Pemrograman Game Tetris Dengan C# 3.2 Menambahkan methods Right-click PapanPermainan di Class View sekali lagi, kali ini pilih Add→Method: Isi seperti di atas dan klik Finish. Inilah kode untuk CekBaris(): private void CekBaris() { // 1. Cek berapa baris yg harus dihilangkan int jmlhBarisYgDitemukan = 0; bool selesai = false; for (int i = TINGGI-1; i >= _terkiniTinggiTumpukan && !selesai; i--) { // cek dari bawah ke atas for (int j = 0; j < LEBAR && !selesai; j++) { if (_elemen[i,j] == HITAM) selesai = true; } if (!selesai) ++jmlhBarisYgDitemukan; } if (jmlhBarisYgDitemukan == 0) return; // nggak perlu reDraw tumpukan // Kode untuk me-reDraw tumpukan … Nanti kita akan selesaikan kode dalam method ini. Untuk sekarang, kita hanya perlu berapa jumlah baris yang harus dihilangkan. Method ini mudah dimengerti, intinya kalau suatu baris semuanya tidak berwarna hitam, maka increment jumlah baris yang harus dihilangkan. Apakah konstan HITAM diatas sudah kita definisikan? Kalau begitu, waktunya menambahkan kode konstan warna di bagian fields: // Konstan-konstan warna public const int HITAM = 0; public const int MERAH = 1; public const int KUNING = 2; public const int HIJAU = 3; Project Otak – http://otak.csharpindonesia.net 36
  • 37. CSH202 – Pemrograman Game Tetris Dengan C# public const int BIRU = 4; public const int MAGENTA = 5; public const int CYAN = 6; public const int COKLAT = 7; dan menambahkan kode di konstruktor PapanPermainan(): this._elemen = new int[TINGGI,LEBAR]; for (int i = 0; i < TINGGI; i++) for (int j = 0; j < LEBAR; j++) _elemen[i,j] = HITAM; Lanjut ke method TurunkanBlok()! Sebelum berlanjut, kita tambahkan lagi satu konstan: public const int OFFSETPIXEL = 20; karena 1 grid = 20x20 pixels. 3.3 Koordinat Pixel dan Grid Unit Semua drawing yang akan dilakukan di atas windows forms kita harus menggunakan koordinat pixel. Akan tetapi, kita menyimpan data struktur _elemen PapanPermainan sebagai 20x12 integer array. Bagaimana mengkonversi dari unit pixel ke unit grid dan sebaliknya? Lihat gambar diatas. Koordinat default windows forms menggunakan (0,0) sebagai titik paling ujung kiri-atas. Mudah terlihat bahwa untuk mengubah koordinat (80,20) ke dalam grid unit menjadi [1,4] adalah [y / 20, x / 20]. Sekarang kita dapat melanjutkan menulis method TurunkanBlok: private void TurunkanBlok() { // 1. hitamkan baris bekas blok int grid_i = _terkiniBlok.KoordKiriAtas.Y / OFFSETPIXEL; int grid_j = _terkiniBlok.KoordKiriAtas.X / OFFSETPIXEL; for (int i = grid_i, j = grid_j; j < Blok.PANJANG; j++) { Project Otak – http://otak.csharpindonesia.net 37
  • 38. CSH202 – Pemrograman Game Tetris Dengan C# _elemen[i,j] = HITAM; } // 2. Turunkan blok 1 grid unit System.Drawing.Point koordLama = _terkiniBlok.KoordKiriAtas; _terkiniBlok.KoordKiriAtas.Y += OFFSETPIXEL; } Apa yang kita lakukan di method ini? Lihat gambar di bawah untuk jelasnya: Tentunya method ini belum complete karena saya belum memberitahukan bagaimana mewarnai papan permainan dan menampilkan blok. Untuk bab-bab selanjutnya, methods-methods PapanPermainan akan di-refine jadi pastikan tidak ada error dalam kode anda sekarang (tekan Ctrl – Shift – B). Project Otak – http://otak.csharpindonesia.net 38
  • 39. CSH202 – Pemrograman Game Tetris Dengan C# 4. Klas ImageBlok dan Menggambar di atas Canvas Ingat 20x20 pixel berwarna yang kita buat di Bab 0 sebelumnya? Convert mereka ke dalam file dengan format .GIF (Gunakan File → Save As) dan rename mereka menjadi Merah.gif, Kuning.gif, dst. Copy semua file *.gif ini ke dalam folder D:ProjectsdotNetdotTetrusbinDebug. Jika Anda tidak memiliki folder Debug, pastikan anda telah mem-Build Solution terlebih dahulu (Ctrl – Shift – B). 4.1 Klas ImageBlok Gunakan Class View untuk Add→Class: Isi data seperti di atas dan klik Finish. Di atas klas ini, kita tambahkan using statement: using System.Drawing; Lantas isi dengan konstan berikut: public class ImageBlok { public static Image MERAH; public static Image KUNING; public static Image HIJAU; public static Image BIRU; public static Image MAGENTA; public static Image CYAN; public static Image COKLAT; Project Otak – http://otak.csharpindonesia.net 39
  • 40. CSH202 – Pemrograman Game Tetris Dengan C# static ImageBlok() { MERAH = Image.FromFile("Merah.gif"); KUNING = Image.FromFile("Kuning.gif"); HIJAU = Image.FromFile("Hijau.gif"); BIRU = Image.FromFile("Biru.gif"); MAGENTA = Image.FromFile("Magenta.gif"); CYAN = Image.FromFile("Cyan.gif"); COKLAT = Image.FromFile("Coklat.gif"); } } Kita menggunakan static constructor – static ImageBlok() untuk meng-initialize variabel-variabel static kita. Perlu dicatat bahwa kita tidak dapat membuat variabel MERAH dsb sebagai const karena mereka tidak dapat di-init pada waktu kompilasi. Membuat mereka sebagai public memang menyalahi prinsip object-oriented programming, jadi memang seharusnya dibuat private dan menggunakan Properties. Hanya menurut saya untuk situasi ini terlihat overkill. Tergantung Anda seberapa jauh ingin menerapkan OOP dalam program Anda. Sekarang kita dapat mulai menggambar di atas window form kita! 4.2 Modifikasi Klas Blok Kita perlu me-modifikasi klas Blok kita agar tiap-tiap subclass Blok (BlokGaris, dsb) tahu dengan ImageBlok mana mereka harus menggambar. // Variabel-variable hidden protected bool[,] _elemen; protected Image _warnaBlok; Dan di tiap-tiap subclass, kita tentukan warnanya. Di klas BlokGaris, tambahkan kode ke konstruktor: public BlokGaris() : base() { _warnaBlok = ImageBlok.MERAH; Di klas BlokKotak: public BlokKotak() : base() { _warnaBlok = ImageBlok.KUNING; Di klas BlokKros: public BlokKros() : base() { _warnaBlok = ImageBlok.HIJAU; Di klas BlokZNormal: public BlokZNormal() : base() { _warnaBlok = ImageBlok.BIRU; Di klas BlokZTerbalik: public BlokZTerbalik() : base() { _warnaBlok = ImageBlok.MAGENTA; Project Otak – http://otak.csharpindonesia.net 40
  • 41. CSH202 – Pemrograman Game Tetris Dengan C# Di klas BlokLNormal: public BlokLNormal() : base() { _warnaBlok = ImageBlok.CYAN; Di klas BlokLTerbalik: public BlokLTerbalik() : base() { _warnaBlok = ImageBlok.COKLAT; 4.3 Definisi Draw() di Klas Blok Karena kita telah mendapatkan image untuk digunakan menggambar di atas winforms, sekarang kita definisikan method Draw() di Klas Blok sebagai berikut: public void Draw() { Graphics g = PapanPermainan.ActiveForm.CreateGraphics(); for (int i = 0; i < PANJANG; i++) for (int j = 0; j < LEBAR; j++) { if (_elemen[i,j] == true) g.DrawImage(_warnaBlok, new Rectangle( KoordKiriAtas.X + (j * PapanPermainan.OFFSETPIXEL), KoordKiriAtas.Y + (i * PapanPermainan.OFFSETPIXEL), PapanPermainan.OFFSETPIXEL, PapanPermainan.OFFSETPIXEL)); } g.Dispose(); } Baris pertama adalah “mengambil” kanvas dari PapanPermainan. Baris berikutnya, kita hanya menggambar warnaBlok jika data strukture _elemen kita dinyatakan true. Lihat Bab 0 lagi jika Anda lupa bagaimana kita menyimpan sebuah blok Tetris. Lihat definisi DrawImage di CD-ROM MSDN Library. Klik View → Navigation → Index dan ketik Graphics.DrawImage di field Look for, lalu dobel-klik Graphics.DrawImage method di result box. Project Otak – http://otak.csharpindonesia.net 41
  • 42. CSH202 – Pemrograman Game Tetris Dengan C# Di sini, saya menggunakan DrawImage dengan spesifikasi DrawImage(Image, Rectangle). Sedangkan spesifikasi Rectangle yang saya gunakan adalah Rectangle( int koordKiriAtas.X, int koordKiriAtas.Y, int lebar rectangle, int tinggi rectangle). Lihat definisi Rectangle structure di CD-ROM MSDN Library Anda. Yang menarik kenapa KoordKiriAtas.X ditambah dengan j, dan bukan i. Lihat Bab 2, bagian 2.c lagi untuk melihat bagaiman konversi dari pixel ke grid unit. Sudah tidak sabar melihat method Draw() beraksi? Mari kita test method ini! Anda harus ke Forms Designer, dan lakukan hal berikut di Properties Sheet: Insert kode berikut: private void PapanPermainan_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { BlokGaris b1 = new BlokGaris(); b1.KoordKiriAtas = new Point(0,0); b1.Draw(); BlokKros b2 = new BlokKros(); b2.KoordKiriAtas = new Point(80,0); b2.Draw(); BlokZNormal b3 = new BlokZNormal(); b3.KoordKiriAtas = new Point(160,0); b3.Draw(); } Tekan tombol Ctrl – Shift – B untuk Build Solution. Lalu tekan Ctrl – F5. Ketika Form PapanPermainan muncul, tekan tombol A. Hasilnya akan seperti ini: Project Otak – http://otak.csharpindonesia.net 42
  • 43. CSH202 – Pemrograman Game Tetris Dengan C# Jika sudah memastikan method Draw() bekerja, hapus kode test tadi dan lanjut ke bab berikutnya! Project Otak – http://otak.csharpindonesia.net 43
  • 44. CSH202 – Pemrograman Game Tetris Dengan C# 5. Mengaplikasikan Factory Pattern Jarang kita membuat program tanpa melihat-lihat buku patterns. Apakah penting? Tidak juga, tapi patterns berisi resep-resep membuat program yang telah dipakai berulang- ulang oleh para programmer veteran. Jadi mirip dengan mengimplementasikan fungsi sorting sendiri atau menggunakan standard library yang telah ada. Kita lihat apa yang dimaksud dengan Factory Pattern ini. 5.1 Klas BlokFactory dotTetrus harus menampilkan blok secara random, jadi jangan sampai user tahu bahwa setelah BlokBaris akan ada BlokKotak, dst. Kita bisa mengimplementasinya sbb: int i = angka random antara 1-7. switch (i) { case 1: _terkiniBlok = new BlokGaris(); break; case 2: _terkiniBlok = new BlokKotak(); break; ... } Tapi secara design, apakah tugas PapanPermainan membuat instance-instance BlokXXX? Kalau dilihat dalam real-life, sebuah pabrik (Factory) membuat berbagai macam komponen. Kita tinggal memesan komponen sesuai dengan yang kita inginkan, misalnya ban model offroad untuk dipasang di mobil kita. Jadi bukan mobil kita (Client) yang seharusnya membuat ban atau kaca. Mobil kita memang menggunakan komponen-komponen tersebut dan justru terdiri dari komponen-komponen tersebut, akan tetapi bukan berarti mobil kita lah yang bertugas membuat ban, dsb. Gunakan Class View untuk menciptakan klas baru: BlokFactory. Project Otak – http://otak.csharpindonesia.net 44
  • 45. CSH202 – Pemrograman Game Tetris Dengan C# Isi seperti diatas lalu klik Finish. *Perhatikan bahwa klas BlokFactory adalah Sealed class. Artinya klas ini tidak dapat di- inherit, dan memang semestinya begitu karena hanya ada satu macam BlokFactory. Dalam klas BlokFactory, hanya ada satu method, dan method ini static sehingga bisa dipanggil tanpa membuat sebuah instance BlokFactory terlebih dahulu: public static Blok BuatkanBlok(int spesifikasi) { Blok b = null; switch (spesifikasi) { case Blok.BARIS: b = new BlokGaris(); break; case Blok.KOTAK: b = new BlokKotak(); break; case Blok.KROS: b = new BlokKros(); break; case Blok.ZNORMAL: b = new BlokZNormal(); break; case Blok.ZTERBALIK: b = new BlokZTerbalik(); break; case Blok.LNORMAL: b = new BlokLNormal(); break; case Blok.LTERBALIK: b = new BlokLTerbalik(); break; } return b; Project Otak – http://otak.csharpindonesia.net 45
  • 46. CSH202 – Pemrograman Game Tetris Dengan C# } 5.2 Method BuatBlokBaru() untuk klas PapanPermainan PapanPermainan memerlukan satu method baru untuk “memesan” blok dari BlokFactory. Karena pembuatan blok baru ini harus dilakukan secara acak, tambahkan variabel Random ke dalam data privat PapanPermainan: // Variabel-variabel hidden ... private Random _random; Dan kita harus meng-init seed dari random generator di konstruktor PapanPermainan: public PapanPermainan() { ... // init random generator _random = new Random(); } Sekarang kita siap mengisi kode untuk BuatBlokBaru: private void BuatBlokBaru() { // antara 0-6 (termasuk 0 dan 6) int spesifikasi = _random.Next(0, 7); _terkiniBlok = BlokFactory.BuatkanBlok(spesifikasi); _terkiniBlok.KoordKiriAtas = new Point(100,0); // tengah atas // Hitamkan area sebelum menampilkan Blok baru Graphics g = this.CreateGraphics(); SolidBrush hitam = new SolidBrush(Color.Black); int i_max = _terkiniBlok.KoordKiriAtas.X + (Blok.PANJANG * OFFSETPIXEL); int j_max = _terkiniBlok.KoordKiriAtas.Y + (Blok.LEBAR * OFFSETPIXEL); for (int i = _terkiniBlok.KoordKiriAtas.X; i < i_max; i += OFFSETPIXEL) { for (int j = _terkiniBlok.KoordKiriAtas.Y; j < j_max; j += OFFSETPIXEL) { g.FillRectangle(hitam, i, j, OFFSETPIXEL, OFFSETPIXEL); } } // tampilkan blok baru _terkiniBlok.Draw(); // dispose setelah dipakai hitam.Dispose(); g.Dispose(); Project Otak – http://otak.csharpindonesia.net 46
  • 47. CSH202 – Pemrograman Game Tetris Dengan C# } Lihat definisi Graphics.FillRectangle() di MSDN Library. Di sini saya menggunakan FillRectangle(Brush warnaBrush, int koordKiriAtas.X, int koordKiriAtas.Y, int lebar rectangle, int tinggi rectangle) Untuk menge-test method baru ini, kita buatkan agar dotTetrus membuat blok baru tiap kali user mengetik huruf ‘M’ atau ‘m’: private void PapanPermainan_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { switch (e.KeyChar) { case 'M': goto case 'm'; case 'm': BuatBlokBaru(); break; } e.Handled = true; } Tekan tombol Ctrl – F5 untuk menampilkan dotTetrus, lalu tekan huruf ‘m’ di atas Papan Permainan. Project Otak – http://otak.csharpindonesia.net 47
  • 48. CSH202 – Pemrograman Game Tetris Dengan C# 6. Menggunakan Invalidate() Selama ini, kita menggambar blok di masing-masing method. Ini akan menimbulkan redundancy atau kode yang sama di beberapa method. Ada satu problem dengan approach kita selama ini. Coba jalankan aplikasi dotTetrus, tekan ‘m’ untuk memunculkan blok baru, lalu minimize dotTetrus. Sekarang kembalikan window dotTetrus. Apa yang terjadi? Papan permainan menjadi hitam semua. Tentunya kita bisa saja melakukan trap atas event Minimize, tapi ada cara yang lebih baik: menggunakan Event Paint. Pindah view ke PapanPermainan.cs [Design], lihat Properties, dan pilih tombol Events, lalu dobel-klik value Paint. Isi dengan kode berikut: private void PapanPermainan_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { Graphics g = e.Graphics; SolidBrush hitam = new SolidBrush(Color.Black); Image warnaBlok = null; for (int i = 0; i < TINGGI; i++) { for (int j = 0; j < LEBAR; j++) { switch (_elemen[i,j]) { case HITAM: g.FillRectangle( hitam, j * OFFSETPIXEL, i * OFFSETPIXEL, OFFSETPIXEL, Project Otak – http://otak.csharpindonesia.net 48
  • 49. CSH202 – Pemrograman Game Tetris Dengan C# OFFSETPIXEL); break; case MERAH: warnaBlok = ImageBlok.MERAH; break; case KUNING: warnaBlok = ImageBlok.KUNING; break; case HIJAU: warnaBlok = ImageBlok.HIJAU; break; case BIRU: warnaBlok = ImageBlok.BIRU; break; case MAGENTA: warnaBlok = ImageBlok.MAGENTA; break; case CYAN: warnaBlok = ImageBlok.CYAN; break; case COKLAT: warnaBlok = ImageBlok.COKLAT; break; } // end case if (_elemen[i,j] > HITAM) g.DrawImage(warnaBlok, j * OFFSETPIXEL, // x-coord i * OFFSETPIXEL, // y-coord OFFSETPIXEL, // lebar OFFSETPIXEL); // tinggi } // end for j } // end for i } // end _Paint() 6.1 Penambahan method SetElemen() dan GetElemen() Tambahkan method SetElemen() kepada PapanPermainan: public void SetElemen(int i, int j, int warna) { _element[i,j] = warna; } Dan juga GetElemen() pada PapanPermainan: public int GetElemen(int i, int j) { return _elemen[i,j]; } Method ini diperlukan karena kita akan me-modifikasi method Blok.Draw() Project Otak – http://otak.csharpindonesia.net 49
  • 50. CSH202 – Pemrograman Game Tetris Dengan C# 6.2 Modifikasi klas Blok Ubah tipe variabel _warnaBlok dari Image menjadi int. // Variabel-variable hidden protected bool[,] _elemen; // protected Image _warnaBlok; protected int _warnaBlok; Dan di tiap-tiap subclass, ubah variabel ini. Di klas BlokGaris: public BlokGaris() : base() { _warnaBlok = PapanPermainan.MERAH; Di klas BlokKotak: public BlokKotak() : base() { _warnaBlok = PapanPermainan.KUNING; Di klas BlokKros: public BlokKros() : base() { _warnaBlok = PapanPermainan.HIJAU; Di klas BlokZNormal: public BlokZNormal() : base() { _warnaBlok = PapanPermainan.BIRU; Di klas BlokZTerbalik: public BlokZTerbalik() : base() { _warnaBlok = PapanPermainan.MAGENTA; Di klas BlokLNormal: public BlokLNormal() : base() { _warnaBlok = PapanPermainan.CYAN; Di klas BlokLTerbalik: public BlokLTerbalik() : base() { _warnaBlok = PapanPermainan.COKLAT; Sekarang kita ubah method Blok.Draw() menjadi: public void Draw(PapanPermainan papan) { int offset_i = KoordKiriAtas.Y / PapanPermainan.OFFSETPIXEL; int offset_j = KoordKiriAtas.X / PapanPermainan.OFFSETPIXEL; for (int i = 0; i < PANJANG; i++) for (int j = 0; j < LEBAR; j++) { if (_elemen[i,j] == true) papan.SetElemen( offset_i + i, offset_j + j, _warnaBlok); Project Otak – http://otak.csharpindonesia.net 50
  • 51. CSH202 – Pemrograman Game Tetris Dengan C# } } *Perhatikan bahwa Blok.Draw() sekarang menerima sebuah parameter! 6.3 Modifikasi PapanPermainan.BuatBlokBaru() Sesuaikan kode-nya dengan berikut: private void BuatBlokBaru() { // antara 0-6 (termasuk 0 dan 6) int spesifikasi = _random.Next(0, 7); _terkiniBlok = BlokFactory.BuatkanBlok(spesifikasi); _terkiniBlok.KoordKiriAtas = new Point(100,0); // tengah atas int i_max = _terkiniBlok.KoordKiriAtas.X + (Blok.PANJANG * OFFSETPIXEL); int j_max = _terkiniBlok.KoordKiriAtas.Y + (Blok.LEBAR * OFFSETPIXEL); for (int i = _terkiniBlok.KoordKiriAtas.X; i < i_max; i += OFFSETPIXEL) { for (int j = _terkiniBlok.KoordKiriAtas.Y; j < j_max; j += OFFSETPIXEL) { _elemen[j/OFFSETPIXEL, i/OFFSETPIXEL] = HITAM; } } // tampilkan blok baru _terkiniBlok.Draw(this); // panggil Invalidate Size s = new Size(Blok.PANJANG * OFFSETPIXEL, Blok.LEBAR * OFFSETPIXEL); this.Invalidate(new Rectangle(_terkiniBlok.KoordKiriAtas, s)); } Tekan tombol Ctrl – Shift – B, diikuti dengan Ctrl – F5 untuk menjalankan dotTetrus. Tekan tombol M, lalu minimize window, dan restore. Seharusnya ketika di restore, blok Tetris akan muncul kembali. Jika tidak, cek kode Anda! 6.4 Sekilas tentang Invalidate() Bagi yang belum pernah membuat program dengan bahasa pemrograman C (Win32 API) atau dengan MFC Visual C++, akan saya jelaskan apa yang dilakukan dengan memanggil Invalidate(). Project Otak – http://otak.csharpindonesia.net 51
  • 52. CSH202 – Pemrograman Game Tetris Dengan C# Dengan memanggil Invalidate(), kita menyalakan event PAINT. Event Paint ini menyala setiap kali window harus di re-draw ulang. Contohnya, ketika di maximize, restore setelah minimize, restore setelah ditutupi window lain diatasnya. Dalam kata lain, kita memaksa program untuk menjalankan kode yang meng-handle event Paint ini. Kode yang meng-handle event Paint dalam dotTetrus adalah: private void PapanPermainan_Paint(object sender, System.Windows.Forms.PaintEventArgs e) Lantas kenapa memanggil Invalidate() dengan argumen Rectangle dan Size? Lihat bagan di bawah ini: Jadi kalau kita memanggil Invalidate() tanpa argumen, maka kita memaksa program untuk me-redraw seluruh windows forms kita, dari koord (0,0) sampai (240,400)! Ini tentunya lebih lama daripada hanya me-redraw sebagian area saja. Memang kode PapanPermainan_Paint kita sebenarnya mengecek tiap grid dan menggambar blok yang sesuai. Tapi ada hal yang magic: Windows tidak akan me- redraw sesuatu diluar area yang diminta! Lihat bagan diatas sekali lagi. Bila Invalidate() dipanggil dengan argumen r, maka kode seperti: g.DrawImage(image, 100,100, 20,20); tidak akan dijalankan karena berada di luar area r (lihat kotak merah). Ada baiknya sekarang Anda membuka MSDN library, dan membaca tentang Control.Invalidate method (System.Windows.Forms). Satu hal lagi, saya bisa menulis kode Invalidate() di BlokBaru() dengan gaya seperti kode-kode sebelumnya: this.Invalidate(new Rectangle( _terkiniBlok.KoordKiriAtas.X, _terkiniBlok.KoordKiriAtas.Y, Blok.PANJANG * OFFSETPIXEL, Blok.LEBAR * OFFSETPIXEL)); Project Otak – http://otak.csharpindonesia.net 52
  • 53. CSH202 – Pemrograman Game Tetris Dengan C# Tapi ada konstruktor Rectangle() yang menerima argumen Point dan Size. Dan saya melihatnya lebih elegan dari kode diatas. Tergantung Anda mau menggunakan style yang mana. Dan lebih penting lagi, jika ada konstruktor atau method yang belum terlihat sebelumnya, lihat di MSDN Library dan periksa argumen-argumen apa saja yang bisa diterima oleh konstruktor dan method tersebut. Project Otak – http://otak.csharpindonesia.net 53
  • 54. CSH202 – Pemrograman Game Tetris Dengan C# 7. Merespons Keyboard Event Pada bab ini saya akan fokus koding untuk merespons tombol Bawah, Kiri, Kanan. Sebelumnya, kita tambahkan satu lagi method ke klas Blok, yaitu HapusDariPapan(): public void HapusDariPapan(PapanPermainan papan) { int offset_i = KoordKiriAtas.Y / PapanPermainan.OFFSETPIXEL; int offset_j = KoordKiriAtas.X / PapanPermainan.OFFSETPIXEL; for (int i = 0; i < PANJANG; i++) for (int j = 0; j < LEBAR; j++) { if (_elemen[i,j] == true) papan.SetElemen( offset_i + i, offset_j + j, PapanPermainan.HITAM); } } Kode Blok.HapusDariPapan() adalah kebalikan dari kode Blok.Draw(), dan ini digunakan untuk me-reset papan sebelum menggeser blok ke bawah, kiri atau kanan. Kemudian, kita buat method untuk meng-handle event KeyDown, yaitu event yang akan menyala ketika user memencet suatu tombol di keyboard. Pindah ke Properties Sheet untuk PapanPermainan.cs [Design] dan ikuti bagan berikut: Project Otak – http://otak.csharpindonesia.net 54
  • 55. CSH202 – Pemrograman Game Tetris Dengan C# 7.1 Merespons key Bawah Untuk merespons tombol arrow Bawah, kode yang akan digunakan adalah method TurunkanBlok(). Pertama, tambahkan kode berikut ke dalam KeyDown-handler kita: private void PapanPermainan_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { switch (e.KeyCode) { case Keys.Down: TurunkanBlok(); break; } } Dan method TurunkanBlok kita modifikasi seperti berikut: private void TurunkanBlok() { // 1. Hapus bekas blok _terkiniBlok.HapusDariPapan(this); // 2. Turunkan blok 1 grid unit System.Drawing.Point koordLama = _terkiniBlok.KoordKiriAtas; _terkiniBlok.KoordKiriAtas.Y += OFFSETPIXEL; // 3. ReDraw Blok _terkiniBlok.Draw(this); Size s = new Size( (Blok.PANJANG * OFFSETPIXEL), (Blok.LEBAR * OFFSETPIXEL) + OFFSETPIXEL); this.Invalidate(new Rectangle(koordLama, s)); } Project Otak – http://otak.csharpindonesia.net 55
  • 56. CSH202 – Pemrograman Game Tetris Dengan C# 7.2 Merespons key Kiri Kita buatkan method baru GeserKiriBlok() ke dalam klas PapanPermainan: private void GeserKiriBlok() { // 1. Hapus bekas blok _terkiniBlok.HapusDariPapan(this); // 2. Geser kiri blok 1 grid unit _terkiniBlok.KoordKiriAtas.X -= OFFSETPIXEL; // 3. ReDraw Blok _terkiniBlok.Draw(this); Size s = new Size( (Blok.PANJANG * OFFSETPIXEL) + OFFSETPIXEL, (Blok.LEBAR * OFFSETPIXEL) ); this.Invalidate(new Rectangle(_terkiniBlok.KoordKiriAtas, s)); } Dan tambahkan kode di KeyDown-handler: private void PapanPermainan_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { switch (e.KeyCode) { ... case Keys.Left: GeserKiriBlok(); break; 7.3 Merespons Key Kanan Kita buatkan method baru GeserKananBlok() ke dalam klas PapanPermainan: private void GeserKananBlok() { // 1. Hapus bekas blok _terkiniBlok.HapusDariPapan(this); // 2. Geser kanan blok 1 grid unit System.Drawing.Point koordLama = _terkiniBlok.KoordKiriAtas; Project Otak – http://otak.csharpindonesia.net 56
  • 57. CSH202 – Pemrograman Game Tetris Dengan C# _terkiniBlok.KoordKiriAtas.X += OFFSETPIXEL; // 3. ReDraw Blok _terkiniBlok.Draw(this); Size s = new Size( (Blok.PANJANG * OFFSETPIXEL) + OFFSETPIXEL, (Blok.LEBAR * OFFSETPIXEL) ); this.Invalidate(new Rectangle(koordLama, s)); } Dan tambahkan kode di KeyDown-handler: private void PapanPermainan_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { switch (e.KeyCode) { ... case Keys.Right: GeserKananBlok(); break; } } Sekarang, Build Solution, dan jalankan dotTetrus. Tekan ‘m’ untuk memunculkan blok baru, lalu gerakkan ke bawah, kiri, kanan. Project Otak – http://otak.csharpindonesia.net 57
  • 58. CSH202 – Pemrograman Game Tetris Dengan C# 8. Menumpuk Blok Sampai sekarang sudah banyak kemajuan di program dotTetrus kita; memunculkan blok baru secara random, menggeser kiri, menggeser kanan, dan menggeser ke bawah. Akan tetapi, satu hal masih mengganjal. Kita belum dapat membuat tumpukan satu blok di atas blok yang lain. Sekarang kita akan menangani masalah tersebut. Sebelum kita mulai, ada satu bug yang harus ditangani. Client Area kita (kanvas tempat kita menggambar blok Tetris) ternyata tidak memiliki panjang 240 pixel dan tinggi 400 pixel. Coba lihat kode InitializeComponent() di klas PapanPermainan: this.ClientSize = new System.Drawing.Size(234, 369); Ganti kode ini menjadi: this.ClientSize = new System.Drawing.Size(240, 400); 8.1 Modifikasi Klas Blok Ternyata kita harus menambahkan satu method baru di klas Blok, yaitu GetElemen(), karena kita perlu membandingkan elemen di Blok dan elemen di PapanPermainan. Tambahkan method ini di klas Blok: public bool GetElemen(int i, int j) { return _elemen[i,j]; } 8.2 Mengkontrol Penurunan Blok Tambahkan kode berikut di klas PapanPermainan: private bool BisaDiturunkan() { // simulasi penurunan Point koordBaru = new Point( _terkiniBlok.KoordKiriAtas.X, _terkiniBlok.KoordKiriAtas.Y + OFFSETPIXEL); int offset_i = koordBaru.Y / OFFSETPIXEL; int offset_j = koordBaru.X / OFFSETPIXEL; // cari elemen terbawah dari blok int barisTerbawah = Blok.LEBAR - 1; bool found = false; for (int i = barisTerbawah; i >= 0 && !found; i--) { Project Otak – http://otak.csharpindonesia.net 58
  • 59. CSH202 – Pemrograman Game Tetris Dengan C# for (int j = 0; j < Blok.PANJANG && !found; j++) { if ( _terkiniBlok.GetElemen(i,j) == true ) found = true; } if (!found) --barisTerbawah; } for (int j = 0; j < Blok.PANJANG; j++) { // case 1: menyentuh lantai papan if ( _terkiniBlok.GetElemen(barisTerbawah,j) == true && offset_i + barisTerbawah >= PapanPermainan.TINGGI ) return false; // case 2: menyentuh blok lain di bawahnya if ( _terkiniBlok.GetElemen(barisTerbawah,j) == true && _elemen[offset_i + barisTerbawah, offset_j + j] > HITAM) { return false; } } // tidak menyentuh apa-apa return true; } Dan modifikasi KeyDown-handler kita: private void PapanPermainan_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { switch (e.KeyCode) { case Keys.Down: if ( BisaDiturunkan() ) TurunkanBlok(); break; ... Build Solution dan jalankan dotTetrus untuk memastikan kode ini bekerja dengan benar! 8.3 Mengkontrol Penggeseran Kiri Tidak hanya menurunkan blok, kita pun harus memastikan bahwa ketika menggeser ke kiri dan ke kanan, blok tidak akan keluar dari papan permainan. Prinsipnya sama dengan kode BisaDiturunkan(), hanya untuk mengkontrol penggeseran ke kiri, kita musti mencari elemen terkiri blok. private bool BisaDigeserKiri() { // simulasi geser kiri Point koordBaru = new Point( _terkiniBlok.KoordKiriAtas.X - OFFSETPIXEL, _terkiniBlok.KoordKiriAtas.Y); Project Otak – http://otak.csharpindonesia.net 59
  • 60. CSH202 – Pemrograman Game Tetris Dengan C# int offset_i = koordBaru.Y / OFFSETPIXEL; int offset_j = koordBaru.X / OFFSETPIXEL; // cari elemen terkiri dari blok int kolomTerkiri = 0; bool found = false; for (int i = kolomTerkiri; i < Blok.PANJANG && !found; i++) { for (int j = 0; j < Blok.LEBAR && !found; j++) { // hati-hati (j,i) BUKAN (i,j)! if ( _terkiniBlok.GetElemen(j,i) == true ) found = true; } if (!found) ++kolomTerkiri; } for (int i = 0; i < Blok.PANJANG; i++) { // case 1: menyentuh pinggir kiri papan if ( _terkiniBlok.GetElemen(i,kolomTerkiri) == true && (offset_j + kolomTerkiri) < 0 ) return false; // case 2: menyentuh blok lain di sebelah kiri if ( _terkiniBlok.GetElemen(i,kolomTerkiri) == true && _elemen[offset_i + i, offset_j + kolomTerkiri] > HITAM) { return false; } } // tidak menyentuh apa-apa return true; } Dan modifikasi KeyDown-handler PapanPermainan: private void PapanPermainan_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { switch (e.KeyCode) { ... case Keys.Left: if ( BisaDigeserKiri() ) GeserKiriBlok(); break; … Mungkin untuk kode kali ini agak susah dicerna. Saya akan coba terangkan secara visual: Project Otak – http://otak.csharpindonesia.net 60
  • 61. CSH202 – Pemrograman Game Tetris Dengan C# Andaikan blok di bagan atas digeser ke kiri, maka: koordBaru = ( -20, 20 ) offset_j = -20 / 20 = -1 offset_j + kolomTerkiri = -1 + 0 = -1 ( < 0 ! tidak bisa digeser lagi ) 8.4 Mengkontrol Penggeseran Kanan Kode ini akan lebih kurang sama dengan BisaDigeserKiri(), hanya kita harus mencari kolom terkanan: private bool BisaDigeserKanan() { // simulasi geser kanan Point koordBaru = new Point( _terkiniBlok.KoordKiriAtas.X + OFFSETPIXEL, _terkiniBlok.KoordKiriAtas.Y); int offset_i = koordBaru.Y / OFFSETPIXEL; int offset_j = koordBaru.X / OFFSETPIXEL; // cari elemen terkiri dari blok int kolomTerkanan = Blok.PANJANG - 1; bool found = false; for (int i = kolomTerkanan; i >= 0 && !found; i--) { for (int j = 0; j < Blok.LEBAR && !found; j++) { // hati-hati (j,i) BUKAN (i,j)! if ( _terkiniBlok.GetElemen(j,i) == true ) found = true; } if (!found) --kolomTerkanan; } for (int i = 0; i < Blok.PANJANG; i++) { // case 1: menyentuh pinggir kanan papan if ( _terkiniBlok.GetElemen(i,kolomTerkanan) == true Project Otak – http://otak.csharpindonesia.net 61
  • 62. CSH202 – Pemrograman Game Tetris Dengan C# && (offset_j + kolomTerkanan) >= PapanPermainan.LEBAR ) return false; // case 2: menyentuh blok lain di sebelah kanan if ( _terkiniBlok.GetElemen(i,kolomTerkanan) == true && _elemen[offset_i + i, offset_j + kolomTerkanan] > HITAM) { return false; } } // tidak menyentuh apa-apa return true; } Dan modifikasi KeyDown-handler kita: private void PapanPermainan_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { switch (e.KeyCode) { ... case Keys.Right: if ( BisaDigeserKanan() ) GeserKananBlok(); break; } Sekali lagi, saya coba jelaskan secara visual: Andaikan blok di bagan atas digeser ke kanan, maka: koordBaru = ( 180, 20 ) offset_j = 180 / 20 = 9 offset_j + kolomTerkanan = 9 + 3 = 12 ( >= 12 ! tidak bisa digeser lagi ) Project Otak – http://otak.csharpindonesia.net 62
  • 63. CSH202 – Pemrograman Game Tetris Dengan C# 9. Merotasikan Blok Kita sudah dapat menurunkan blok, geser kiri dan geser kanan. Yang kurang hanyalah merotasikan blok ke atas, bawah, kiri dan kanan. 9.1 Menambahkan ICloneable ke klas Blok Tambahkan ICloneable interface ke deklarasi klas Blok: public class Blok : ICloneable *Ketika selesai mengetik ICloneable, VS.Net akan menyarankan memencet tombol Tab untuk men-generate semua methods ICloneable secara otomatis. Tekan Tab dan biarkan VS.Net melakukkanya. Scroll ke bawah sekali, cari method Clone(). Mungkin VS.Net akan menyembunyikannya di bawah region ICloneable Members: Klik tanda ‘+’ pada ICloneable Members maka sekarang Anda akan melihat method Klon(). Jika method ini disembunyikan isinya, klik tanda ‘+’ untuk melihat isinya. Isi method Klon dengan kode berikut: public object Clone() { Blok b = null; // buat sesuai subklas if (this is BlokGaris) b = new BlokGaris(); else if (this is BlokKotak) b = new BlokKotak(); else if (this is BlokKros) b = new BlokKros(); else if (this is BlokZNormal) b = new BlokZNormal(); else if (this is BlokZTerbalik) b = new BlokZTerbalik(); else if (this is BlokLNormal) b = new BlokLNormal(); else if (this is BlokLTerbalik) b = new BlokLTerbalik(); // copy koord dan warnablok Project Otak – http://otak.csharpindonesia.net 63
  • 64. CSH202 – Pemrograman Game Tetris Dengan C# b.KoordKiriAtas = this.KoordKiriAtas; b._warnaBlok = this._warnaBlok; // copy elemen for (int i = 0; i < LEBAR; i++) for (int j = 0; j < PANJANG; j++) b._elemen[i,j] = this._elemen[i,j]; return b; } Sebaiknya kode untuk membuat blok jangan dimasukkan ke dalam if-then-else. Ingat tugas membuat blok adalah urusan BlokFactory. Kode yang baik memang sebaiknya // buat sesuai subklas b = BlokFactory.BuatkanBlok(spesifikasi); Akan tetapi ini berarti menambahkan satu variabel baru semacam kodeBlok atau spesifikasi dan melakukan perubahan di tiap konstruktor subclass kita. Saya hanya melakukannya seperti ini untuk mengingatkan bahwa potensi bad-coding semakin besar ketika deadline semakin dekat dan program hampir selesai :P OK, kenapa kita membuat klas Blok mengimplementasi ICloneable interface? Ini karena semua method Rotasi (RotateAtas, RotateBawah, dsb) mengubah value Blok._elemen. Sedangkan kita ingin dapat mengecek apakah rotasi bisa dilakukan seperti halnya kita mengecek apakah blok bisa digeser kiri. Oleh karena itu kita harus bekerja dengan sebuah copy dari blok terkini. 9.2 Method BisaRotasi() untuk klas PapanPermainan Inilah kode BisaRotasi() yang fungsinya sama seperti BisaDigeserKiri, BisaDigeserKanan dan BisaDiturunkan, yaitu untuk mengecek apakah sebuah rotasi bisa dilakukan: private bool BisaRotasi(char key) { // clone blok terkini Blok b = (Blok) _terkiniBlok.Clone(); // rotasi sesuai keypress switch (key) { case 'w': b.RotateAtas(); break; case 'a': b.RotateKiri(); break; case 's': b.RotateBawah(); break; case 'd': b.RotateKanan(); break; Project Otak – http://otak.csharpindonesia.net 64
  • 65. CSH202 – Pemrograman Game Tetris Dengan C# } // cek apakah hasil rotasi menutupi blok lain int offset_i = b.KoordKiriAtas.Y / OFFSETPIXEL; int offset_j = b.KoordKiriAtas.X / OFFSETPIXEL; for (int i = 0; i < Blok.LEBAR; i++) for (int j = 0; j < Blok.PANJANG; j++) if ( offset_j + j >= 0 && offset_j + j <= PapanPermainan.LEBAR - 1 && offset_i + i >= 0 && offset_i + i <= PapanPermainan.TINGGI - 1 && b.GetElemen(i,j) == true && _terkiniBlok.GetElemen(i,j) == false && _elemen[offset_i + i, offset_j + j] > HITAM ) { return false; } // hasil rotasi tidak menutupi blok lain return true; } Tentunya kode yang harus Anda konsentrasi adalah kode di blok if… Kode ini: offset_j + j >= 0 && offset_j + j <= PapanPermainan.LEBAR - 1 && offset_i + i >= 0 && offset_i + i <= PapanPermainan.TINGGI - 1 && Memaksa rotasi hanya dilakukan di dalam client area atau di dalam papan permainan atau di dalam area (0,0) → (240,400). Kode ini: b.GetElemen(i,j) == true && _terkiniBlok.GetElemen(i,j) == false && Hanya mengecek area baru yang dihasilkan oleh rotasi. Lihat blok dibawah ini: Project Otak – http://otak.csharpindonesia.net 65
  • 66. CSH202 – Pemrograman Game Tetris Dengan C# Setelah di RotateKanan() akan menghasilkan: Area merah adalah area yang berbeda dari sebelum rotasi. Area inilah yang harus dicek apakah menyentuh blok lain atau keluar dari papan permainan. Sedangkan kode ini: _elemen[offset_i + i, offset_j + j] > HITAM ) mengecek apakah area baru yang dihasilkan rotasi bersentuhan dengan blok lain. Karena jika ada blok lain, maka value _elemen di papan permainan adalah MERAH, KUNING, dsb. 9.3 Modifikasi KeyPress-handler Kenapa KeyPress dan bukan KeyDown-handler yang dimodifikasi? Secara general, gunakan aturan ini: Character key seperti ‘a’, ‘b’, ‘c’, dsb di-handle di Keypress event. Sedangkan non- character key seperti ArrowAtas, ArrowBawah, F1, dsb di-handle di Keydown event. Pula, kita memerlukan sebuah char sebagai argumen untuk method BisaRotasi(). Karena kodenya lumayan panjang, saya paparkan semua isi method Keypress-handler: private void PapanPermainan_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { switch (e.KeyChar) { case 'M': goto case 'm'; case 'm': BuatBlokBaru(); break; Project Otak – http://otak.csharpindonesia.net 66
  • 67. CSH202 – Pemrograman Game Tetris Dengan C# } if (e.KeyChar == 'w' || e.KeyChar == 'a' || e.KeyChar == 's' || e.KeyChar == 'd') { // cek apakah bisa dirotasi if ( !BisaRotasi(e.KeyChar) ) { e.Handled = true; return; // tidak bisa rotasi } // sampai sini berarti bisa dirotasi _terkiniBlok.HapusDariPapan(this); switch (e.KeyChar) { case 'w': _terkiniBlok.RotateAtas(); break; case 'a': _terkiniBlok.RotateKiri(); break; case 's': _terkiniBlok.RotateBawah(); break; case 'd': _terkiniBlok.RotateKanan(); break; } _terkiniBlok.Draw(this); Size s = new Size( Blok.PANJANG * OFFSETPIXEL, Blok.LEBAR * OFFSETPIXEL ); this.Invalidate(new Rectangle( _terkiniBlok.KoordKiriAtas, s)); } // end if key rotasi e.Handled = true; } Sekarang Build Solution dan tes dotTetrus untuk memastikan semua kode Rotasi bekerja! Project Otak – http://otak.csharpindonesia.net 67
  • 68. CSH202 – Pemrograman Game Tetris Dengan C# 10. Menghilangkan Baris Komplet *** BUG *** Sebelum Anda melanjutkan, saya baru saja menemukan bug pada method Blok.Draw(). Cara menampilkan bug tersebut: Modify method PapanPermainan.BuatBlokBaru(): private void BuatBlokBaru() { // antara 0-6 (termasuk 0 dan 6) int spesifikasi = _random.Next(0, 7); //_terkiniBlok = BlokFactory.BuatkanBlok(spesifikasi); _terkiniBlok = BlokFactory.BuatkanBlok(6); Build Solution Geser blok ke kanan sampai pol / tidak bisa digeser lagi. Rotasi blok dengan tombol ‘a’ Dapat dilihat bahwa error ini disebabkan oleh: index yang diluar range Project Otak – http://otak.csharpindonesia.net 68
  • 69. CSH202 – Pemrograman Game Tetris Dengan C# yg menyebabkan error adalah call PapanPermainan.SetElemen() yg berada di method Blok.Draw() Modify PapanPermainan.SetElemen() menjadi: public void SetElemen(int i, int j, int warna) { if (i >= 0 && i < TINGGI && j >= 0 && j < LEBAR) _elemen[i,j] = warna; } *** Saya menulis e-book ini sembari menulis kode. Jadi memang tidak ada working program sebelum menulis. Akibatnya bugs baru muncul setelah beberapa bab. Mohon maaf kalau ada bugs-bugs yang lain :P Pastikan Anda me-reset method BuatBlokBaru() sebelum melanjuti: private void BuatBlokBaru() { // antara 0-6 (termasuk 0 dan 6) int spesifikasi = _random.Next(0, 7); _terkiniBlok = BlokFactory.BuatkanBlok(spesifikasi); // untuk debug //_terkiniBlok = BlokFactory.BuatkanBlok(6); Project Otak – http://otak.csharpindonesia.net 69
  • 70. CSH202 – Pemrograman Game Tetris Dengan C# 10.1 Menampilkan “Blink” effect Sebelum menghilangkan baris-baris Tetris yang komplet, saya ingin menampilkan visual cue (petunjuk visual) bahwa memang baris-baris tersebut komplet. Idenya simple sekali: hitamkan baris sleep() untuk bbrp millisecond kembalikan baris ke warna asal Dan untuk lebih kelihatan, saya sengaja mem-blink nya dua kali. Ide yang simple ini ternyata membutuhkan kode yang lumayan kompleks. Pertama tambahkan deklarasi using ini diatas file PapanPermainan.cs using System; ... using System.Threading; Kita perlu bekerja dengan Thread sekarang. Karena ketika kita mem-blink baris, kita tidak ingin Paint-handler kita ikut berhenti. Kedua, buat method baru CekTumpukan() di klas PapanPermainan: private void CekTumpukan() { if (this._terkiniTinggiTumpukan >= PapanPermainan.TINGGI) return; // lantai masih kosong // mulai dari bawah int barisYgDicek = PapanPermainan.TINGGI - 1; int[] barisKomplet = new int[20]; int jmlhBarisKomplet = 0; bool found; do { found = false; for (int j = 0; j < PapanPermainan.LEBAR && !found; j++) { if ( _elemen[barisYgDicek,j] == HITAM ) found = true; } if (!found) { barisKomplet[jmlhBarisKomplet++] = barisYgDicek; } --barisYgDicek; } while (barisYgDicek >= this._terkiniTinggiTumpukan); if (jmlhBarisKomplet == 0) return; Project Otak – http://otak.csharpindonesia.net 70
  • 71. CSH202 – Pemrograman Game Tetris Dengan C# // hitamkan sebentar untuk memunculkan // "BLINK" effect Graphics g = this.CreateGraphics(); SolidBrush brushHitam = new SolidBrush(Color.Black); // blink effect! for (int jmlhBlink = 0; jmlhBlink < 2; jmlhBlink++) { Thread.Sleep(100); for (int baris = 0; baris < jmlhBarisKomplet; baris++) { int barisBlink = barisKomplet[baris]; // hitamkan baris ini for (int i = 0; i < TINGGI; i++) { g.FillRectangle(brushHitam, i * OFFSETPIXEL, barisBlink * OFFSETPIXEL, OFFSETPIXEL, OFFSETPIXEL); } } // tunggu 100ms Thread.Sleep(100); // Restore kembali for (int baris = 0; baris < jmlhBarisKomplet; baris++) { int barisBlink = barisKomplet[baris]; // kembalikan warna semula for (int j = 0; j < LEBAR; j++) DrawElemen(barisBlink, j, g); } } brushHitam.Dispose(); g.Dispose(); // delete baris2 komplet int tinggiLama = this._terkiniTinggiTumpukan; for (int i = jmlhBarisKomplet - 1; i >= 0; i--) { int barisDel = barisKomplet[i]; // turunkan baris diatas barisDel for (int baris = barisDel; baris >= this._terkiniTinggiTumpukan; baris--) { for (int j = 0; j < LEBAR; j++) { _elemen[baris,j] = _elemen[baris-1,j]; } } } Project Otak – http://otak.csharpindonesia.net 71
  • 72. CSH202 – Pemrograman Game Tetris Dengan C# // update tinggi tumpukan this.UpdateTerkiniTinggiTumpukan(); // reDraw Point koord = new Point(0, tinggiLama * OFFSETPIXEL); Size s = new Size(LEBAR * OFFSETPIXEL, (TINGGI - tinggiLama) * OFFSETPIXEL); this.Invalidate(new Rectangle(koord, s)); } Dan juga tambahkan method DrawElemen() di kelas PapanPermainan: private void DrawElemen(int i, int j, Graphics g) { Image warnaBlok = null; switch ( _elemen[i,j] ) { case MERAH: warnaBlok = ImageBlok.MERAH; break; case KUNING: warnaBlok = ImageBlok.KUNING; break; case HIJAU: warnaBlok = ImageBlok.HIJAU; break; case BIRU: warnaBlok = ImageBlok.BIRU; break; case MAGENTA: warnaBlok = ImageBlok.MAGENTA; break; case CYAN: warnaBlok = ImageBlok.CYAN; break; case COKLAT: warnaBlok = ImageBlok.COKLAT; break; } // end case g.DrawImage(warnaBlok, j * OFFSETPIXEL, i * OFFSETPIXEL, OFFSETPIXEL, OFFSETPIXEL); } Project Otak – http://otak.csharpindonesia.net 72
  • 73. CSH202 – Pemrograman Game Tetris Dengan C# Sekarang, kita harus memanggil CekTumpukan setelah menurunkan Blok: private void TurunkanBlok() { ... this.Invalidate(new Rectangle(koordLama, s)); // update terkiniTinggi this.UpdateTerkiniTinggiTumpukan(); // cek tumpukan Thread t = new Thread(new ThreadStart(CekTumpukan)); t.Start(); Ah, kita juga harus meng-update _terkiniTinggiTumpukan dengan method: private void UpdateTerkiniTinggiTumpukan() { // misi kita adalah mencari satu baris yang // berisi HITAM semua // mulai dari bawah int barisYgDicek = PapanPermainan.TINGGI - 1; bool found; do { found = true; for (int j = 0; j < PapanPermainan.LEBAR && found; j++) { if ( _elemen[barisYgDicek,j] > HITAM ) found = false; } if (!found) --barisYgDicek; } while (barisYgDicek >= 0 && !found); // terkiniTinggiTumpukan sekarang berada // di bawah garis yg berisi HITAM semua this._terkiniTinggiTumpukan = barisYgDicek + 1; } Lihat bagan di awal Bab 2 untuk mengingat apa fungsi _terkiniTinggiTumpukan. Anda bisa mem-Build Solution dan lihat hasilnya. Project Otak – http://otak.csharpindonesia.net 73
  • 74. CSH202 – Pemrograman Game Tetris Dengan C# 11. Menggunakan Timer Selama ini kita harus menekan tombol ‘m’ untuk membuat blok baru. Selazimnya, seperti game Tetris yang kita mainkan, blok baru akan muncul setelah blok kita menyentuh lantai atau berada di atas blok lain. Kita akan menggunakan Timer untuk menurunkan blok setiap 1 detik. Ketika blok tidak bisa lagi diturunkan, maka itulah saatnya untuk meng-update _terkiniTinggiTumpukan, memanggil CekTumpukan(), dan membuat blok baru. 11.1 Menambahkan Timer Klik View→Toolbox dan drag-n-drop sebuah Timer komponen ke atas form Papan Permainan: Pindah ke Properties Sheet untuk Timer. Ganti fields berikut: Field Value Name _timer Interval 1000 Enabled False Kemudian kita buat kode Tick-handler nya, yaitu event yang akan menyala setiap kali interval telah terlewati: Project Otak – http://otak.csharpindonesia.net 74
  • 75. CSH202 – Pemrograman Game Tetris Dengan C# private void _timer_Tick(object sender, System.EventArgs e) { // pertama kali if ( _terkiniBlok == null ) BuatBlokBaru(); if ( BisaDiturunkan() ) TurunkanBlok(); else { // update terkini tinggi this.UpdateTerkiniTinggiTumpukan(); // blink dan hilangkan baris komplet Thread t = new Thread(new ThreadStart(CekTumpukan)); t.Start(); // buat blok baru BuatBlokBaru(); } } Dan kita harus memodifikasi kode TurunkanBlok: private void TurunkanBlok() { // 1. Hapus bekas blok _terkiniBlok.HapusDariPapan(this); // 2. Turunkan blok 1 grid unit System.Drawing.Point koordLama = _terkiniBlok.KoordKiriAtas; _terkiniBlok.KoordKiriAtas.Y += OFFSETPIXEL; // 3. ReDraw Blok _terkiniBlok.Draw(this); Size s = new Size( (Blok.PANJANG * OFFSETPIXEL), (Blok.LEBAR * OFFSETPIXEL) + OFFSETPIXEL); this.Invalidate(new Rectangle(koordLama, s)); // // hapus kode berikut // this.UpdateTerkiniTinggiTumpukan(); // Thread t = new Thread(new ThreadStart(CekTumpukan)); // t.Start(); } Project Otak – http://otak.csharpindonesia.net 75
  • 76. CSH202 – Pemrograman Game Tetris Dengan C# Disini kita tidak lagi mengecek apakah ada baris komplet di tumpukan, karena sudah di- handle oleh Timer. Terakhir, modify Keypress-handler kita: private void PapanPermainan_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { switch (e.KeyChar) { case 'M': goto case 'm'; case 'm': BuatBlokBaru(); _timer.Enabled = true; break; case 'P': goto case 'p'; case 'p': // pause dotTetrus _timer.Enabled = false; String s = "*** GAME PAUSED ***" + " nTekan 'm' untuk kembali main"; MessageBox.Show(s); break; } … Dan tambahkan sebuah Load-handler (cara cepat membuat Load-handler adalah men- dobelClick form Papan Permainan di Form Designer): private void PapanPermainan_Load(object sender, System.EventArgs e) { String s = "*** dotTetrus by Zeddy *** " + "n http://www.zedilabs.com" + "nn Tekan 'm' untuk mulai!"; MessageBox.Show(s); } OK, sebenarnya yang terakhir ini tidak perlu… tapi biasakanlah memberi kredit kepada orang yang mengajarkan :P (euww… programmer emang musti egomaniac yah) Project Otak – http://otak.csharpindonesia.net 76
  • 77. CSH202 – Pemrograman Game Tetris Dengan C# 11.2 Kapan Game Over? Kita harus menentukan kapan Game berakhir, dan ini caranya mudah. Tinggal bandingkan _terkiniTinggiTumpukan apakah sama dengan 0 (nol): private void CekGameOver() { if ( this._terkiniTinggiTumpukan >= 1 ) return; // belum saatnya // game over, reset semua elemen _timer.Enabled = false; for (int i = 0; i < TINGGI; i++) for (int j = 0; j < LEBAR; j++) _elemen[i,j] = HITAM; String s = "*** GAME OVER ***" + "n Tekan 'm' untuk mulai lagi"; MessageBox.Show(s); // invalidate semuanya! this.Invalidate(); } Agar lebih fair, kita modify BlokBaru() agar memunculkan blok baru dari atas papan: Perhatikan bahwa koordinat-y nya adalah negatif, oleh karena itu kita harus menambahkan extra kode agar tidak muncul index out-of-range error. private void BuatBlokBaru() { ... _terkiniBlok.KoordKiriAtas = new Point(100,-60); // tengah atas for (int i = _terkiniBlok.KoordKiriAtas.X; i < i_max; i += OFFSETPIXEL) { for (int j = _terkiniBlok.KoordKiriAtas.Y; j < j_max; j += OFFSETPIXEL) { if (i >= 0 && j >= 0) // TAMBAHKAN ini! _elemen[j/OFFSETPIXEL, i/OFFSETPIXEL] = HITAM; } } ... Project Otak – http://otak.csharpindonesia.net 77
  • 78. CSH202 – Pemrograman Game Tetris Dengan C# 11.3 Dua Bugs lagi… Ternyata ada 2 bugs lagi yang perlu ditangani. Cara me-replikanya adalah: Tekan ‘m’ untuk mulai game baru Langsung geser kiri atau kanan dengan menggunakan ArrowKiri dan ArrowKanan. Index out of range error gara-gara kita memulai dari koordinat negatif! Cara menanganinya: Modify method BisaDigeserKanan(): private bool BisaDigeserKanan() { ... // case 2: menyentuh blok lain di sebelah kanan if ( _terkiniBlok.GetElemen(i,kolomTerkanan) == true && offset_i + i >= 0 && // TAMBAHKAN ini! _elemen[offset_i + i, offset_j + kolomTerkanan] > HITAM) { return false; } ... Dan juga method BisaDigeserKiri(): private bool BisaDigeserKiri() { ... // case 2: menyentuh blok lain di sebelah kiri if ( _terkiniBlok.GetElemen(i,kolomTerkiri) == true && offset_i + i >= 0 && // TAMBAHKAN ini! _elemen[offset_i + i, offset_j + kolomTerkiri] > HITAM) { return false; } ... Build Solution dan jalankan dotTetrus! Be proud of your first game! Project Otak – http://otak.csharpindonesia.net 78
  • 79. CSH202 – Pemrograman Game Tetris Dengan C# PENUTUP Volum 1 Saya akan menutup perjumpaan kita sampai disini dulu. Memang banyak yang masih perlu dilakukan, seperti: test secara intensif untuk bugs mengintegrasi sistem skor dan level graphics yang lebih baik (sekarang Anda tahu cara menggambar image di canvas form dengan DrawImage, maka mohon dibuat lebih bagus ImageBlok nya) banyak kode yang mirip dan harus di-refactor agar terlihat lebih apik. Kenapa ditutup sampai sini? Karena saya sudah memberikan basic training nya. Sekarang Anda seharusnya bisa mengimprovisasi program dotTetrus tanpa bimbingan saya. Dengan begitu, Anda bisa belajar improvisasi, tidak tergantung “nyontek” kode orang lain :P Kemudian alasan kedua adalah komitmen. Saya tidak bisa janji kapan akan ada Volum 2. Bahkan mungkin diantara Anda, ada yang sukses mengimprovisasi program dotTetrus dan mau membagi pengalaman untuk menulis Volum 2-nya. e-Book kecil ini ditulis dalam 5 hari, mulai Sabtu 19 Maret 2005 sampai dengan 23 Maret 2005. Ide-nya dari pengen nulis sebuah e-book yang fun (harus fun agar saya tidak bosan menulis dan agar pembaca tertarik). Dalam proses penulisan ini, banyak yang ditelantarkan; cucian dan setrikaan numpuk, makan telat, lupa belajar untuk kuliah hari berikutnya, dan uang kost lupa dibayar. Alhamdulillah selesai, jadi saya bisa back to my normal life :P Salam, Zeddy Iskandar. www.zedilabs.com Project Otak – http://otak.csharpindonesia.net 79
  • 80. CSH202 – Pemrograman Game Tetris Dengan C# Lampiran MSDN Connection MSDN Connection adalah komunitas developer .NET di Indonesia. Komunitas ini bertujuan meningkatkan pemahaman dan pengalaman anda tentang .NET Dengan bergabung bersama kami, anda otomatis mendapatkan update secara berkala mengenai perkembangan teknologi .NET langsung dari Microsoft Indonesia. Jika anda ingin bergabung dengan kami, caranya mudah. Hanya dengan mengklik url http://www.msdnconnection.com/indonesia dan masukkan data-data anda. Komunitas C# Indonesia Komunitas C# Indonesia merupakan bagian dari komunitas .NET Indonesia (INDC) yang berfokus kebidang teknologi .NET dengan menggunakan bahasa C# Komunitas C# Indonesia dapat dijumpai di url www.csharpindonesia.net dan anda dapat bergabung di site ini. Komunitas .NET Indonesia (INDC) Komunitas .NET Indonesia merupakan official dari komunitas-komunitas di Indonesia yang berbasis .NET. Anda bisa bertemu dengan beberapa aktivis komunitas .NET diseluruh wilayah Indonesia. Anda dapat bergabung kedalam komunitas ini dengan masuk ke url www.netindonesia.net dan dapat juga bergabung ke milis DOTNET dengan cara mengirim email kosong ke dotnet-subscribe@netindonesia.net Project Otak – http://otak.csharpindonesia.net 80
  • 81. CSH202 – Pemrograman Game Tetris Dengan C# Strukutur Organisasi Project Otak 2005-2006 Secara umum: Semua team adalah Technical Writer Semau Technical Writer harus mentaati semua aturan yang dibuat oleh Technical Writer Leader pada setiap project yang diikuti Semua wajib menyukseskan semua project yang ada di project otak Project Manager Manajemen semua departemen dan kegiatannya Interface antara team project otak dengan publik Memastikan semua kegiatan berjalan sesuai dengan scenario dan fungsinya. Secretary Mengatur semua administrasi project otak Manajemen keanggotaan team project otak Resource, Information, and Technology Department Diketuai oleh seorang Kepala Department ( Department Head) Tugas o Manajemen resource technical writer termasuk alokasi timing o Mengontrol semua project yang sedang berjalan agar berjalan sesuai dengan schedule Didalam departemen ini terdiri dari semua technical writer Setiap project e-book akan dikepalai oleh Technical Writer Leader yang bertanggung jawab ke Department Head Project Otak – http://otak.csharpindonesia.net 81
  • 82. CSH202 – Pemrograman Game Tetris Dengan C# QA Department Diketuai oleh seorang Kepala Department ( Department Head) Tugas o Manajemen resource Technical Editor o Menguji semua materi yang ada sesuai dengan standard dan template Planning, Strategic, and Finance Department Diketuai oleh seorang Kepala Department ( Department Head) Tugas o Membuat planning dan strategi dalam hal pengembangan dan peningkatan project otak baik materi, resource maupun member o Mencari sumber dana baik dari bentuk kerja sama maupun sponsorship Publication and Marketing Department Diketuai oleh seorang Kepala Department ( Department Head) Tugas o Membuat publikasi dan marketing ke publik tentang project otak Berikut ini susunan pengurus project otak yang baru dan berlaku sejak tanggal 3 Desember 2004 Project Manager : Agus Kurniawan (agusasia@yahoo.com) Secretary : Clementine Katarina Dewi Maya (demayac@yahoo.com) Resource, Information, and Technology Department Head : M Fathur Rahman (fatur@inforsys.co.id ) QA Department Head : Panji Aryaputra (paputra@gmail.com ) Planning, Strategic, and Finance Department Head : Risman Adnan (rismana@microsoft.com ) Publication and Marketing Department Head : Kunarto (ch03n@yahoo.com ) Untuk pengurus diatas, program kerja nya bisa dimulai pada tanggal 3 Desember 2004 Agus Kurniawan Project Manager of Project Otak Project Otak – http://otak.csharpindonesia.net 82
  • 83. CSH202 – Pemrograman Game Tetris Dengan C# Program Donatur Project Otak Untuk kemajuan dan kelangsungan project otak, kami dari team project otak mengundang para participant yang peduli atas kemajuan project ini dan resource teknologi .NET untuk menyumbang dana ke project ini. Program donatur ini terbagi menjadi 2 jenis yaitu Program donatur untuk kategori personal. Program ini dapat diikuti oleh masing- masing individu yang peduli pada project ini. Program donatur untuk kategori perusahan/institusi/lembaga. Program ini dapat diikuti oleh perusahan/institusi/lembaga Jika anda atau perusahan/institusi/lembaga anda tertarik untuk menyumbangkan dana ke project otak ini maka bisa menghubungi project manager, Agus Kurniawan, via email yaitu: agusasia@yahoo.com Project Otak – http://otak.csharpindonesia.net 83