Materi Workshop - Code
Materi Workshop - Code
adalah kelas MIDlet. Sekarang kita coba membuat sebuah kelas MIDlet dengan nama SampleMIDlet, caranya yaitu dengan klik kanan pada default package, pilih new, pilih MIDlet.
Akan muncul sebuah form berikut kemudian kita isi nama MIDlet nya dengan Example 1 dan nama Class nya MainMidlet, lalu klik finish. MIDlet Name ini akan muncul sebagai nama game ketika di instal di device.
Kelas MainMidlet ketika dibuka maka isinya adalah sebagai berikut. import javax.microedition.midlet.*; public class MainMidlet extends MIDlet { public void startApp() { } public void pauseApp() { } public void destroyApp(boolean unconditional) { } } - method startApp() merupakan method yang dipanggil ketika aplikasi mulai dijalankan - method pauseApp() merupakan method yang dipanggil ketika muncul interupsi dari telepon ketika aplikasi berjalan. Misalkan ketika aplikasi berjalan ada telepon masuk. - method destroyApp() merupakan method yang dipanggil ketika keluar dari aplikasi (exit)
Mencetak Output Fungsi utama dari sebuah program adalah memberikan output kepada pengguna. Karena jika tidak bisa memberikan output maka bagaimana program tersebut bisa memberikan manfaat kepada penggunanya? Oleh karena itu pastilah sebuah program pasti memiliki output, entah itu berupa teks, gambar, maupun suara. Kita mulai mencoba dengan output yang paling dasar yaitu output teks. Tambahkan kode untuk mencetak kata/kalimat yaitu System.out.println() di dalam startApp() kemudian coba jalankan dengan mengeklik tombol run atau langsung tekan F6.
... public class HelloMidlet extends MIDlet { public void startApp() { System.out.println("Hello World"); } ... } ketika dijalankan maka di emulator tidak akan muncul sesuatu apapun, melainkan di output consol akan muncul "Hello World".
Hasil cetakan dikonsol ini tidak bisa kita lihat jika melalui device sesungguhnya. Lantas apa gunanya mencetak lewat konsol ini? Penggunaan output konsol ini lebih terasa bagi developer(pembuat aplikasi), yaitu digunakan untuk keperluan tracing atau debugging, semisal untuk mengetahui isi dari sebuah variabel, atau untuk mengetahui kode bagian manakah yang sedang dijalankan oleh emulator.
Mencetak output di layar terus bagaimana untuk menampilkan di layar handphone emulator? ada 2 buah metode : 1. menggunakan J2ME API LCDUI, yaitu metode highlevel yang merupakan bawaan dari J2ME. tampilan yang dibuat menggunakan LCDUI akan mirip dengan tampilan yang biasa muncul di handphone. metode ini merupakan metode yang mudah digunakan akan tetapi penggunaannya kurang variatif. 2. menggunakan metode low level canvas, yaitu dengan cara memanipulasi secara langsung warna piksel - piksel yang ada di layar handphone. metode ini lebih sulit tetapi lebih variatif dan bebas penggunaannya. untuk membuat game, tentu saja metode kedua yang kita gunakan. karena pada dasarnya game adalah kumpulan gambar-gambar yang kita tampilkan dan animasikan sedemikian rupa sehingga tercipta sebuah permainan yang dapat diinteraksikan dengan pengguna. sedangkan untuk metode pertama sendiri biasanya digunakan untuk membuat aplikasi, bukan game. namun tidak ada salahnya kita coba. Ubah kelas MainMidlet pada bagian startApp() sehingga menjadi seperti berikut ... public class MainMidlet extends MIDlet { public void startApp() { Form form = new Form("Workshop JGE"); //[membuat form baru dengan judul "Workshop JGE"] form.append("Hello World"); //[menampilkan "Hello World"] Display.getDisplay(this).setCurrent(form); //[mengeset layar agar menampilkan form yang kita buat] } ... }
setelah mencoba menggunakan metode high level API sekarang kita coba untuk menggunakan low level canvas. untuk itu kita buat sebuah class baru dengan nama MainCanvas. Caranya yaitu klik kanan pada default package kemudian pilih New, Java Class.
Kemudian isikan kode berikut pada kelas tersebut. import javax.microedition.lcdui.game.GameCanvas; public class MainCanvas extends GameCanvas { public MainCanvas() { super(false); setFullScreenMode(true); } } Penjelasan : Kode di atas menunjukkan bahwa kelas MainCanvas merupakan turunan (extends) dari kelas GameCanvas. Kelas GameCanvas sendiri adalah sebuah kelas yang digunakan untuk memanipulasi layar handphone, khususnya untuk digunakan dalam aplikasi game. Di dalam kelas MainCanvas, kita buat method konstruktor MainCanvas() , yaitu method yang akan otomatis terseksekusi ketika kita membuat objek MainCanvas baru. Di dalam method tesebut kita tambahkan super(false) yaitu pemanggilan konstruktor parent (GameCanvas) yang memiliki sebuah parameter boolean yang jika isi true akan
mencegah penggunaan tombol pada handphone, kode diatas (super(false);) agar aplikasi nantinya dapat menerima inputan dari user. Kemudian setFullScreenMode() digunakan agar kita dapat memanipulasi layar secara penuh (Full Screen). Thread Sebuah game pada dasarnya adalah sebuah animasi, yang pergerakannya dapat diatur oleh pengguna atau pemain game. Sedangkan sebuah animasi itu sendiri merupakan kumpulan frame atau gambar yang kita tampilkan pada layar secara bergantian dan terus menerus. Untuk menciptakan efek seperti ini kita harus membuat kelas MainCanvas di atas agar dapat berjalan secara terus menerus untuk mengganti frame atau gambar yang ada di layar. Oleh karena itu kita buat kelas GameCanvas agar dapat berajalan sendiri dengan menggunakan Thread. import javax.microedition.lcdui.game.GameCanvas; public class MainCanvas extends GameCanvas implements Runnable{ public MainCanvas(){ ... } ... public void run() { } } Penjelasan: Implements Runnable digunakan agar kelas MainCanvas dapat dijalankan sebagai sebuah Thread. Method run() merupakan method yang akan dieksekusi ketika kelas MainCanvas dijalankan sebagai Thread. Di dalam method inilah kita nantinya akan menambahkan kode untuk mengganti tampilan layar secara terus menerus. Menggambar Objek Kita coba untuk menggambar beberapa objek di canvas yang baru kita buat. Di dalam method run tambahkan kode berikut. public void run() { Graphics g = getGraphics(); //mengeset warna biru g.setColor(0, 0, 255);
//menggambar segi empat seukuran layar (sebagai background) g.fillRect(0, 0, getWidth(), getHeight()); //mengeset warna merah g.setColor(255, 0, 0); //menggambar lingkaran g.fillArc(100, 100, 50, 50, 0, 360); } Penjelasan: Kelas Graphics merupakan kelas yang menyimpan nilai-nilai warna pada tiap piksel layar. Sedangkan getGraphics() berfungsi untuk mengambil nilai-nilai warna piksel layar pada saat ini. Untuk menjalankan kelas MainCanvas kita perlu memodifikasi kelas MainMidlet untuk menambahkan kode yang akan menjalankan kelas MainCanvas sebagai sebuah Thread baru. Kemudian coba jalankan. ... MainCanvas canvas; public void startApp() { canvas = new MainCanvas(); Thread t = new Thread(canvas); t.start(); Display.getDisplay(this).setCurrent(canvas); } ...
Membuat Animasi Untuk membuat animasi, kita perlu memodifikasi method run() agar dapat mengganti gambar pada layar secara terus menerus, sehingga menjadi sebuah animasi. Ubah method run() menjadi seperti berikut kemudian coba jalankan. public void run() { Graphics g = getGraphics(); //koordinat awal lingkaran int x = 100; int y = 0; while (true) { //mengeset warna biru g.setColor(0, 0, 255); //menggambar segi empat seukuran layar //(sebagai background) g.fillRect(0, 0, getWidth(), getHeight()); //mengeset warna merah g.setColor(255, 0, 0); //menggambar lingkaran g.fillArc(x, y, 50, 50, 0, 360); //menggerakkan lingkaran y = y + 5; flushGraphics(); try { //mengatur kecepatan frame ~ 30 fps Thread.sleep(1000 / 30); } catch (InterruptedException ex) { ex.printStackTrace(); } } } Penjelasan: Thread.sleep() berfungsi untuk memberikan jeda pada setiap perulangan sehingga dapat kita atur frameratenya
Game Structure Pembagian kode di dalam game secara umum dapat dibagi menjadi tiga, yaitu pengambilan input dari pemain, pengubahan objek-objek di dalam game, dan penggambaran objek-objek game ke layar. Oleh karena itu kita tambahkan method-method berikut. public class MainCanvas extends GameCanvas implements Runnable{ public MainCanvas(){ ... } public void getInput() { } public void update() { } public void draw(Graphics g) { } } Kita bersihkan kode di dalam run(), kemudian di dalam run() kita panggil getInput(), update(), dan draw() dengan memasukkannya terlebih dahulu ke dalam perulangan agar pemanggilan dilakukan secara berulang. ... public void run() { Graphics g = getGraphics(); while(true){ getInput(); update(); draw(g); try { Thread.sleep(1000/30); } catch (InterruptedException ex) { ex.printStackTrace(); } } } ...
Menggambar Image Kita coba untuk menggambar sebuah Image. Kopikan gambar bg.png (beserta gambar lain yang disediakan) ke dalam project. Caranya yaitu klik kanan pada gambar yang ingin dikopi, klik copy, kemudian pastekan di dalam default package project di dalam Netbeans.
Kemudian untuk me-load gambar ke dalam program, tambahkan kode berikut. ... Image bgImage; public MainCanvas() { super(false); setFullScreenMode(true); try { bgImage = Image.createImage("/bg.png"); } catch (IOException ex) { ex.printStackTrace(); } } ... Kemudian kita gambarkan gambar tersebut ke layar dengan menambah kode berikut pada method draw() ... public void draw(Graphics g) { g.drawImage(bgImage, 0, 0, 0); flushGraphics(); } ... Penjelasan: flushGraphics() digunakan untuk menggambar nilai-nilai warna piksel di dalam kelas Graphics ke layar handphone. Pada g.drawImage(bgImage, 0, 0, 0) , 0 pertama merupakan posisi x pada layar dan 0 yang kedua merupakan posisi y, dan 0 yang ketiga adalah anchor(acuan gambar) dan nilai
0 adalah default(pojok kiri atas), anchor bisa kita set sepert g.drawImage(bgImage, 0, 0, Graphics.HCENTER | Graphics.TOP)maka gambar akan dimulai dari tengah, penjelasan
Sekarang kita coba menambahkan player ke dalam game. Berbeda dengan dengan sebelumnya kali ini kita menggunakan sprite. Sprite adalah sebuah objek yang memiliki beberapa gambar/frame yang nanti dapat kita atur gambar/frame mana yang akan ditampilkan.
Pertama kita masukkan gambar player ke dalam program, kemudian kita buat sprite berdasarkan gambar tersebut. Gambar player.png berukuran 80x40 piksel berisi 2 buah frame. Oleh karena itu sprite yang kita buat ukurannya adalah 40x40 piksel. public class MainCanvas extends GameCanvas implements Runnable { Image bgImage; Image playerImage; Sprite playerSprite; ...
... public MainCanvas() { super(false); setFullScreenMode(true); try { bgImage = Image.createImage("/bg.png"); playerImage = Image.createImage("/player.png"); playerSprite = new Sprite(playerImage, 40, 40); } catch (IOException ex) { ex.printStackTrace(); } } ... } Kemudian kita buat method drawPlayer() untuk menggambar sprite player, lalu kita panggil di dalam method draw() ... public void drawPlayer(Graphics g){ playerSprite.paint(g); } public void draw(Graphics g) { g.drawImage(bgImage, 0, 0, 0); drawPlayer(g); flushGraphics(); } ...
Kemudian kita coba untuk meletakkan player di bawah tengah, dengan sebelumnya kita set anchor/referensi piksel di tengah-tengah sprite player
public MainCanvas() { super(false); setFullScreenMode(true); try { bgImage = Image.createImage("/bg.png"); playerImage = Image.createImage("/player.png"); playerSprite = new Sprite(playerImage, 40, 40); int x = playerSprite.getWidth() / 2; int y = playerSprite.getHeight() / 2;
playerSprite.defineReferencePixel(x, y); x = getWidth() / 2; y = getHeight() - playerSprite.getHeight(); playerSprite.setRefPixelPosition(x, y); } catch (IOException ex) { ex.printStackTrace(); } }
Kemudian kita coba menggerakkan player sesuai dengan input pemain. Kita edit bagian getInput sehingga menjadi seperti berikut. Image bgImage; Image playerImage; Sprite playerSprite; int keyStates; ... public void getInput() { keyState = getKeyStates(); if ((keyState & LEFT_PRESSED) != 0) { playerSprite.move(-4, 0); } else if ((keyState & RIGHT_PRESSED) != 0) { playerSprite.move(4, 0); } }
Penjelasan untuk playerSprite.move(-4, 0);, angka -4 merupakan perubahan gerak x pada layar, dan 0 disini merupakan perubahan y, jadi tidak menutup kemungkinan jika ditekan tombol 4 hanya kekiri saja, tetapi juga bias ke kiri atas, atau ke kiri bawah. Kemudian coba jalankan dan gerakkan player dengan menekan tombol 4 atau 6 di emulator maupun di keyboard.
Lalu tambahkan juga kode untuk menggerakkan player ke atas dan ke bawah public void getInput() { int keyState = getKeyStates(); if ((keyState & LEFT_PRESSED) != 0) { playerSprite.move(-4, 0); } else if ((keyState & RIGHT_PRESSED) != 0) { playerSprite.move(4, 0); } if ((keyState & UP_PRESSED) != 0) { playerSprite.move(0, -4); } else if ((keyState & DOWN_PRESSED) != 0) { playerSprite.move(0, 4); } }
Setelah berhasil membuat player dapat digerakkan, selanjutnya kita tambahkan peluru untuk player. Untuk penambahan ini kita menambahkan beberapa variabel dan method yaitu 1. 2. 3. 4. 5. Variabel bulletImage, berisi gambar peluru (bullet.png) Variabel bullets, vektor yang akan menyimpan kumpulan peluru yang dilepaskan oleh player Method addBullet() yaitu method untuk menambah (menembakkan) peluru. Method drawBullet() yaitu method yang akan menggambar sprite peluru ke layar Method updateBullet() yaitu method yang akan mengubah posisi peluru setiap kali perulangan. Pertama kita masukkan dulu gambar yang dibutuhkan ke dalam variabel.
public class MainCanvas extends GameCanvas implements Runnable { Image bgImage; Image playerImage; Sprite playerSprite; int keyState; Image bulletImage; Vector bullets; public MainCanvas() { ... playerSprite.setRefPixelPosition(x, y); bulletImage = Image.createImage("/bullet.png"); bullets = new Vector(); } catch (IOException ex) { ex.printStackTrace(); } } ... } Penjelasan: Vector merupakan kelas yang dapat menyimpan beberapa objek sekaligus. Di sini vector bullets akan digunakan untuk menyimpan sprite-sprite peluru yang dikeluarkan oleh player. Kita tambahkan method addBullet() untuk menembakkan peluru. Kemudian kita set agar method ini dipanggil ketika kita memencet tombol fire atau 5 pada keyboard handphone. public void addBullet() { Sprite bullet = new Sprite(bulletImage, 6, 16); int x = bullet.getWidth() / 2; int y = bullet.getWidth() / 2; bullet.defineReferencePixel(x, y); x = playerSprite.getRefPixelX();
y = playerSprite.getRefPixelY() - 20; bullet.setRefPixelPosition(x, y); bullets.addElement(bullet); } public void getInput() { int keyState = getKeyStates(); if ((keyState & LEFT_PRESSED) != 0) { ... } if ((keyState & UP_PRESSED) != 0) { ... } if ((keyState & FIRE_PRESSED) != 0) { addBullet(); } } Kemudian kita tambahkan method drawBullet() untuk menggambar setiap peluru ke layar. public void drawBullet(Graphics g) { Sprite bullet; for (int i = 0; i < bullets.size(); i++) { bullet = (Sprite) bullets.elementAt(i); bullet.paint(g); } } public void draw(Graphics g) { g.drawImage(bgImage, 0, 0, 0); drawPlayer(g); drawBullet(g); flushGraphics(); } Jika dicoba dijalankan hasilnya sebagai berikut:
Sperti yang terlihat, peluru sudah berhasil ditambahkan, tetapi peluru tidak bergerak. Oleh karena itu kita tambahkan method updateBullet() untuk menggerakkan setiap peluru ke atas. Lalu coba jalankan. public void updateBullet() { Sprite bullet; for (int i = 0; i < bullets.size(); i++) { bullet = (Sprite) bullets.elementAt(i); bullet.move(0, -8); } } public void update() { updateBullet(); }
Jika diperhatikan peluru yang ditembakkan pesawat tampak berjejer terlalu rapat. Untuk mengaturnya agar lebih renggang kita ubah bagian pemanggilan addBullet() di dalam getInput() agar peluru hanya bertambah satu kali ketika tombol fire ditekan. public class MainCanvas extends GameCanvas implements Runnable { ... Image bulletImage; Vector bullets; int lastKeyState; ... public void getInput() { lastKeyState = keyState; keyState = getKeyStates(); if ((keyState & LEFT_PRESSED) != 0) { ... } if ((keyState & UP_PRESSED) != 0) { ... } if ((keyState & FIRE_PRESSED) != 0 && (lastKeyState & FIRE_PRESSED) == 0) { addBullet(); }
Selanjutnya kita perlu melakukan penghapusan terhadap peluru yang sudah tidak diperlukan, yaitu peluru-peluru yang sudah keluar dari layar. Hal ini perlu dilakukan untuk menghemat penggunaan memori, karena setiap melakukan penembakan, isi dari vector bullet akan bertambah satu terus menerus, sehingga perlu dilakukan penghapusan. public void updateBullet() { Sprite bullet; for (int i = 0; i < bullets.size(); i++) { bullet = (Sprite) bullets.elementAt(i); bullet.move(0, -8); if (bullet.getRefPixelY() < 0) { bullets.removeElement(bullet); i = i 1; } } } Selanjutnya kita tambahkan musuh ke dalam permainan. Hampir sama dengan peluru, tambahan yang kita butuhkan adalah:
1. 2. 3. 4. 5. 6.
Variabel enemyImage, untuk menyimpan gambar enemy.png. Variabel enemies, untuk menyimpan musuh-musuh yang tampil dilayar. Variabel random, untuk menggenerate angka random. Method addEnemy(), untuk menambahkan musuh. Method drawEnemy(), untuk menggambar musuh. Method updateEnemy(), untuk menggerakkan musuh.
Pertama kita tambahkan dan inisialisasi variabel yang dibutuhkan yaitu enemyImage dan enemies. public class MainCanvas extends GameCanvas implements Runnable { ... int lastKeyState; Image enemyImage; Vector enemies; Random random; public MainCanvas() { super(false); setFullScreenMode(true); try { ... enemyImage = Image.createImage("/enemy.png"); enemies = new Vector(); random = new Random(); } catch (IOException ex) { ex.printStackTrace(); } } } Setelah itu kita tambahkan method addEnemy(). Method addEnemy() kita panggil di dalan update() agar musuh dapat tertambah secara otomatis. public void addEnemy(){ Sprite enemy = new Sprite(enemyImage, 40, 40); int x = enemy.getWidth() / 2; int y = enemy.getWidth() / 2; enemy.defineReferencePixel(x, y); x = random.nextInt(getWidth()); y = 0; enemy.setTransform(Sprite.TRANS_ROT180); enemy.setRefPixelPosition(x, y); enemies.addElement(enemy); }
public void update() { addEnemy(); updateBullet(); } Penjelasan: Posisi dari musuh pada awalnya kita tempatkan di paling atas (y = 0) namun lokasinya random (x = random). Karena musuh bergerak dari atas ke bawah, maka Sprite-nya perlu kita putar 180 derajat. Kemudian tambahkan method drawEnemy() dan kita panggil method tersebut di dalam draw() public void drawEnemy(Graphics g) { Sprite enemy; for (int i = 0; i < enemies.size(); i++) { enemy = (Sprite) enemies.elementAt(i); enemy.paint(g); } } public void draw(Graphics g) { g.drawImage(bgImage, 0, 0, 0); drawPlayer(g); drawBullet(g); drawEnemy(g); flushGraphics(); }
Kemudian kita tambahakan method updateEnemy() untuk menggerakkan setiap musuh ke bawah. public void updateEnemy() { Sprite enemy; for (int i = 0; i < enemies.size(); i++) { enemy = (Sprite) enemies.elementAt(i); enemy.move(0, 5); } } public void update() { addEnemy(); updateBullet(); updateEnemy(); }
Setelah dijalankan tampak kemunculan pesawat musuh terlalu berdekatan. Perlu kita beri jeda, dengan cara menambahkan counter sehingga dapat diatur jarak kemunculan setiap musuh. public class MainCanvas extends GameCanvas implements Runnable { ... Random random; int counterEnemy = 0; public void update() {
Kemudian sama dengan kasus peluru sebelumnya, kita perlu melakukan penghapusan musuh yang sudah tidak diperlukan lagi (tidak tampil di layar). Kita tambahkan penghapusan ini di bagian updateEnemy() public void updateEnemy() { Sprite enemy; for (int i = 0; i < enemies.size(); i++) { enemy = (Sprite) enemies.elementAt(i); enemy.move(0, 5); if (enemy.getRefPixelY() > getHeight()) { enemies.removeElement(enemy); i--; } }
} Selanjutnya kita tambahkan efek jika peluru mengenai pesawat musuh maka akan meledak. Untuk mencapai ini kita perlu melakukan pendeteksian tabrakan (collision detection) antara peluru dengan musuh. Setelah itu jika ternyata memang terjadi tabrakan kita hilangkan peluru tersebut, kemudian kita ganti frame musuh dengan frame musuh yang meledak, lalu setelah itu baru kita hilangkan musuhnya. public void updateEnemy() { Sprite enemy; Sprite bullet; for (int i = 0; i < enemies.size(); i++) { enemy = (Sprite) enemies.elementAt(i); enemy.move(0, 5); if (enemy.getRefPixelY() > getHeight() || enemy.getFrame() == 1) { enemies.removeElement(enemy); i--; } else { for (int j = 0; j < bullets.size(); j++) { bullet = (Sprite) bullets.elementAt(j); if (bullet.collidesWith(enemy, true)) { bullets.removeElement(bullet); enemy.setFrame(1); break; } } } } } Penjelasan: Di sini kita mengubah bagian yang sebelumnya berfungsi menghilangkan musuh yang keluar dari layar saja, kita tambahi supaya juga menghilangkan musuh yang sedang meledak (frame = 1). Kemudian jika ternyata seharusnya musuh tidak dihilangkan maka kita cek apakah musuh terkena tembakan menggunakan collision detection, jika terkena maka kita ubah framenya menjadi frame meledak. Untuk collision detection sendiri sebenarnya ada dua tipe yaitu collision detection yang mencapai level piksel dan yang bukan.
Selanjutnya kita menambahkan efek jika pesawat musuh menabak player maka keduanya akan meledak. public void updateEnemy() { Sprite enemy; Sprite bullet; for (int i = 0; i < enemies.size(); i++) { ... } else { for (int j = 0; j < bullets.size(); j++) { bullet = (Sprite) bullets.elementAt(j); if (bullet.collidesWith(enemy, true)) { bullets.removeElement(bullet); enemy.setFrame(1); break; } } if (enemy.collidesWith(playerSprite, true)) { enemy.setFrame(1); playerSprite.setFrame(1); } } }
Selanjutnya kita tambahkan mekanisme game over ketika pesawat player meledak. Untuk melakukan ini kita mulai menggunakan yang namanya state. Ketika permainan memiliki state PLAY maka pemain bisa memasukkan input ke permainan dan objek di dalamnya kita gerakkan sesuai jalannya permainan. Namun jika permainan memasuki state OVER, objek di dalam permainan kita diamkan, tetapi pemain masih bisa memberikan masukan untuk mereset permainan. Pertama jika player meledak maka state berubah menjadi OVER int int int int ... counterEnemy = 0; PLAY = 1; OVER = 2; state = PLAY;
public void updateEnemy() { ... for (int i = 0; i < enemies.size(); i++) { ... if (enemy.collidesWith(playerSprite, true)) { enemy.setFrame(1); playerSprite.setFrame(1); state = OVER;
} } } } Kemudian kita hanya melakukan addEnemy(), updateEnemy(), updateBullet() jika state = PLAY public void update() { if (state == PLAY) { if (counterEnemy == 16) { addEnemy(); counterEnemy = 0; } counterEnemy++; updateBullet(); updateEnemy(); } } Jika dijalankan maka ketika player meledak, maka game seolah berhenti, karena kita tidak melakukan update. Tetapi masih masih bisa digerakkan, oleh karena itu kita juga perlu mengedit getInput(). public void getInput() { lastKeyState = keyState; int keyState = getKeyStates(); if (state == PLAY) { if ((keyState & LEFT_PRESSED) != 0) { ... } if ((keyState & UP_PRESSED) != 0) { ... } if ((keyState & FIRE_PRESSED) != 0) { ... } } } Setelah itu kita edit bagian draw() supaya menampilkan tulisan GAME OVER.
public void draw(Graphics g) { g.drawImage(bgImage, 0, 0, 0); drawPlayer(g); drawBullet(g); drawEnemy(g); if (state == OVER) { g.setFont(Font.getDefaultFont()); g.setColor(0xFF0000); g.drawString("GAME OVER", getWidth() / 2, getHeight() / 2, Graphics.HCENTER | Graphics.TOP); } flushGraphics(); } Terakhir, kita tambahkan method reset() agar pemain dapat memulai kembali permainan. Kita panggil method tersebut jika pemain menekan tombol FIRE pada keadaan state = OVER public void reset() { int x = getWidth() / 2; int y = getHeight() - playerSprite.getHeight(); playerSprite.setRefPixelPosition(x, y); playerSprite.setFrame(0); enemies.removeAllElements(); bullets.removeAllElements(); state = PLAY; } public void getInput() { int keyState = getKeyStates(); if (state == PLAY) { ... } else if (state == OVER) { if ((keyState & FIRE_PRESSED) != 0) { reset(); } } } Untuk mempercantik, ketika game over kita beri petunjuk kepada pemain untuk menekan FIRE jika ingin mengulang kembali permainan. public void draw(Graphics g) {
... if (state == OVER) { g.setFont(Font.getDefaultFont()); g.setColor(0xFF0000); g.drawString("GAME OVER", getWidth() / 2, getHeight() / 2 - 15, Graphics.HCENTER | Graphics.TOP); g.drawString("PRESS FIRE", getWidth() / 2, getHeight() / 2 + 15, Graphics.HCENTER | Graphics.TOP); } flushGraphics(); }
Scoring Untuk menambahkan perhitungan skor di dalam game maka kita perlu menambahkan variabel baru, kita beri nama saja score. Kemudian setiap kali player berhasil menembak musuh kita tambahkan score dengan nilai tertentu misalkan 100. Selain itu kita juga perlu menambahkan method drawScore() untuk menggambar/menampilkan score yang dimiliki saat ini. Dan terakhir ketika player kalah kita tunjukkan berapa skor yang dimiliki. Jangan lupa juga untuk mengeset score menjadi 0 di dalam method reset(). public class MainCanvas extends GameCanvas implements Runnable { ... int state = PLAY; int score = 0;
... public void reset() { ... score = 0; } ... public void updateEnemy() { ... for (int i = 0; i < enemies.size(); i++) { ... if (enemy.getRefPixelY() > getHeight() || enemy.getFrame() == 1) { ... } else { for (int j = 0; j < bullets.size(); j++) { bullet = (Sprite) bullets.elementAt(j); if (bullet.collidesWith(enemy, true)) { bullets.removeElement(bullet); enemy.setFrame(1); score += 100; break; } } ... } } } ... public void drawScore(Graphics g) { g.setFont(Font.getDefaultFont()); g.setColor(0xFF0000); g.drawString("SCORE : " + score, Graphics.TOP); } public void draw(Graphics g) { g.drawImage(bgImage, 0, 0, 0); ... drawScore(g);
10,
10,
Graphics.LEFT
if (state == OVER) { g.setFont(Font.getDefaultFont()); g.setColor(0xFF0000); g.drawString("GAME OVER", getWidth() / 2, getHeight() / 2 - 30, Graphics.HCENTER | Graphics.TOP); g.drawString("YOU GOT " + score, getWidth() / 2, getHeight() / 2, Graphics.HCENTER | Graphics.TOP); g.drawString("PRESS FIRE", getWidth() / 2, getHeight() / 2 + 30, Graphics.HCENTER | Graphics.TOP); } flushGraphics(); } }