Pemrograman Game Tetris Dengan C#

2,999 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
2,999
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
114
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Pemrograman Game Tetris Dengan C#

  1. 1. CSH202 – Pemrograman Game Tetris Dengan C# Pemgraman Game Tetris Dengan C# (CSH202) Zeddy Iskandar Project Otak 2005Project Otak – http://otak.csharpindonesia.net 2
  2. 2. CSH202 – Pemrograman Game Tetris Dengan C# Project OtakProject otak adalah project community yang bertujuan untuk menyediakan resourcestentang informasi teknologi .NET bagi orang-orang yang ingin belajar teknologi .NET. Trademark AcknowledgementsTeam project otak akan berusaha menyediakan informasi trademark termasuk semuaproduk yang telah disebut didalam buku ini.Windows, Framework .NET, C#, dan Visual Studio.NET adalah trademark dari Microsoft CreditsProject Manager SecretaryAgus Kurniawan Dewi MayaTechnical WriterZeddy IskandarEditorAgus KurniawanCover DesignerDanni AfasyahVersion 1.0Printed: 2 April 2005Book Code: CSH202Update E-Book : http://otak.csharpindonesia.netSemua materi yang ada didalam buku ini adalah satu kesatuan. Tidak boleh sebagianatau seluruh materi didalam buku ini diubah tanpa seijin team project otak.Project Otak – http://otak.csharpindonesia.net 3
  3. 3. CSH202 – Pemrograman Game Tetris Dengan C#Kata PengantarSaya ingin membuat e-book yang fun dan informatif. Bagi saya, menulis adalahpekerjaan 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 PembacaBanyak programmer yang sebelum menyentuh komputer menyentuh permainan konsolseperti Nintendo, Sega, PS, dsb. Ketika mereka belajar programming, biasanya merekatertarik untuk membuat game, tapi tidak tahu harus mulai dari mana. Buku ini bisadijadikan fondasi mereka untuk belajar tentang game-programming.Pembaca HARUS sudah mengerti bahasa programming C#. Andaikan tidak, sayasarankan untuk membaca e-book CSH101: Pengenalan Bahasa C# oleh AgusKurniawan dkk. di website Otak Project (http://otak.csharpindonesia.net)Pembaca juga MINIMAL sudah pernah membuat project di Visual Studio dan pernahmenggunakan Graphics Editing Program semacam Adobe Photoshop atau bahkanMicrosoft 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 IskandarCurtin University of Technology (Malaysia Campus)Project Otak – http://otak.csharpindonesia.net 4
  4. 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
  5. 5. CSH202 – Pemrograman Game Tetris Dengan C#Daftar IsiProject Otak .......................................................................................................3Credits .................................................................................................................3Kata Pengantar .....................................................................................................4Tentang Penulis ....................................................................................................5Daftar Isi ...............................................................................................................61. 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....................................................................................... 102. 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 ............................................................................................. 303. Papan Permainan ...........................................................................................33 3.1 Menambahkan fields .............................................................................................. 35 3.2 Menambahkan methods ......................................................................................... 36 3.3 Koordinat Pixel dan Grid Unit............................................................................... 374. 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................................................................................. 415. Mengaplikasikan Factory Pattern...................................................................44 5.1 Klas BlokFactory ................................................................................................... 44 5.2 Method BuatBlokBaru() untuk klas PapanPermainan........................................... 466. 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().................................................................................... 517. Merespons Keyboard Event............................................................................54 7.1 Merespons key Bawah ........................................................................................... 55 7.2 Merespons key Kiri................................................................................................ 56 7.3 Merespons Key Kanan........................................................................................... 568. Menumpuk Blok ..............................................................................................58 8.1 Modifikasi Klas Blok............................................................................................. 58Project Otak – http://otak.csharpindonesia.net 6
  6. 6. CSH202 – Pemrograman Game Tetris Dengan C# 8.2 Mengkontrol Penurunan Blok................................................................................ 58 8.3 Mengkontrol Penggeseran Kiri .............................................................................. 59 8.4 Mengkontrol Penggeseran Kanan .......................................................................... 619. Merotasikan Blok ............................................................................................63 9.1 Menambahkan ICloneable ke klas Blok ................................................................ 63 9.2 Method BisaRotasi() untuk klas PapanPermainan................................................. 64 9.3 Modifikasi KeyPress-handler................................................................................. 6610. Menghilangkan Baris Komplet ......................................................................68 10.1 Menampilkan “Blink” effect................................................................................ 7011. Menggunakan Timer .....................................................................................74 11.1 Menambahkan Timer ........................................................................................... 74 11.2 Kapan Game Over?.............................................................................................. 77 11.3 Dua Bugs lagi…................................................................................................... 78PENUTUP Volum 1.............................................................................................79Lampiran.............................................................................................................80Strukutur Organisasi Project Otak 2005-2006 ....................................................81Program Donatur Project Otak............................................................................83Project Otak – http://otak.csharpindonesia.net 7
  7. 7. CSH202 – Pemrograman Game Tetris Dengan C#1. Menyusun Blok-Blok TetrisAda banyak cara membuat program Tetris. Cara saya mungkin tidak efisien, tapisetidaknya simple.1.1 Data Struktur untuk Blok TetrisBaiklah, kita mulai dari dasar. Bagaimana menggambar blok Tetris?Bayangkan ARRAY 2-dimensi (dalam dunia .Net Framework dikenal dengan rectangulararray), 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 memakantempat. Lantas bagaimana implementasinya? Blok “Kros” diatas tadi dapat di-implementasikan menggunakan array of boolean values. Jadi yang disimpan di arrayadalah TRUE atau FALSE: F F F F F T F F T T T F F F F FKemudian, pada saatnya dibutuhkan untul ditampilkan, barulah kita ganti tiap-tiap TRUEdengan sebuah image pixel berwarna.Project Otak – http://otak.csharpindonesia.net 8
  8. 8. CSH202 – Pemrograman Game Tetris Dengan C#1.2 Data Struktur Papan PermainanKita dapat menggunakan boolean array juga sebagi papan permainan dimana blok-blokTetris akan diletakkan. Misalnya dengan ukuran panjang-lebar 12x20:Project Otak – http://otak.csharpindonesia.net 9
  9. 9. CSH202 – Pemrograman Game Tetris Dengan C#1.3 Elemen untuk blok TetrisTelah saya sebutkan bahwa sebuah blok Tetris disimpan sebagai 4x4 array danmanakala ada value True, maka disitulah kita insert sebuah box grafik.Buka Adobe Photoshop atau aplikasi grafik favorit Anda sekarang. Pertama saya buatasumsi 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 ygberbeda.Selanjutnya saya cek apakah papan permainan kelihatan pas (tidak terlalu besar ataukecil):Project Otak – http://otak.csharpindonesia.net 10
  10. 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→RulersProject Otak – http://otak.csharpindonesia.net 11
  11. 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: RGBGunakan Paint Bucket Tool untuk mewarnai pixel:Buat 7 macam dengan spesifikasi warna berikut:No. Warna RGB value1. Merah R:255, G:0, B:02. Kuning R:255, G:255, B:03. Hijau R:0, G:255, B:04. Biru R:0, G:0, B:2555. Magenta R:255, G:0, B:2556. Cyan R:0, G:255, B:2557. Coklat R: 198, G:156, B:109Project Otak – http://otak.csharpindonesia.net 12
  12. 12. CSH202 – Pemrograman Game Tetris Dengan C#Setelah itu, silahkan drag-n-drop masing-masing blok elemen berwarna untuk menyusunblok-blok Tetris.Bagaimana semangat Anda sekarang? Kita akan mulai menuliskan kode di babselanjutnya!Project Otak – http://otak.csharpindonesia.net 13
  13. 13. CSH202 – Pemrograman Game Tetris Dengan C#2. Design Klas BlokDi sini saya definisikan apa yang dimaksud dengan Blok. Definisi ini akan dipakaisampai akhir buku.Blok adalah bentuk-bentuk (shape) yang harus disusun dalam game Tetris. Blok ini ada7 macam: 1. Baris 5. ZTerbalik 2. Kotak 6. LNormal 3. Kros 7. LTerbalik 4. ZNormalInilah saatnya untuk menggunakan konsep inheritance dalam object-orientedprogramming.Project Otak – http://otak.csharpindonesia.net 14
  14. 14. CSH202 – Pemrograman Game Tetris Dengan C#2.1 UML DiagramKoordKiriAtas akan dijelaskan pada bab berikutnya.Panjang dan Lebar adalah 4x4. Karena value ini tetap, maka saya menggunakan constmodifier. Dan karena ini konstan, kita boleh membuatnya public.Draw() berisi kode untuk mengupdate gambar blok di atas papan permainan. Method initidak virtrual karena kodenya sama untuk semua subclass.RotateAtas() dsb adalah kode untuk mengubah posisi blok sesuai dengan tombol yangditekan user pada keyboard. Method ini virtual karena tiap-tiap blok jika di-rotasi akanberbeda posisinya dari blok yang lain.2.2 Visual Studio .NetSekarang saatnya untuk membuat VS.Net dan mulai menambahkan kode sedikit demisedikit.Pilih File→New→Project:Project Type: Visual C# ProjectsTemplate: Windows ApplicationName: dotTetrusLocation: Terserah*Nama “Tetris” adalah hak intelektual seorang programmer Russia yang sekarang kayakarena mendapatkan royalti dari game Tetris. Oleh karenanya, kita tidak boleh membuatgame dengan nama “Tetris” atau yang bunyinya mirip.Project Otak – http://otak.csharpindonesia.net 15
  15. 15. CSH202 – Pemrograman Game Tetris Dengan C#Untuk saat ini, kita ignore User Interface atau Windows Forms nya. Kita konsentrasimembuat class dahulu.Lihat Class View.Right-click Project dotTetrus, pilih Add→Class.Project Otak – http://otak.csharpindonesia.net 16
  16. 16. CSH202 – Pemrograman Game Tetris Dengan C#Isi sesuai dgn di atas dan click Finish.2.3 Klas BlokBerikut 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 ReferenceSystem.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
  17. 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 kodesebelumnya: // 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
  18. 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 setelahmempelajari 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. Methodini protected karena tidak boleh dipanggil dari luar class Blok, namun harus dapatdiakses oleh subclass seperti BlokGaris dsb.2.4 Klas BlokGarisSekarang kita siap untuk membuat 7 subclass Blok. Pilih Class View, right-clickdotTetrus 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
  19. 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 perlumengisi 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 konstruktorBlok() –lah kita meng-initialize array kita menjadi 4x4 boolean array!Sekarang kita harus meng-override semua virtual methods dari Base Class Blok. Tidakingat? 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
  20. 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 dalamsuatu 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
  21. 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 selesaimenulis suatu class baru, untuk make sure error-error di kelas tersebut diperbaiki dahulusebelum menulis sebuah class lain.Klik Build → Build Solution. Jika Anda menemui error, berarti Anda perlu meninjaukembali kode Anda! Mohon cek lagi pelan-pelan dan sabar sebelum melanjutkan ke klasberikutnya…Project Otak – http://otak.csharpindonesia.net 22
  22. 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 danperhatikan apakah ada error atau tidak!Project Otak – http://otak.csharpindonesia.net 23
  23. 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 untukConstructor 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
  24. 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
  25. 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 untukConstructor 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
  26. 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 kodeuntuk 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
  27. 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 untukConstructor 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
  28. 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
  29. 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 untukConstructor 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
  30. 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
  31. 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 danpastikan tidak ada error sampai sejauh ini!Project Otak – http://otak.csharpindonesia.net 32
  32. 32. CSH202 – Pemrograman Game Tetris Dengan C#3. Papan PermainanKira-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 namanyamenjadi PapanPermainan:Project Otak – http://otak.csharpindonesia.net 33
  33. 33. CSH202 – Pemrograman Game Tetris Dengan C#Kemudian, klik nama Form1 di Solution Explorer, dan lihat Properties nya. Gantifilename nya menjadi PapanPermainan.csSekarang kita ke Windows Forms Designer (PapanPermainan.cs [Design] tab), danubah Properties nya:Properties ValuesBackColor Pilih Custom, lalu klik warna hitam.Text dotTetrusFormBorderStyle FixedSingleSize::Width 240Size::Height 400MaximizeBox FalseStartPosition CenterScreenKemudian, 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
  34. 34. CSH202 – Pemrograman Game Tetris Dengan C#Sebelum mulai lebih lanjut, Build Solution (Ctrl – Shift – B) dan cek apakah ada builderror.3.1 Menambahkan fieldsRight-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 (palingbawah), oleh karenanya selanjutnya kita tidak usah menggunakan wizard, cukupmenaruhnya 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 warnablok ditambah 1 warna background hitam).Project Otak – http://otak.csharpindonesia.net 35
  35. 35. CSH202 – Pemrograman Game Tetris Dengan C#3.2 Menambahkan methodsRight-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 perluberapa jumlah baris yang harus dihilangkan. Method ini mudah dimengerti, intinya kalausuatu baris semuanya tidak berwarna hitam, maka increment jumlah baris yang harusdihilangkan.Apakah konstan HITAM diatas sudah kita definisikan? Kalau begitu, waktunyamenambahkan 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
  36. 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 UnitSemua drawing yang akan dilakukan di atas windows forms kita harus menggunakankoordinat pixel. Akan tetapi, kita menyimpan data struktur _elemen PapanPermainansebagai 20x12 integer array. Bagaimana mengkonversi dari unit pixel ke unit grid dansebaliknya?Lihat gambar diatas. Koordinat default windows forms menggunakan (0,0) sebagai titikpaling ujung kiri-atas. Mudah terlihat bahwa untuk mengubah koordinat (80,20) ke dalamgrid 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
  37. 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 bagaimanamewarnai papan permainan dan menampilkan blok. Untuk bab-bab selanjutnya,methods-methods PapanPermainan akan di-refine jadi pastikan tidak ada error dalamkode anda sekarang (tekan Ctrl – Shift – B).Project Otak – http://otak.csharpindonesia.net 38
  38. 38. CSH202 – Pemrograman Game Tetris Dengan C#4. Klas ImageBlok dan Menggambar di atas CanvasIngat 20x20 pixel berwarna yang kita buat di Bab 0 sebelumnya? Convert mereka kedalam file dengan format .GIF (Gunakan File → Save As) dan rename mereka menjadiMerah.gif, Kuning.gif, dst.Copy semua file *.gif ini ke dalam folder D:ProjectsdotNetdotTetrusbinDebug. JikaAnda tidak memiliki folder Debug, pastikan anda telah mem-Build Solution terlebihdahulu (Ctrl – Shift – B).4.1 Klas ImageBlokGunakan 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
  39. 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-initializevariabel-variabel static kita. Perlu dicatat bahwa kita tidak dapat membuat variabelMERAH dsb sebagai const karena mereka tidak dapat di-init pada waktu kompilasi.Membuat mereka sebagai public memang menyalahi prinsip object-orientedprogramming, jadi memang seharusnya dibuat private dan menggunakan Properties.Hanya menurut saya untuk situasi ini terlihat overkill. Tergantung Anda seberapa jauhingin menerapkan OOP dalam program Anda.Sekarang kita dapat mulai menggambar di atas window form kita!4.2 Modifikasi Klas BlokKita perlu me-modifikasi klas Blok kita agar tiap-tiap subclass Blok (BlokGaris, dsb) tahudengan 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
  40. 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 BlokKarena 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 kitadinyatakan true. Lihat Bab 0 lagi jika Anda lupa bagaimana kita menyimpan sebuah blokTetris.Lihat definisi DrawImage di CD-ROM MSDN Library. Klik View → Navigation → Indexdan ketik Graphics.DrawImage di field Look for, lalu dobel-klik Graphics.DrawImagemethod di result box.Project Otak – http://otak.csharpindonesia.net 41
  41. 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
  42. 42. CSH202 – Pemrograman Game Tetris Dengan C#Jika sudah memastikan method Draw() bekerja, hapus kode test tadi dan lanjut ke babberikutnya!Project Otak – http://otak.csharpindonesia.net 43
  43. 43. CSH202 – Pemrograman Game Tetris Dengan C#5. Mengaplikasikan Factory PatternJarang kita membuat program tanpa melihat-lihat buku patterns. Apakah penting? Tidakjuga, tapi patterns berisi resep-resep membuat program yang telah dipakai berulang-ulang oleh para programmer veteran. Jadi mirip dengan mengimplementasikan fungsisorting sendiri atau menggunakan standard library yang telah ada.Kita lihat apa yang dimaksud dengan Factory Pattern ini.5.1 Klas BlokFactorydotTetrus harus menampilkan blok secara random, jadi jangan sampai user tahu bahwasetelah 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-instanceBlokXXX? Kalau dilihat dalam real-life, sebuah pabrik (Factory) membuat berbagaimacam 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 menggunakankomponen-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
  44. 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 bisadipanggil 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
  45. 45. CSH202 – Pemrograman Game Tetris Dengan C# }5.2 Method BuatBlokBaru() untuk klas PapanPermainanPapanPermainan memerlukan satu method baru untuk “memesan” blok dariBlokFactory.Karena pembuatan blok baru ini harus dilakukan secara acak, tambahkan variabelRandom 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
  46. 46. CSH202 – Pemrograman Game Tetris Dengan C# }Lihat definisi Graphics.FillRectangle() di MSDN Library. Di sini saya menggunakanFillRectangle(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 tiapkali 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 PapanPermainan.Project Otak – http://otak.csharpindonesia.net 47
  47. 47. CSH202 – Pemrograman Game Tetris Dengan C#6. Menggunakan Invalidate()Selama ini, kita menggambar blok di masing-masing method. Ini akan menimbulkanredundancy atau kode yang sama di beberapa method. Ada satu problem denganapproach kita selama ini. Coba jalankan aplikasi dotTetrus, tekan ‘m’ untukmemunculkan blok baru, lalu minimize dotTetrus.Sekarang kembalikan window dotTetrus. Apa yang terjadi?Papan permainan menjadi hitam semua. Tentunya kita bisa saja melakukan trap atasevent Minimize, tapi ada cara yang lebih baik: menggunakan Event Paint.Pindah view ke PapanPermainan.cs [Design], lihat Properties, dan pilih tombolEvents, 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
  48. 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
  49. 49. CSH202 – Pemrograman Game Tetris Dengan C#6.2 Modifikasi klas BlokUbah 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
  50. 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, blokTetris akan muncul kembali. Jika tidak, cek kode Anda!6.4 Sekilas tentang Invalidate()Bagi yang belum pernah membuat program dengan bahasa pemrograman C (Win32API) atau dengan MFC Visual C++, akan saya jelaskan apa yang dilakukan denganmemanggil Invalidate().Project Otak – http://otak.csharpindonesia.net 51
  51. 51. CSH202 – Pemrograman Game Tetris Dengan C#Dengan memanggil Invalidate(), kita menyalakan event PAINT. Event Paint ini menyalasetiap kali window harus di re-draw ulang. Contohnya, ketika di maximize, restoresetelah minimize, restore setelah ditutupi window lain diatasnya.Dalam kata lain, kita memaksa program untuk menjalankan kode yang meng-handleevent 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 programuntuk me-redraw seluruh windows forms kita, dari koord (0,0) sampai (240,400)! Initentunya lebih lama daripada hanya me-redraw sebagian area saja.Memang kode PapanPermainan_Paint kita sebenarnya mengecek tiap grid danmenggambar 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 kodeseperti: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 tentangControl.Invalidate method (System.Windows.Forms).Satu hal lagi, saya bisa menulis kode Invalidate() di BlokBaru() dengan gaya sepertikode-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
  52. 52. CSH202 – Pemrograman Game Tetris Dengan C#Tapi ada konstruktor Rectangle() yang menerima argumen Point dan Size. Dan sayamelihatnya lebih elegan dari kode diatas. Tergantung Anda mau menggunakan styleyang mana. Dan lebih penting lagi, jika ada konstruktor atau method yang belum terlihatsebelumnya, lihat di MSDN Library dan periksa argumen-argumen apa saja yang bisaditerima oleh konstruktor dan method tersebut.Project Otak – http://otak.csharpindonesia.net 53
  53. 53. CSH202 – Pemrograman Game Tetris Dengan C#7. Merespons Keyboard EventPada 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 digunakanuntuk me-reset papan sebelum menggeser blok ke bawah, kiri atau kanan.Kemudian, kita buat method untuk meng-handle event KeyDown, yaitu event yang akanmenyala ketika user memencet suatu tombol di keyboard. Pindah ke Properties Sheetuntuk PapanPermainan.cs [Design] dan ikuti bagan berikut:Project Otak – http://otak.csharpindonesia.net 54
  54. 54. CSH202 – Pemrograman Game Tetris Dengan C#7.1 Merespons key BawahUntuk merespons tombol arrow Bawah, kode yang akan digunakan adalah methodTurunkanBlok().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
  55. 55. CSH202 – Pemrograman Game Tetris Dengan C#7.2 Merespons key KiriKita 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 KananKita 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
  56. 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 blokbaru, lalu gerakkan ke bawah, kiri, kanan.Project Otak – http://otak.csharpindonesia.net 57
  57. 57. CSH202 – Pemrograman Game Tetris Dengan C#8. Menumpuk BlokSampai sekarang sudah banyak kemajuan di program dotTetrus kita; memunculkan blokbaru secara random, menggeser kiri, menggeser kanan, dan menggeser ke bawah.Akan tetapi, satu hal masih mengganjal. Kita belum dapat membuat tumpukan satu blokdi 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 memilikipanjang 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 BlokTernyata 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 BlokTambahkan 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
  58. 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 KiriTidak hanya menurunkan blok, kita pun harus memastikan bahwa ketika menggeser kekiri dan ke kanan, blok tidak akan keluar dari papan permainan.Prinsipnya sama dengan kode BisaDiturunkan(), hanya untuk mengkontrol penggeseranke 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
  59. 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 secaravisual:Project Otak – http://otak.csharpindonesia.net 60
  60. 60. CSH202 – Pemrograman Game Tetris Dengan C#Andaikan blok di bagan atas digeser ke kiri, maka:koordBaru = ( -20, 20 )offset_j = -20 / 20 = -1offset_j + kolomTerkiri = -1 + 0 = -1 ( < 0 ! tidak bisa digeser lagi )8.4 Mengkontrol Penggeseran KananKode ini akan lebih kurang sama dengan BisaDigeserKiri(), hanya kita harus mencarikolom 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) == trueProject Otak – http://otak.csharpindonesia.net 61
  61. 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 = 9offset_j + kolomTerkanan = 9 + 3 = 12 ( >= 12 ! tidak bisa digeser lagi )Project Otak – http://otak.csharpindonesia.net 62
  62. 62. CSH202 – Pemrograman Game Tetris Dengan C#9. Merotasikan BlokKita sudah dapat menurunkan blok, geser kiri dan geser kanan. Yang kurang hanyalahmerotasikan blok ke atas, bawah, kiri dan kanan.9.1 Menambahkan ICloneable ke klas BlokTambahkan ICloneable interface ke deklarasi klas Blok:public class Blok : ICloneable*Ketika selesai mengetik ICloneable, VS.Net akan menyarankan memencet tombol Tabuntuk men-generate semua methods ICloneable secara otomatis. Tekan Tab danbiarkan VS.Net melakukkanya.Scroll ke bawah sekali, cari method Clone(). Mungkin VS.Net akanmenyembunyikannya di bawah region ICloneable Members:Klik tanda ‘+’ pada ICloneable Members maka sekarang Anda akan melihat methodKlon(). 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 warnablokProject Otak – http://otak.csharpindonesia.net 63
  63. 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. Ingattugas membuat blok adalah urusan BlokFactory. Kode yang baik memang sebaiknya// buat sesuai subklasb = BlokFactory.BuatkanBlok(spesifikasi);Akan tetapi ini berarti menambahkan satu variabel baru semacam kodeBlok atauspesifikasi dan melakukan perubahan di tiap konstruktor subclass kita. Saya hanyamelakukannya seperti ini untuk mengingatkan bahwa potensi bad-coding semakinbesar ketika deadline semakin dekat dan program hampir selesai :POK, kenapa kita membuat klas Blok mengimplementasi ICloneable interface? Ini karenasemua method Rotasi (RotateAtas, RotateBawah, dsb) mengubah value Blok._elemen.Sedangkan kita ingin dapat mengecek apakah rotasi bisa dilakukan seperti halnya kitamengecek apakah blok bisa digeser kiri. Oleh karena itu kita harus bekerja dengansebuah copy dari blok terkini.9.2 Method BisaRotasi() untuk klas PapanPermainanInilah kode BisaRotasi() yang fungsinya sama seperti BisaDigeserKiri,BisaDigeserKanan dan BisaDiturunkan, yaitu untuk mengecek apakah sebuah rotasibisa 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
  64. 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 permainanatau 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
  65. 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 dicekapakah 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-handlerKenapa 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
  66. 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 Rotasibekerja!Project Otak – http://otak.csharpindonesia.net 67
  67. 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 SolutionGeser blok ke kanan sampai pol / tidak bisa digeser lagi.Rotasi blok dengan tombol ‘a’Dapat dilihat bahwa error ini disebabkan oleh:index yang diluar rangeProject Otak – http://otak.csharpindonesia.net 68
  68. 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 workingprogram sebelum menulis. Akibatnya bugs baru muncul setelah beberapa bab. Mohonmaaf kalau ada bugs-bugs yang lain :PPastikan 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
  69. 69. CSH202 – Pemrograman Game Tetris Dengan C#10.1 Menampilkan “Blink” effectSebelum menghilangkan baris-baris Tetris yang komplet, saya ingin menampilkan visualcue (petunjuk visual) bahwa memang baris-baris tersebut komplet.Idenya simple sekali: hitamkan baris sleep() untuk bbrp millisecond kembalikan baris ke warna asalDan untuk lebih kelihatan, saya sengaja mem-blink nya dua kali. Ide yang simple initernyata 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, kitatidak 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

×