P. 1
Membuat Game Menggunakan Java Dan Netbeans

Membuat Game Menggunakan Java Dan Netbeans

|Views: 126|Likes:
Published by Eko Adja

More info:

Published by: Eko Adja on Aug 13, 2013
Copyright:Attribution Non-commercial

Availability:

Read on Scribd mobile: iPhone, iPad and Android.
download as PDF, TXT or read online from Scribd
See more
See less

11/19/2013

pdf

text

original

05/2009

CODING

KNOW-HOW

89

MEMBUAT GAME STRATEGI SEDERHANA MENGGUNAKAN JAVA DAN NETBEANS
BAGIAN 1 DARI 3 ARTIKEL
Dalam tiga seri ini, kita akan belajar untuk membuat game strategi “Devilish Children” dengan menggunakan bahasa pemrograman Java.
Windra Swastika & M. Fauzil Haqqi

Sekilas Java dan NetBeans
Java adalah bahasa pemrograman tingkat tinggi yang dikembangkan oleh Sun Microsystems. Bagi Anda yang sudah pernah menggunakan bahasa C atau C++, tentu tidak akan asing dengan sintaks bahasa Java. Hanya saja, pemrograman bahasa Java berorientasi pada object atau yang biasa disebut dengan OOP (Object Oriented Programming). Kelebihan dari program yang dibuat dengan menggunakan bahasa Java adalah dapat berjalan pada platform yang berbeda, seperti mottonya, “Write Once, Run Anywhere”. Dalam artikel ini, kita akan menggunakan Java SE versi 6. Versi terbarunya dapat di-download di http://www.java.com. NetBeans adalah IDE (integrated development environment), yaitu sebuah program yang berfungsi sebagai alat bantu bagi programer untuk mempermudah pembuatan program. Semua proses membuat program mulai dari menulis, compiling, debugging, dan packing program dilakukan dengan IDE ini. Dalam artikel ini, penulis mengunakan NetBeans 6.5. Versi terbaru NetBeans dapat diunduh di http://www.netbeans.org.

memiliki atribut dan method masing-masing. Sebagai contoh, dalam game yang akan Anda buat ini akan ada karakter atau monster yang dijalankan. Setiap monster memiliki HP, attack, dan status lainnya. Itulah yang disebut sebagai atribut. Monster tersebut juga bisa berpindah tempat atau menyerang. Kemampuan itu yang disebut method.

Konsep Pemrograman pada Java
Seperti yang telah disinggung sebelumnya, Java adalah bahasa pemrograman OOP. Artinya, semua bagian yang terlibat dalam program direpresentasikan sebagai object. Setiap object akan
Tampilan Final Fantasy Tactic 2, salah satu game strategi pada platform Nintendo DS.

90

KNOW-HOW

CODING

05/2009

Object sendiri merupakan representasi dari suatu class. Ibaratnya class adalah cetak biru (blue print) dari suatu object. Artinya, class akan mendefinisikan atribut dan method yang dimiliki, tanpa harus menentukan nilainya. Class inilah yang akan kita buat dan kita simpan dalam bentuk file java.

Devilish Children
Jika Anda suka bermain game sejenis Grandia, Final Fantasy Tactic, dan Romance of Three Kingdom, pasti tidak akan asing dengan game yang akan Anda coba buat ini. Persamaan dari game tersebut sistem battle antara dua pemain dalam suatu arena yang berpetak-petak. Setiap pemain memiliki setidaknya satu buah karakter yang dapat dimainkan. Karakter tersebut dapat berpindah tempat, menyerang, ataupun menunjukkan kemampuan lainnya. Arena pertarungannya pun bisa bergeser mengikuti kursor yang digerakkan. Bagaimanakah cara pembuatannya? Dalam kesempatan kali ini, penulis akan mencoba membahas salah satu game sejenis yang dibuat oleh penulis, yaitu Devilish Children. Game ini dibuat dengan tujuan sebagai dasar pembuatan game strategi tingkat yang lebih tinggi. Bagian yang dibuat pun hanya pada sesi battle saja. Penulis akan berusaha menjelaskan cara pembuatannya sedetail mungkin, namun penulis menyarankan bahwa sebaiknya Anda mengetahui dasar-dasar pemrograman bahasa Java terlebih dahulu. Semua source termasuk file gambar yang akan digunakan dalam artikel ini juga dapat di-download di blog penulis, dengan alamat http://fauzilhaqqi.blogspot.com.

Untuk membuat project baru, klik menu File à New Project atau klik icon New Project pada Toolbar. Pada jendela New Project, pilih kategori Java dan project Java Application, lalu klik Next. Isi Project Name dengan nama DevilishChildren lalu atur lokasi project dan klik Finish. Secara otomatis, NetBeans akan membuat beberapa subfolder dalam folder DevilishChildren, yaitu nbproject, src, dan test. Folder yang akan sering Anda buka melalui explorer adalah folder src, sebab folder inilah yang menjadi tempat semua file source Anda di simpan. Untuk membuat struktur penempatan lokasi file yang baik, sebaiknya Anda menambahkan beberapa folder lagi. Folderfolder tersebut adalah chara, images, dan map yang akan diletakkan di dalam folder src/devilishchildren. Semua folder tersebut digunakan untuk menyimpan file gambar yang akan digunakan dalam pembuatan game. Folder chara untuk gambar karakter, folder images untuk gambar-gambar umum, dan folder map untuk gambar petak-petak map. Selain itu, buat juga folder chara dan map langsung di bawah folder utama, DevilishChildren. Gunanya adalah untuk menyimpan file yang berisi detail dari sebuah karakter dan map. File ini akan dijelaskan kemudian. Untuk lebih jelasnya tentang penempatan folder, lihatlah pada gambar.
Catatan: Anda bisa membuat sendiri file gambar yang akan digunakan, namun Anda juga bisa menggunakan semua file gambar yang ada dalam blog penulis untuk memudahkan pembuatan game ini.

Class Dasar yang Digunakan
Game ini membutuhkan beberapa class dasar yang harus ada. Masing-masing class memiliki fungsinya sendiri. Untuk membuat class baru, klik File à New File atau klik icon New File pada Toolbar. Pada jendela New File, pilih kategori Java dan tipe file Java Class. Setelah itu, klik Finish. Secara umum, hierarki sebuah class adalah seperti pada listing a. Untuk mempermudah pembacaan, sebaiknya Anda letakkan semua atribut dan variable global di atas constructor. Constructor adalah method yang memiliki nama sama dengan class-nya dan yang akan dijalankan pertama kali saat Anda membuat object dari class tersebut. Sedangkan, method-method lainnya diletakkan di bagian bawah. Sebagai langkah awal, buatlah semua class yang ada di bawah ini.

Aturan Main Game (Game Rules)
Karena game ini hanya sebagai dasar pembuatan game strategi yang sesungguhnya, kita tidak akan membahas terlalu dalam masalah game rule. Sama dengan game tactic yang lain, game ini lebih ke arah Turn-Based Strategy. Artinya, setiap pemain bergantian memainkan karakter masing-masing yang ada dalam arena permainan. Arena permainannya sendiri berupa petakpetak hexagonal (segi-6). Game ini didesain untuk 2 orang pemain. Setiap pemain memiliki satu karakter yang disebut Hero. Pemain pertama menggunakan Hero bernama Frost (warna biru), sedangkan pemain kedua menggunakan Flare (warna merah). Hero ini memiliki kemampuan untuk memanggil (summon) monster ke arena battle. Untuk memanggil setiap monster membutuhkan Mana yang cukup dari hero tersebut. Jumlah maksimal monster yang dapat dipanggil sesuai dengan jumlah kastil yang dimiliki. Pemain yang mengalahkan Hero lawan terlebih dahulu adalah pemenangnya. Game rules lainnya akan dijelaskan lebih lanjut.

Main
Class ini akan secara otomatis dibuat oleh NetBeans saat Anda membuat project baru. Semua program pasti harus memiliki class ini karena class ini adalah class yang kali pertama dijalankan saat Anda menjalankan program.

Membuat Project Baru dan Mengatur Folder
Sebelum mulai membuat program dengan NetBeans, pertama-tama Anda harus membuat project baru dan mengatur folder-folder yang menjadi tempat penyimpanan semua file Anda.

GameManager
Class ini merupakan inti dari game ini karena class ini menyimpan semua informasi umum yang berhubungan dengan game serta mempunyai method-method dasar yang banyak digunakan dalam game.

Penempatan folder source.

Catatan: Semua penggunaan library Java harus diikuti proses import. Sebuah jendela tentu memiliki atribut panjang dan lebar. Anda tidak perlu menggunakan class ini secara langsung. yaitu: import java. Semua hal yang terdapat di panel map akan diletakkan di class ini. Anda harus membuat object dari class GameManager. informasi karakter dan menu-menu yang digunakan. Jangan lupa untuk melakukan proses import. Untuk mengatur agar lokasi munculnya jendela tepat di tengah layar. Semua hal yang terdapat di panel info akan diletakkan di class ini. . images. Pada langkah sebelumnya Anda telah membuat folder yang nantinya akan menjadi lokasi penyimpanan gambar. dan monster atau karakter yang digunakan. Pembuatan jendela ini sangat penting karena semua bagian game akan ditampilkan dalam jendela ini. sebenarnya adalah object yang dibuat dari class Toolkit dari library Java. Sehingga Anda cukup mengeset beberapa atribut dan menambahkan kode program yang Anda inginkan. Setelah itu. Membuat Jendela Game Tahap berikutnya adalah membuat jendela game menggunakan class GameFrame. kita perlu meng-import class tersebut dengan cara menuliskannya di bagian atas class. Setelah itu. class anda akan mewarisi semua atribut dan method dari class JFrame. kursor. Karena termasuk dalam library Java. Class GameManager Kita mulai penulisan program pada class GameManager. Tapi. Anda cukup mengatur agar class GameFrame milik Anda inherit pada class JFrame. dan map. maka akan muncul beberapa pilihan seperti pada gambar di bawah ini: dapat mengenal lokasi tersebut. Seperti yang telah dijelaskan sebelumnya. yaitu chara. Dalam class ini akan diletakkan 2 buah panel. objek img menyimpan alamat tempat file gambar disimpan. Informasi yang disimpan antara lain adalah gambar setiap petaknya dan karakter yang ada di tiap petak. Bacalah tips cara import library java dengan netbeans.05/2009 CODING KNOW-HOW 91 TIPS: IMPORT LIBRARY JAVA DENGAN NETBEANS Pada saat anda menuliskan public Toolkit. Dalam library Java telah tersedia class JFrame yang merupakan class dasar untuk membuat jendela game.Toolkit. Kegunaan class Toolkit ini sangat banyak.getResource() dengan parameter folder dan nama file. GameFrame juga bertindak sebagai penghubung kedua panel ini. dengan ukuran 800x600. yaitu panel map dan panel info. Informasi yang disimpan tentu saja meliputi atribut dan method yang dimiliki tiap karakter. variable-nya ditulis dengan nama charaFolder. Setelah itu. Anda perlu melakukan sedikit penghitungan. imagesFolder. yang nantinya digunakan untuk load gambar. Dalam listing b. Klik gambar lampu itu. Pada listing c. diantaranya adalah untuk load file gambar yang akan Anda lakukan dengan method loadImage().awt. Jika tidak. class ini berisi variable dan method yang akan digunakan secara global. GameFrame Class ini adalah class yang menjadi window dari program tempat semua hal ditampilkan. Secara otomatis NetBeans akan menuliskan statement import di bagian atas class. Pada method loadImage(). Karena game ini nantinya tidak hanya berjalan InfoPanel Bagian window ini terletak di bagian bawah. diantaranya adalah map. Cara ini juga bisa digunakan untuk proses import yang lain. Agar program Tombol Run Main Project. karena class JFrame terletak pada library Java. Cara cepat import dengan NetBeans. seperti yang terlihat pada listing c. dan mapFolder dengan tipe data String. lakukan pengaturan ukuran dengan memanggil method setSize() di dalam constructor. method akan mengembalikan nilai ke pemanggilnya. Agar file tetap dapat dibaca meskipun folder utama berpindah-pindah. Klik pada pilihan Add import sesuai library yang ingin di-import. HexaMap Class ini menyimpan informasi dari suatu map. Di antaranya. Anda bisa melakukannya lebih cepat tanpa perlu menuliskan statement import terlebih dahulu. MapPanel Bagian dari window yang menampilkan area permainan dibuat dengan class ini. salah satunya adalah method untuk membuka file gambar. Dengan menggunakan NetBeans. akan muncul gambar lampu di sebelah kiri baris tersebut. Anda bisa menggunakan method getClass(). Artinya. Langkah Awal. Caranya adalah dengan menambahkan kata “extends JFrame” di sebelah kanan nama class GameFrame. Variable yang terletak paling atas. Coba Anda lihat pada listing b. atribut tersebut didefinisikan dalam variable frameWidth dan frameHeight. maka program tidak akan mengenali class yang sedang digunakan. Chara Class ini sebagai representasi dari sebuah karakter. buatlah variable yang berisi alamat folder tersebut. Nilai tersebut berupa data gambar yang telah di-load.

di satu komputer saja. klik icon Run Main data dari object class HexaMap. Jika jendela berhasil ditampilkan dan terletak tepat di mendapatkan gambar tersebut? Untuk itu. Untuk lebih jelasnya. Atribut lain yang dimiliki adalah panjang dan lebar arena yang bisa didapatkan dengan method getWidth() dan get Height() yang mengemMencoba Menjalankan Program balikan ukuran array.92 KNOW-HOW CODING 05/2009 Membuat Panel Secara garis besar. Jadi. yaitu dengan memanggil method getScreenSize() yang diikuti dengan mengambil nilai panjang dan lebarnya. Anda perlu membuat dua buah panel yang berbeda. Anda bisa Class HexaMap yang Anda buat masih dalam bentuk komulai melakukan tes sederhana dengan menjalankan program. seperti notepad. Class MapPanel Class ini akan menampilkan semua hal yang terjadi di arena pertarungan. Sebelum menjalankan program. jenis tile. Listing g di bawah Project berbentuk segitiga berwarna hijau yang ada ini adalah salah satu contoh method loadMap() yang pada toolbar. Anda perlu membuat tengah layar. Parameter yang dibutuhkan adalah sebuah gambar. Kedua panel tersebut memegang peranan penting. membaca file tersebut dan membuatnya menjadi Untuk menjalankan program. Sebagai contoh. Sebab class Mainmap. Arena pertarungan dibuat dengan menggunakan class HexaMap. Untuk membuat kedua class dari panel tersebut. lihat listing d. Ketikkan definisi tersebut dalam Setelah membuat object. Anda perlu memanggil method loadImage() dari object gm untuk mengambil gambarnya.dc” di ini akan membuat jendela dapat ditampilkan. Seperti yang telah dijelaskan sebelumnya. Anda juga harus memanggil text editor. songan. Class HexaMap . sedangkan method getImage digunakan untuk mengambil gambar yang ada pada koordinat tertentu. artinya sama sekali belum ada informasi gambar yang Jika jendela tidak tampil. Anda perlu membuat object Sebelum itu. bukan di dalam folder src. Anda bisa mengganti icon jendela dengan memanggil method setIconImage(). rameter true. Setelah class GameFrame sederhana telah dibuat. Untuk mendapatkan ukuran tersebut. berarti Anda sudah melakukannya dengan benar. setidaknya menyimpan informasi gambar dari map tersebut. arena pertarungannya berupa petak-petak heksagonal. Anda tinggal membuat method untuk akan berhenti. lihatlah method setVisible() dari object tersebut dengan papada listing f. Untuk memperindah tampilan jendela. Anda tinggal inherit pada class JPanel yang tersedia dalam library Java. method untuk load map tersebut. Anda bisa menggunakan array dua dimensi dari object tileImage yang dibuat dari class Image dari library Java sebagai tempat penyimpanan gambar. Anda tinggal menghitung lokasi dengan rumus seperti pada listing. sedangkan method setDefaultCloseOperation() akan membuat program otomatis berhenti jika jendela tertutup. Karena map ini berjenis tile map. sebelum Anda membuat MapPanel. panggil juga method setResizeable() dengan parameter false. false dan jendela tidak akan ditampilkan lalu program Setelah itu. Jika dalam folder map yang langsung berada di bawah tidak mengeset true. Setelah itu. panel-panel tersebut dibuat dengan class MapPanel dan InfoPanel. Coba Anda berpikir sejenak. Artinya. Untuk itu. kita menggunakan object kit dari class Toolkit yang ada pada object gm. bagaimana object dari class HexaMap nantinya tepat. Anda harus mengatur definisi dari sebuah dari class GameFrame di dalam class Main. Sebuah map sederhana. Pemanggilan method setTitle() digunakan untuk mengganti judul jendela. berarti program Anda masih kurang disimpan. Pembagian panel dalam . Seperti yang dijelaskan sebelumnya. Lalu aturlah lokasi jendela dengan memanggil method setLocation(). Method setImage() digunakan untuk menyimpan gambar. Buatlah method loadMap() tersedengan menekan tombol F6. Dengan parameter true artinya method Simpan file tersebut dengan nama “Map. apa saja yang ada dalam arena pertarungan. termasuk castle. Anda perlu untuk mengetahui ukuran layar monitor tempat game ini dijalankan. anggap saja ada 5 lah yang akan dijalankan kali pertama saat program dijalankan. terpisah dalam sebuah file. agar ukuran jendela tidak dapat diubah. Definisi ini sebaiknya diletakkan Untuk lebih jelasnya. Anda harus membuat arena pertarungannya dahulu. Index dari array tersebut yang nantinya digunakan sebagai koordinat. bagian atas yang menampilkan arena pertarungan dan bagian bawah yang menampilkan infoinfo sesuai event yang terjadi. tempat menampilkan gambar dalam game ini terbagi menjadi dua bagian. maka nilai default-nya adalah folder utama. yaitu sebagai container atau tempat semua object lain berinteraksi. Anda juga bisa menggunakan shortcut Ukuran dari tile segi-6 dibuat oleh penulis. coba Anda lihat pada listing e. Hal terpenting yang harus ada adalah arena pertarungan itu sendiri. yang dibutuhkan. Setelah mendapatkan ukuran layar. Tapi.

object infoSize digunakan untuk menyimpan dimensi ukuran yang akan dimasukkan sebagai parameter saat memanggil method setPreferredSize().05/2009 CODING KNOW-HOW 93 Sistem koordinat map segi-6. dalam hal ini contohnya adalah file yang digunakan tidak dapat ditemukan atau dibuka. Anda perlu mengerti bagaimana konsep menampilkan arena yang berupa segi-6 beserta sistem koordinatnya. setiap huruf dalam file tersebut mewakili setiap petak sesuai koordinatnya. Sebelum mulai menampilkan gambar. Anda perlu memberikan statement try dan catch IOException di bagian terluar. Perbedaan dengan class MapPanel adalah pengaturan ukuran panel. Cara mudah untuk membuatnya adalah klik kanan pada editor. Anda perlu membuat method paintComponent(). kita bisa mendapatkan nilai tinggi dan lebar gambar dengan mudah. Dengan sedikit perhitungan trigonometri. Class InfoPanel Cara pembuatan panel ini tidak jauh berbeda dengan panel sebelumnya. Setelah jendela Override Method muncul. Setelah itu. Gambar kursor disimpan dalam object curImg. Jangan lupa juga untuk mengatur warna background dari panel ini. Gunanya adalah pada saat Anda membutuhkan proses scrolling (penggeseran) map. Parameter standar yang dibutuhkan berturutturut adalah gambar. Anda harus menentukan tinggi panel sesuai ukuran gambar dari panel info. sehingga akan terasa lebih mudah. Setelah itu. setelah itu buatlah class MapPanel seperti pada listing h. Namun. cari method paintComponent() pada kategori JComponent. Method ini menggunakan metode pembacaan file yang sudah Anda ketik sebelumnya. Pada baris kedua. cukup mengalikan koordinat dengan nilai p. Shorcut-nya adalah tekan Alt+Insert. Coba Anda lihat pada gambar segi-6 dengan lebar sebesar r. Baris berikutnya tidak tepat di bawah batas tinggi hexagonal di atasnya. Coba Anda lihat pada gambar sistem koordinat map segi-6. Jangan lupa juga untuk melakukan proses import seperti sebelumnya. dan lokasi kursor disimpan dalam variable curPosX dan curPosY. Setelah itu. lokasi pixel X. Untuk itu kita menggunakan method tileXToPixel() untuk mendapatkan nilai lokasi X sesuai nilai Y-nya. Tapi untuk apa nilai p tersebut? Setelah mendapatkan nilai p. Jadi. maka akan ditemukan nilai p adalah ¾ dari tinggi segi-6. yaitu 180 pixel. lokasi X sedikit berubah. Java menampilkan gambar dengan satuan pixel. untuk melihat apakah hasilnya sesuai Anda perlu memasang panel-panel itu ke dalam class GameFrame. Tulislah seperti listing h dan pahami sampai Anda mengerti. Nah.getProperty(“user. Coba Anda pahami terlebih dahulu sistem koordinat tersebut. karena di dalam method ini banyak mengandung library Java yang belum Anda import sebelumnya. pilih Insert Code lalu klik pada pilihan Override Method. ada sedikit perhitungan kecil untuk mendapatkan nilai p yang nanti akan digunakan untuk mengatur letak petak-petak sesuai koordinatnya. Bentuk awal class ini adalah seperti pada listing i. Menampilkan Arena Langkah berikutnya adalah menampilkan arena pada jendela. Dalam class ini. selama file yang digunakan masih lengkap. Tapi tidak demikian dengan lokasi X seperti yang telah Anda lihat pada gambar sistem koordinat sebelumnya. Gunanya adalah menangkap kesalahan-kesalahan program yang disebabkan masalah inputoutput. Untuk menampilkan gambar pada panel. Tambahkan kode di bawah . karena bentuk map segi-6 tidak simetris seperti halnya map persegi. dan observer. Caranya. Anda cukup memanggil method drawImage() dari object g yang diletakkan dalam perulangan for. Variable tileOffsetX dan tileOffsetY digunakan sebagai titik awal penggambaran pada jendela. Tapi hati-hati. Untuk mendapatkan lokasi Y sangat mudah. Anda tinggal mengubah nilai variable tersebut. Method tersebut harus Override dengan method aslinya yang dimiliki class JPanel. ganjil atau genap. object dari class HexaMap harus dibuat terlebih dahulu. Variable r adalah lebar dari gambar tersebut. untuk mulai menggambar petak pada panel. but di dalam class GameManager. lokasi pixel Y. Gunanya adalah untuk membuat program bisa dijalankan di folder manapun meskipun dipindah-pindah. Listing h tersebut sekaligus menampilkan kursor yang nantinya akan digunakan dalam permainan. Sebelum itu.dir”) akan mengembalikan nilai berupa alamat folder dimana program berjalan. pertama-tama deklarasikan object dari masing-masing panel. Terlihat ada perbedaan letak baris pertama dengan berikutnya. Teknik ini akan dijelaskan kemudian. itulah guna dari nilai p. Method System. Object yang digunakan untuk membaca file adalah reader dari class BufferedReader. Gambar yang perlu ditampilkan tidak terlalu banyak. Dari suatu file gambar. Menambahkan Panel ke GameFrame Setelah Anda membuat kedua panel tersebut. di dalam constructor Anda harus memanggil method loadMap() dari object gm untuk inisialisasi object map. Anda tinggal meletakkannya sesuai koordinat tiap petak. tapi terletak pada satuan p.

Setelah itu. Penulis juga akan membahas pembuatan program untuk menerapkan aturan main dalam game ini. BorderLayout.frameWidth)/2. ip = new InfoPanel(). Method setLayout() akan mengatur layout dari jendela. import java.URL.net. private static MapPanel mp. add(ip. } } GameFrame gf = new GameFrame(). jika berhasil maka akan muncul tampilan seperti pada contoh sebelumnya.height. setLocation((scrWidth . inisialisasi object tersebut pada bagian paling atas dari constructor class GameFrame dengan menambahkan kode di bawah ini: mp = new MapPanel(). setTitle(“Devilish Children”). public static final int frameHeight = 600. } public static final String charaFolder = “chara/”.getImage(img). Listing b package devilishchildren. } } //nama class public class Coba { //tempat atribut String nama. import javax. Coba Anda jalankan program Anda.imagesFolder. public GameFrame() { setSize(frameWidth.94 KNOW-HOW CODING 05/2009 ini pada tempat variable global di class GameFrame. gf. serta menambahkan karakter dan menjalankannya. private static InfoPanel ip.CENTER). Panel map diletakkan pada layout tengah.SOUTH).width. Pada bagian selanjutnya penulis akan membahas tentang bagaimana cara menjalankan kursor. setIconImage(gm. public class GameFrame extends JFrame { //constructor public Coba() { } public static final int frameWidth = 800. //method public void serang() { } //method lainnya } private final int scrWidth = gm. return kit. public static final String imagesFolder = “images/”. dalam hal ini kita menggunakan BorderLayout.awt.kit. private final int scrHeight = gm. import java. setResizable(false). BorderLayout. “icon.getScreenSize().png”)). //variabel lainnya Listing c package devilishchildren. Listing d package devilishchildren.frameHeight)/2). public class GameManager { public final Toolkit kit = Toolkit. sedangkan panel info pada layout bawah. private GameManager gm = new GameManager(). public class Main { public static void main(String[] args) { public Image loadImage( String folder. Jangan lupa untuk melakukan proses import pada class BorListing a //nama package package devilishchildren. . public static final String mapFolder = “map/”. karena class itu baru saja digunakan pada penambahan kode ini.getScreenSize().JFrame. } setDefaultCloseOperation(JFrame .loadImage(GameManager .setVisible(true).Image.Toolkit. derLayout. (scrHeight . add(mp. import java.EXIT_ON_CLOSE).getResource(folder + name).kit.swing. setLayout(new BorderLayout()). String name) { URL img = getClass() . frameHeight). scrolling map.getDefaultToolkit().awt.

“tileSand. int y.getProperty(“user. //2 loadImage(mapFolder. x < width. for(int x = 0. x++) { char ch = line. int height) { tileImage = new Image[width][height]. } } } } } width = Math. catch (IOException iOException) { Listing f-Definisi Map Map percobaan Devilish Children #Baris yang diawali tanda # adalah komentar #Detail: #F = Forest #G = Grass #S = Sand #W = Water #C = Castle FFFFGGGGGFFFFSSSSSWFWWWFFF FFCGGGGFFFCSSSSSWWWWWGGGCS GGGGSSSSFFWWWWSSSSFWWGGFFF GFSSSSSCFFFWFSCSSGGCGGGFFF GSSFFFFFGGFFFFSSSSSSFGGFFF SSSCSFFFFFFFFFFGGGGGGGCGFG WFWWFFFFFFFWCWWWSSSSFGGFFF WWSSSFFFGGCGWCFFSSSGGGGFFF WSSWWWFFFFGGCSGGGGSSWWWSSF WWWSFFFGFGWWWWSSSSSSSSSFFS FFFFGGGCWSSSSGGGGGCWFWWSSF } System. y < height. “tileWater. int width = 0. } } break. public Image getImage(int x.max(width.png”). break. break.add(line).getCause()). switch(ch) { case ‘F’: index = 0.out.awt.dir”) + File. loadImage(mapFolder.startsWith(“#”)) { lines.png”). }. Image img) { tileImage[x][y] = img. //1 import java.length. case ‘S’: index = 2. Listing g-Load Map public HexaMap loadMap(String name) { ArrayList lines = new ArrayList(). height = lines. break.Image. public int getWidth() { return tileImage. int height = 0. } try { BufferedReader reader = new BufferedReader( new FileReader(new File(path))).length. int index.png”). “tileGrass.size(). case ‘G’: index = 1.png”) //4 public HexaMap(int width. } String path = System. if (!line. line.readLine().get(y). Image[] tileImage = { loadImage(mapFolder.println(iOException.charAt(x). height). //3 public class HexaMap { private Image[][] tileImage. HexaMap newMap = new HexaMap(width. if (line == null) { reader. public int getHeight() { return tileImage[0]. loadImage(mapFolder. case ‘C’: . “tileForest. //0 loadImage(mapFolder. int y) { return tileImage[x][y]. case ‘W’: index = 3. break. y++) { String line = (String)lines.separatorChar + mapFolder + name.05/2009 CODING KNOW-HOW 95 Listing e-HexaMap 1 package devilishchildren. public void setImage(int x.png”). } while (true) { String line = reader. “castleGray. for(int y = 0.length()).close().

Java.JPanel.de for(int y = 0. import java. www.loadImage( GameManager. g. y). 0. “cursor. private final int margin = 20. } } return newMap.dc”). curPosY) + tileOffsetX * r + margin . private Dimension infoSize = new Dimension(). this).Image. private HexaMap map. import javax. setBackground(Color. private Image infoImg = gm. import java. private final int p = 64 * 3 / 4.getWidth(). public InfoPanel() { public MapPanel() { map = gm. g. Listing h-Map Panel package devilishchildren. public static final int infoHeight = 180.imagesFolder.java. curPosY * p + tileOffsetY * p import java. “info.2.Color. } } infoSize. y < map. O’Reilly.getImage(x. g. tileXToPixel(curPosX.png”).2.net Forum. http://forums.frameWidth.Graphics.png”).drawImage(map. } } @Override protected void paintComponent(Graphics g) { super. } @Override protected void paintComponent(Graphics g) { super. } } + margin . y.96 KNOW-HOW CODING 05/2009 index = 4.awt. break.swing. GameManager. import java.setImage(x.awt. May 2005.drawImage(infoImg. for(int x = 0.Image. Killer Game Programming in Java.net Java Game Programming Tutorial.paintComponent(g).JPanel.Graphics.loadMap(“Map. 0. public class InfoPanel extends JPanel { private GameManager gm = new GameManager(). import java. private int curPosY = 0. if(y % 2 != 0) { width += r / 2. pixelX. } } } + margin. private int curPosX = 0.BLACK).awt. y) + tileOffsetX * r + margin.getHeight().awt. infoHeight). int y) { int width = x * r.imagesFolder.setSize(GameFrame. } return width.loadImage( private int tileOffsetX = 0.paintComponent(g). import java.drawImage(curImg. } newMap. import javax. private final int r = 56.awt.Dimension. x++ ) { int pixelX = tileXToPixel(x. this). Andrew. default: index = 0. private Image curImg = gm. package devilishchildren.awt. public int tileXToPixel(int x. Listing i-Info Panel public class MapPanel extends JPanel { private GameManager gm = new GameManager(). this). break. gmxhome.javacooperation. LEBIH LANJUT Davidson. x < map.swing. private int tileOffsetY = 0. setPreferredSize(infoSize). pixelY. tileImage[index]). y++) { int pixelY = y * p + tileOffsetY * p .

Menggerakkan Kursor Untuk menggerakkan kursor. yaitu dari keyboard. Cek lagi apakah kursor yang dipindah keluar dari ukuran tampilan panel map. Logika yang perlu dilakukan program setiap program mendapatkan keyCode akibat user menekan tombol adalah: 1. Anda dapat mengklik pada gambar bola lampu. 2. kanan. Devilish children hanya menggunakan input dasar saja. library Java memudahkan kita untuk membuat class tersebut. dan keyRe- Gambar 1..106 KNOW-HOW CODING 06/2009 MEMBUAT GAME STRATEGI SEDERHANA MENGGUNAKAN JAVA DAN NETBEANS BAGIAN 2 DARI 3 ARTIKEL Di seri kedua ini. tapi cukup diletakkan dalam class yang membutuhkan event dari keyboard tersebut. sampai dengan beberapa method penting dalam game Devilish Children ini. Jika ya. Jika tidak. Sekali lagi. yaitu keyTyped(). Anda juga harus melakukan implements ke semua abstract method yang dimiliki class KeyListener. Artinya. Anda harus membuat inner class tersebut di dalam class MapPanel. Cara cepat implement abstract method. serta. Kita akan memulainya dari bagaimana cara menggerakkan kursor. leased(). yaitu Frost dan Flare. Sebuah class yang diletakkan dalam class dinamakan inner class. kita akan berurusan dengan tokoh utama game ini. pada bagian kedua ini penulis akan membahas mulai dari bagaimana cara membuat scrolling map. Fauzil Haqqi SETELAH berhasil membuat tampilan dasar.. untuk menjalankan event dalam MapPanel. Tulis listing a ke dalam class MapPanel. Kita akan menamai class tersebut dengan nama MapControl. . Cek apakah kursor ada di tepi map. dan kiri saja. sama dengan cara melakukan import pada NetBeans. variable tersebut di-switch untuk menentukan aksi apa yang harus dijalankan program. Setelah itu. Class tersebut tidak perlu dibuat terpisah. Anda hanya perlu menangkap kode dari panah atas. keyPressed(). bawah.monster dan kastilnya! Windra Swastika & M. Variable keyCode menyimpan nilai berupa kode tombol yang sedang ditekan. Setelah proses import class KeyListener. maka tidak akan dilakukan apa-apa 3. posisi kursor dipindah sesuai arahnya dengan mengubah nilai variable curPosX atau curPosY. class tersebut harus mampu mendeteksi tombol-tombol apa yang ditekan pengguna pada keyboard. Anda harus membuat class yang berfungsi untuk menangkap event dari keyboard anda. Caranya adalah dengan implements pada class KeyListeners. Untuk melakukannya lebih cepat. Jadi.

bject mc tersebut belum menjadi Listener dari class MapPanel. Anda bisa menggunakan enumeration pada Java. Karakter utama yang digunakan. Coba Anda jalankan program buatan Anda. panggil repaint() untuk mengulang proses penggambaran terhadap object gambar yang berubah secara otomatis. posX. maka semua titik awal penggambaran diubah dengan mengubah nilai variable tileOffsetX atau tileOffsetY. pemain pertama mengGambar 3. Anda bisa membuat variable yang menandakan pemain mana yang sedang mendapat giliran bermain. posY. dengan menambahkan kode di bawah ini: private MapControl mc. Di antaranya adalah jumlah monster yang dimiliki pemain. Semua informasi tersebut harus statis. maka semua class juga membaca hasil perubahan yang terjadi. berarti program Anda sudah benar. Frost dan Flare memiliki atribut berupa mana. Enumeration ini hampir sama seperti class. 4. tulis listing b di dalam file enumeration tersebut. hanya saja dia berfungsi layaknya tipe data buatan Anda sendiri. Setelah Anda membuat inner class MapControl. Untuk mendeteksi apakah kursor ada di tepi map. Jika ya. Gambar 2. sesuai ide awal bahwa semua hal yang bersifat global akan diletakkan pada class ini. Anda tinggal mengecek koordinat kursor apakah ada di antara 0 sampai ukuran map. setFocusable(true). Variable tersebut diletakkan di dalam class GameManager untuk lebih memudahkan. dengan memanggil method getWidth() atau getHeight pada object map. addKeyListener(mc). lokasi hero pemain. Jika Flare sedang mendapat giliran kemudian memanggil method ini. klik New File lalu pilih Java Enum. Setelah itu. maka giliran berganti ke Frost. Untuk itu. tambahkan kode di bawah ini dalam constructor class MapPanel: mc = new MapControl(). Kemudian Anda juga bisa membuat method untuk mengganti giliran bermain dengan menambahkan listing c ke dalam class GameManager juga. Variable mana akan menyimpan jumlah mana yang sedang dimiliki pemain. Jika informasi tersebut berubah. Mengatur Informasi Pemain Dalam game ini ada dua orang pemain. dan yang lain menggunakan Flare. serta monster menyimpan jumlah monster yang dimiliki pada arena. Dalam listing di atas. mana untuk memanggil monster. Pemain yang Mendapat Giliran Setelah membuat enum dari pemain. Jadi. 5. Setiap pemain memiliki jenis informasi yang sama. tambahkan baris di bawah ini di lokasi atribut dalam class GameManager: public static Player turn. . tidak tergantung pada lokasi di mana object tersebut dibentuk. Jika tidak. Simpan dengan nama Player. Setelah itu. castle. dan jumlah kastil yang dimiliki. jika kursor bergerak saat Anda menekan tombol panah. Sebuah monster yang dibuat dari class Meskipun sudah membuat object untuk mendeteksi event keyboard. Artinya kapanpun dan apapun class yang mengakses informasi dari tiap player. Untuk mengaturnya. Langkah program menggerakkan kursor. Anda perlu mengecek ulang apakah yang Anda lakukan sudah sesuai. Begitu pula sebaliknya. maka langsung menuju poin 5. Membuat Monster Langkah berikutnya adalah mengisi class Chara yang telah Anda buat sebelumnya. Jika tidak. Untuk membuatnya. Method tersebut akan mengecek siapakah pemain yang sedang mendapat giliran. castle akan menyimpan jumlah kastil yang dimiliki. posX dan posY adalah posisi hero pemain. hasilnya selalu sama.06/2009 CODING KNOW-HOW 107 gunakan hero Frost. langkah berikutnya adalah membuat object tersebut pada class MapPanel sendiri. dan monster.

setOwner(x. area = new boolean[width][height]. di antaranya adalah nama. Anda perlu menambahkan beberapa variable ke dalam class tersebut. true). dan canSelected apakah monster masih bisa dipilih. y++) { for(int x = 0. kemudian fTiamat. Sehingga penulis lebih mudah untuk membuat method loadChara() seperti listing f. dan status-status yang lain. Constructor class ini mengambil parameter sebuah array String. dalam game ini Anda membutuhkan suatu file yang berisi informasi dari monster tersebut dan method untuk me-load isi file ke dalam game. kemudian berturut-turut adalah maximum HP.png untuk file gambar tile monster bernama Tiamat. Setelah itu. private boolean[][] area. y. Array tersebut berisi informasi masing-masing monster yang dipanggil. Sebab lokasi kastil tersimpan pada file detail map. variable area akan digunakan untuk proses aksi berpindah atau menyerang yang dilakukan monster. Anda bisa melihatnya lagi pada bagian 1 artikel ini. chara = new Chara[width][height]. private Player[][] owner. owner = new Player[width][height]. Penulis membuat nama tTiamat. dan jangkauan menyerang. newMap. yaitu: private Chara[][] chara. Memanggil Monster Sama seperti load map sebelumnya. AP (Attack Poin). Anda dapat menyimpannya sesuai nama monster dengan ekstensi . attack. Artinya. newMap.png untuk file gambar face-nya. Nama file gambar tersebut sebaiknya mengandung nama monster itu sendiri. atribut dan method semua monster sama persis. Kita tidak perlu membuat subclass yang berbeda untuk setiap monster. HP (Health Poin). Anda bisa menggunakan perulangan sederhana seperti baris di bawah ini: public void setAreaFalse() { for(int y = 0. gambar yang digunakan. defend. serta variable owner menentukan siapa pemilik kastil tersebut. x++) { TABEL KOORDINAT RELATIF SISI-SISI PETAK SEGI-6 SISI Kanan Atas Kanan Kanan Bawah Kiri Bawah Kiri Kiri Atas Y = GENAP X Y 0 -1 +1 0 0 +1 -1 +1 -1 0 -1 -1 Y = GANJIL X Y +1 -1 +1 0 +1 +1 0 +1 -1 0 0 -1 Menambahkan Kastil dan Area Kembali ke class HexaMap. face berisi gambar wajah monster yang akan ditampilkan di panel info.chara. private boolean[][] castle. castle = new boolean[width][height]. Variable-variable tersebut akan berfungsi pada saat mengontrol monster menggunakan keyboard. Sampai dengan langkah ini. null). variable castle untuk menandakan ada tidaknya kastil dalam koordinat tertentu. karena setiap monster tidak memiliki atribut-atribut unik yang tidak dimiliki monster lain. dalam contoh di atas adalah Tiamat. Anda akan memasuki tahap yang lebih spesifik. Anda harus banyak berpikir tentang apa saja yang mungkin terjadi dalam game dan bagaimana algoritma pemecahan masalahnya. Yang harus Anda tambahkan adalah baris di bawah ini ke dalam switch dengan case ‘C’ (kastil). x < getWidth(). canAttack apakah bisa menyerang. Listing d adalah contoh class Chara yang sederhana yang digunakan dalam pembuatan game ini. penulis cukup menggabungkan parameter nama monster yang dipanggil dengan ekstensi chara untuk mencari file informasi. y. Begitu juga dengan file gambar yang nanti digunakan oleh setiap monster. Variable castle dan owner harus terdefinisi sejak map di-load untuk pertama kali. Setelah itu. HP saat ini. Seperti sebelumnya. Anda juga harus membuat method set dan get dari variable di atas seperti pada listing g. Untuk itu. jangkauan berpindah. Method Khusus Class HexaMap Berikutnya. Variable canMove menandakan apakah monster bisa bergerak. Selain itu juga dibutuhkan informasi ada tidaknya monster dalam . inisialisasi variable di atas dalam constructor dengan menambahkan baris berikut ke dalam constructor. Untuk method setArea akan dibuat dan dijelaskan tersendiri karena ada metode khusus untuk menentukan area jangkauan perpindahan monster maupun area serangan monster tersebut.setCastle(x. Anda akan memerlukan method untuk me-reset area menjadi false semua setiap monster selesai melakukan aksinya. meskipun nama dan gambar monster tersebut berbeda satu sama lain. kita menemukan kasus bahwa dalam class HexaMap harus terdapat informasi tentang di manakah kastil berada dan milik siapa. Variable chara menyimpan informasi monster sesuai koordinatnya. Anda bisa membuat file informasi tersebut seperti pada listing e untuk setiap monster. pemiliknya. dan menggabungkan dengan huruf f atau t dengan ekstensi png untuk file gambarnya. y < getHeight(). chara. Method tambahan lain adalah isAlive() yang nanti akan digunakan untuk mengecek apakah monster tersebut masih hidup atau sudah mati. ada method yang berfungsi untuk mengubah nilai dan ada yang berfungsi untuk mendapatkan nilai dari masing-masing variable. name adalah nama monster.108 KNOW-HOW CODING 06/2009 Chara setidaknya memiliki beberapa atribut. suatu area serta status area apakah boleh dipilih saat monster berpindah tempat atau melakukan serangan. Seperti yang dijelaskan sebelumnya. Dalam pembuatan sebuah game. tile berisi gambar monster yang akan ditampilkan di map. Seperti biasa. Variable owner berisi pemilik monster tersebut.

06/2009 CODING KNOW-HOW 109 area[x][y] = false. melakukan perpindahan. Ada 4 sisi dengan rumus sama dan 2 sisi dengan rumus berbeda. untuk melakukan pengecekan. public void resetAllChara() { for(int y = 0. } } Area Perpindahan Monster Rumus koordinat relatif sebelumnya juga digunakan untuk menentukan area perpindahan monster ini. Anda perlu mendapatkan lokasi hero yang sedang mendapat giliran. public boolean isChara(int x. } if(map. Untuk itu.isArea(x. Namun untuk area serangan. jika area perpindahan maka yang dihitung adalah jumlah langkah yang dilakukan monster. Artinya. Untuk saat ini.changeMonster(-1). artinya method ini memanggil dirinya sendiri dan akan berhenti pada kondisi tertentu. Variable pX dan pY menyimpan lokasi tersebut. pixelY. Anda bisa menggunakan method setMoveArea() seperti pada listing I. Anda perlu membuat method seperti di bawah ini di dalam class HexaMap juga. Kemudian dicek lagi apakah dalam radius tersebut terdapat monster milik lawan. method ini menggunakan metode rekursif. Penghapusan tersebut juga akan menambah jatah monster yang dapat dipanggil oleh pemain yang kehilangan monster tersebut. Sebelum melakukan pengecekan.isAlive()) { chara[x][y]. } return false.setCanAttack(true). } } } Anda juga memerlukan method sederhana untuk mengetahui apakah dalam koordinat tertentu terdapat monster atau tidak. Anda harus menghitung koordinat petak-petak di ke-6 sisi tersebut relatif terhadap petak utama. Method ini akan dipanggil setiap kali proses penyerangan yang dilakukan suatu monster berjalan.getTile(). Jika ada. y)) { chara[x][y]. Berikut tabel koordinat relatif sisi-sisi petak segi-6. pixelX. x < getWidth(). maka area perpindahannya harus diatur sedemikian rupa. Pada method ini. Untuk itu. if(map. Cara yang digunakan hampir sama dengan cara mengatur area . chara[x][y]. Dalam game ini. chara[x][y] = null. Anda bisa menggunakan listing h. lokasi pemanggilan adalah di sekitar hero yang sedang mendapat giliran.setCanSelected(true). dan menyerang. status monster harus dikembalikan lagi. Karena monster memiliki kemampuan berpindah tempat sesuai jangkauan langkahnya. this). Menampilkan Monster dan Area Kembali ke class MapPanel. kemudian jika bisa.isChara(x. di dalam map belum terdapat satupun monster atau area yang sudah di-set sebagai area perpindahan maupun area serangan. y++) { for(int x = 0. Caranya adalah dengan menggunakan metode rekursif. } perpindahan monster. int y) { if(chara[x][y] != null) { return true. y) . } } } } Area Pemanggilan Monster Sebelum menampilkan menu pemanggilan monster. Menghapus Monster yang Mati Monster dengan HP nol harus dikeluarkan dari arena. Permasalahannya adalah terdapat rumus sisi-sisi yang berbeda antara baris ganjil dan genap. Anda cukup mencari dalam radius jangkauan serangan saja. Namun ada sedikit perbedaan dalam menangkap kondisi yang terjadi. chara[x][y]. Mereset Status Monster Setiap pergantian giliran. Dengan sedikit analisa sederhana.getOwner(). Perbedaan tersebut adalah. maka monster lawan tersebut termasuk dalam area serangan. Anda tentu perlu mengecek apakah kursor ada di lokasi pemanggilan yang ditentukan. maka dia memanggil dirinya sendiri dan menganggap sisinya sebagai petak utama lagi. y < getHeight(). Seperti yang telah dijelaskan sebelumnya. jika sisi petak utama bisa ditempati. sampai dengan jangkauan monster yang akan dipindah. Tapi mau tidak mau Anda harus bisa menampilkan monster dan area tersebut pada langkah-langkah berikutnya.setCanMove(true). Anda tinggal menambahkan kode untuk menampilkannya di dalam method paintComponent() yang ada di class MapPanel. y)) { Area Serangan Monster Berikutnya adalah bagaimana cara mengatur area serangan monster yang sedang dalam kondisi akan menyerang. Setiap petak mempunyai 6 sisi.getChara(x. Setiap sisi petak dicek apakah bisa ditempati atau tidak. monster harus bisa dipilih. Coba Anda lihat pada listing j di bawah ini. y)) { g. Anda harus mencari rumus lokasi sisi-sisi suatu petak.drawImage(map. Setelah itu. Untuk itu Anda cukup menambahkan method seperti baris di bawah ini: public void setDeath(int x. x++) { if(isChara(x. tanpa perlu menghitung langkah berbelok seperti pada area perpindahan. Anda bisa menemukan sesuai kode di listing h sebelumnya. maka dicek lagi sisi petak tersebut sampai dengan jangkauan si monster. int y) { if(!chara[x][y].

if((curPosY + tileOffsetY + 2) * p > GameFrame. Baris berikutnya akan diletakkan pada layer di atasnya.VK_RIGHT: if(curPosX + 1 < map.1 >= 0) { --curPosY. Artinya. public int getPosX() { return posX.castle += castle. case KeyEvent. Flare. if(curPosX + tileOffsetX == -1) { ++tileOffsetX. public void setPos(int posX. public int getPosY() { return posY.png”). } public void keyTyped(KeyEvent e) { } } public void keyPressed(KeyEvent e) { int keyCode = e. pixelY. } repaint().mana += mana.infoHeight) { --tileOffsetY. switch(keyCode) { case KeyEvent. case KeyEvent. pixelX. penulis akan menjelaskan pembuatan sistem pertarungan dan method-method lanjutan yang digunakan dalam pertarungan dalam game Devilish Children ini. begitu seterusnya. } } } } } } public void keyReleased(KeyEvent e) { } Listing b package devilishchildren.frameWidth) { --tileOffsetX.posY = posY. “tileArea.getHeight()) { ++curPosY.mapFolder.frameHeight .VK_UP: if(curPosY .1 >= 0) { --curPosX.posX = posX. } } break. this). private int posY. public int getMana() { return mana. private int monster.InfoPanel. Pada bagian berikutnya. public enum Player { Frost. } } break. } } break.VK_LEFT: if(curPosX . if(curPosY + tileOffsetY == -1) { ++tileOffsetY. } Kode tersebut harus diletakkan di dalam perulangan dan di bawah baris yang menampilkan petak-petak map. int posY) { this. default: break. private int posX.getWidth()) { ++curPosX. if((curPosX + tileOffsetX + 2) * r > GameFrame. } } break. public void changeMana(int mana) { this.drawImage(gm.getKeyCode().loadImage(GameManager .110 KNOW-HOW CODING 06/2009 g. private int castle. public int getCastle() { . penggambarlisting a private class MapControl implements KeyListener { an dimulai dari baris paling atas sehingga baris tersebut terletak pada layer paling bawah. public void changeCastle(int castle) { this. karena proses penggambaran dalam method ini linear. this. case KeyEvent.VK_DOWN: if(curPosY + 1 < map. private int mana.

Frost.parseInt(detail[3]). private boolean canMove. } import java.canSelected = canSelected. private int ATK.parseInt(detail[6]).face = face. Listing c public static void changeTurn() { if(turn == Player. private boolean canAttack. } public int getATK() { return ATK. } this.canMove = canMove. DEF = Integer. } } } public int getATKr() { return ATKr. ATKr = Integer. private Image face.owner = owner.Flare) { turn = Player.Flare. } public void setCanAttack(boolean canAttack) { this. private int ATKr.tile = tile. name = detail[1].Image. public boolean isCanAttack() { } public Image getFace() { return face.HP += HP. } } public void setFace(Image face) { public void changeMonster(int monster) { this. } Listing d package devilishchildren. . } public int getMOVr() { return MOVr.parseInt(detail[4]). public void setCanMove(boolean canMove) { this. private String name. private int mana. } } public void changeHP(int HP) { this. public int getDEF() { return DEF. private int HP. } this. canSelected = false.parseInt(detail[5]). public int getHP() { return HP. } } } public void setOwner(Player owner) { this.06/2009 CODING KNOW-HOW 111 return castle. private Image tile.canAttack = canAttack.monster += monster. private int DEF. private int maxHP.parseInt(detail[2]).parseInt(detail[0]). canMove = false. } this. MOVr = Integer. private boolean canSelected. public Chara(String[] detail) { mana = Integer. private int MOVr. ATK = Integer. } public void setTile(Image tile) { public int getMonster() { return monster. } else { turn = Player. canAttack = false.awt. public void setCanSelected(boolean canSelected) { public class Chara { private Player owner. maxHP = HP = Integer.

} } catch(IOException iOException) { System.png”)). while(true) { String line = reader. } } detail[++count] = line. “f” + name + “. } int count = -1. } Listing e #Tiamat. Player owner) { this. int y.out. int y) { return castle[x][y]. newChara. } } if(!line. Attack Range #Monster Data 30 Tiamat 850 110 65 5 4 public void setOwner(int x.readLine(). public Player getOwner() { return owner. } public void setChara(int x. ATK. } } charaFolder. break. } Chara newChara = new Chara(detail).png”)). int y) { . Listing f public Chara loadChara(String name) { String[] detail = new String[7]. int y.close(). } try { BufferedReader reader = new BufferedReader( new FileReader(new File(path))). int y) { return chara[x][y].chara #Order: mana needed. } return false.setFace(loadImage( charaFolder. public boolean isCanMove() { return canMove. Move Range. } } Listing g public Chara getChara(int x.getProperty(“user.println(iOException. DEF. public boolean isCanSelected() { return canSelected. public boolean isAlive() { if(HP > 0) { return true. } public boolean isCastle(int x. boolean castle) { this. newChara. “t” + name + “. if(line == null) { public int getMana() { return mana. } } public String getName() { return name.getCause()).castle[x][y] = castle.chara”.startsWith(“#”)) { public int getMaxHP() { return maxHP. } String path = System. int y.owner[x][y] = owner. } public void setCastle(int x.separatorChar + charaFolder + name + “. } public Player getOwner(int x.dir”) + File. reader. name. Chara c) { chara[x][y] = c. return newChara.setTile(loadImage( public Image getTile() { return tile.112 KNOW-HOW CODING 06/2009 return canAttack. max HP.

setMoveArea(range. int y) { int pX = GameManager.turn. y)) { } } } } if(x-1 >= 0 && y-1 >= 0) { if(!isChara(x-1. y)) { if((x == pX+1 && y == pY) || (x == pX-1 && y == pY) || (x == pX && y == pY-1) || (x == pX && y == pY+1)) { return true. } } else { if((x == pX+1 && y == pY-1) || (x == pX+1 && y == pY+1)) { return true. y+1. y-1)) { area[x+1][y-1] = false. . y+1) || chara[x-1][y+1] .getPosX(). int y. y. if(!isChara(x. } } } return false. x-1. setMoveArea(range. y-1) || chara[x-1][y-1] . step).getOwner() == GameManager. } } } if(x+1 < getWidth()) { if(!isChara(x+1.turn) { area[x-1][y] = true. } if(pY % 2 == 0) { if((x == pX-1 && y == pY+1) || (x == pX-1 && y == pY-1)) { return true.turn) { area[x][y-1] = true.turn) { area[x-1][y-1] = true. if(isChara(x. y-1)) { area[x][y-1] = false. } } public boolean isArea(int x.turn) { area[x-1][y+1] = true.getOwner() == GameManager. x.turn) { area[x+1][y] = true. x. int pY = GameManager. if(isChara(x-1. } if(y % 2 == 0) { if(x-1 >= 0 && y+1 < getHeight()) { if(!isChara(x-1. setMoveArea(range. y. if(isChara(x-1. x-1. if(isChara(x+1. } } } } } area[x][y+1] = true.getOwner() == GameManager. x+1. step). step). if(isChara(x+1.getOwner() == GameManager. setMoveArea(range. y-1) || chara[x+1][y-1] .turn) { area[x+1][y-1] = true. y-1. y) || chara[x+1][y] .getOwner() == GameManager. int y) { return area[x][y]. x-1.06/2009 CODING KNOW-HOW 113 return owner[x][y]. if(y-1 >= 0) { if(!isChara(x. y-1. setMoveArea(range. if(isChara(x. y-1. int x. setMoveArea(range. if(isChara(x-1. } } } area[x+1][y] = false. y+1)) { area[x][y+1] = false. x+1. step). step). y+1)) { area[x-1][y+1] = false. y+1) || chara[x][y+1] . int step) { if(step < range) { step++.getPosY(). if(y+1 < getHeight()) { if(!isChara(x. } Listing i public void setMoveArea(int range. step).turn.getOwner() == GameManager. y)) { area[x-1][y] = false. y) || chara[x-1][y] .turn) { Listing h public boolean isSummonArea(int x.getOwner() == GameManager. y+1. } if(x-1 >= 0) { if(!isChara(x-1. y-1) || chara[x][y-1] . step). y-1)) { area[x-1][y-1] = false. setMoveArea(range. } } else { if(x+1 < getWidth() && y-1 >= 0) { if(!isChara(x+1.

de . http://forums. y. y)) { if(chara[x-1][y]. y-1)) { if(chara[x][y-1]. Java. if(x+1 < getWidth() && y-1 >= 0) { if(isChara(x+1. y+1.net Java Game Programming Tutorial. x-1. y-1)) { if(chara[x+1][y-1].turn) { area[x-1][y+1] = true. int step) { if(step < range) { step++. int y.getOwner() != Listing j public void setAttackArea(int range.java. x+1. y+1.getOwner() != GameManager. x. if(x-1 >= 0 && y-1 >= 0) { if(isChara(x-1. y+1.getOwner() != GameManager. y+1)) { if(chara[x-1][y+1]. y+1)) { if(chara[x][y+1]. } if(y+1 < getHeight()) { if(isChara(x. y-1. step). LEBIH LANJUT Davidson. Killer Game Programming in Java. if(x+1 < getWidth() && y+1 < getHeight()) { if(isChara(x+1.114 KNOW-HOW CODING 06/2009 } } } if(x+1 < getWidth() && y+1 < getHeight()) { if(!isChara(x+1. if(y-1 >= 0) { if(isChara(x.getOwner() != GameManager.getOwner() == GameManager. int x.turn) { area[x-1][y] = true. x-1. } } setAttackArea(range. y+1. x+1.getOwner() != GameManager. setAttackArea(range. if(y % 2 == 0) { if(x-1 >= 0 && y+1 < getHeight()) { if(isChara(x-1. x+1. gmxhome.getOwner() != GameManager. y-1. } } setAttackArea(range. y)) { if(chara[x+1][y]. x-1. } } setAttackArea(range. y+1) || chara[x+1][y+1] .turn) { area[x][y+1] = true.net Forum. y. step).turn) { area[x-1][y-1] = true. step). www. step). step).getOwner() != GameManager.getOwner() != GameManager. y+1)) { area[x+1][y+1] = false.turn) { area[x+1][y+1] = true. O’Reilly. if(isChara(x+1. setMoveArea(range. May 2005. } if(x+1 < getWidth()) { if(isChara(x+1.turn) { area[x][y-1] = true. } } } } } } } } } } setAttackArea(range. x+1.turn) { area[x+1][y-1] = true. y-1. } } setAttackArea(range. setAttackArea(range. step). step). y+1)) { if(chara[x+1][y+1]. step). } if(x-1 >= 0) { if(isChara(x-1. Andrew.turn) { area[x+1][y+1] = true.javacooperation. y-1)) { if(chara[x-1][y-1]. setAttackArea(range.turn) { area[x+1][y] = true. x. step). } } } } } } } } } } else { } } } GameManager.

yaitu untuk map dan menu. Anda perlu mengaturnya dalam constructor class MapPanel. Anda harus pikirkan apa saja kondisi-kondisi yang akan terjadi. Dalam game ini. Pertama-tama. terdapat kondisi-kondisi tertentu yang berbeda satu sama lain. Fauzil Haqqi PADA BAGIAN ketiga kali ini. Untuk itu. Menambahkan Hero ke dalam Arena Hero tiap pemain harus sudah ada di dalam arena sejak permainan dimulai. Jika mengikuti semua langkah dengan benar. penulis akan membahas satu demi satu proses event yang terjadi dalam game.112 KNOW-HOW CODING 07/2009 MEMBUAT GAME STRATEGI SEDERHANA MENGGUNAKAN JAVA DAN NETBEANS BAGIAN 3 DARI 3 ARTIKEL Di seri ketiga ini. Coba Anda jalankan program. ada beberapa state yang mungkin terjadi. fungsi tombol Z saat melakukan proses pemanggilan monster berbeda dengan saat melakukan perpindahan monster. Anda perlu mendeklarasikan 2 object state. Event yang disebabkan penekanan tombol tersebut harus ditangkap menggunakan inner class MapControl yang telah Anda buat sebelumnya. Caranya adalah tambahkan listing c ke dalam constructor class MapPanel. Kondisi tersebut dinamakan state. Anda akan berhasil menampilkan hero di bagian pojok arena. public static State menu. Proses penambahan hero sama dengan pemanggilan monster. dan sisa mana yang . Mulai dari penampilan menu pada panel info. Anda akan lebih mengerti kegunaan state tersebut pada langkah-langkah selanjutnya. Penggunaan enum state ini hampir sama dengan enum Player yang telah Anda buat sebelumnya. jumlah kastil. sampai dengan event-event yang dilakukan monster seperti berpindah dan menyerang. Deklarasikan kedua object tersebut dalam area variable di class GameManager. State menentukan apa yang akan terjadi saat tombol utama ditekan. Informasi yang perlu ditampilkan adalah berapa jumlah monster. Membuat State Dalam suatu game. adalah menampilkan informasi dari pemain pada panel info. Selain 4 tombol arah. Listing a adalah salah satu enum state sederhana. kita akan membahas kelanjutan proses pembuatan game “Devilish Children” sampai akhir. State tersebut dapat berupa state dalam panel map maupun untuk menu dalam panel info. Sebagai contoh. hanya saja tidak perlu memenuhi kondisi-kondisi tertentu. Tombol-tombol tersebut adalah huruf Z yang digunakan untuk memilih dan huruf X yang digunakan untuk membatalkan. Menampilkan Info Player pada Panel Info Langkah berikutnya. State ini dapat Anda tentukan sendiri dengan membuat enumeration seperti saat membuat enum Player. public static State map. Windra Swastika & M. game ini menggunakan 2 tombol utama.

Menampilkan Menu Menu dalam game ini akan ditampilkan pada bagian kanan panel info. State Show adalah kondisi saat pemain memilih monster milik lawan atau miliknya sendiri dengan atribut canSelected = false. untuk menggerakkan kursor pada class InfoPanel. Setelah itu. Summon. Anda harus meletakkan listing d di dalam method paintComponent() dari class InfoPanel. Anda cukup menambahkan variable di bawah ini ke dalam lokasi variable global dari class InfoPanel: private Image curImg = gm. Contoh informasi monster saat state menu = Show. Menampilkan Info Monster Pada panel info. Informasi giliran pemain. curMov berisi besar perpindahannya. Listing c adalah kode untuk menampilkan info pemain dan giliran pemain. Sama seperti sebelumnya. bagaimana class InfoPanel dapat menampilkan informasi monster tersebut? Yang perlu Anda lakukan adalah membuat object Chara yang bersifat temporary. state End adalah saat pemain akan menghentikan gilirannya. menu yang ditampilkan sesuai dengan kondisi yang ada. Informasi monster hanya ditampilkan saat state dari menu adalah Show atau Monster. penggambaran informasinya dengan satuan pixel. class InfoPanel tidak memiliki hak untuk mengakses lokasi kursor pada class MapPanel maupun mengakses monster yang sedang ada pada object map dengan koordinat lokasi kursor. Anda bisa memanggil method drawString() milik object g dengan parameter: kata yang ditampilkan. atau End. Maksud dari monster yang sedang aktif adalah monster tersebut sedang dipilih oleh pemain. sedangkan state Attack adalah saat monster melakukan aksi menyerang. jika pemain memilih monster. Artinya monster miliknya sudah tidak dapat melakukan aksi lagi.07/2009 CODING KNOW-HOW 113 Gambar 1. Ada beberapa menu yang bisa ditampilkan. Begitu juga dengan event lainnya. Anda tidak perlu membuat class khusus untuk kursor ini. “menuCur. Karena kursor ini masih sederhana. Seperti yang telah dijelaskan sebelumnya. Begitu pula sebaliknya. public void setActChara(Chara chara) { actChara = chara. Koordinat tersebut adalah lokasi diletakkannya bagian paling kiri bawah dari kata yang ditampilkan. Pada saat kondisi state menu = summon. Misalnya. Letakkan listing e ini di bagian paling bawah method paintComponent() pada class InfoPanel. agar lebih mudah untuk mengetahui siapa pemain yang sedang mendapat giliran. koordinat x. Variable curImg menyimpan gambar kursor. Menggerakkan Kursor Menu Sama seperti pada class MapPanel. perlu ditangkap lagi siapakah pemain yang sedang mendapat giliran untuk menentukan menu pemanggilan. State Summon adalah saat pemain memilih monster yang akan dipanggil ke arena. Penulis menampilkannya pada area penampilan wajah monster. atau saat state dari map adalah Move atau Attack. dilakukan pengecekan giliran pemain. Sebab monster yang dapat dipanggil oleh Frost berbeda dengan yang dipanggil Flare. dimiliki. maka yang ditampilkan adalah gambar Frost. pada state tertentu Anda sebaiknya menampilkan info tersebut.imagesFolder.png”). private int curIndex = 0. Coba Anda lihat pada listing d. private final int curPos = 13. Jika pemain yang menggunakan Frost sedang mendapat giliran. Selain itu. Anda bisa membuat kode penggambaran sederhana seperti listing e. Lalu. maka akan muncul menu aksi monster. Anda juga memerlukan kursor yang berfungsi untuk memilihnya. Anda harus membuat inner class yang Anda juga harus membuat method yang mengeset nilai dari actChara. variable curPos berisi koordinat vertikal awal penggambarannya dalam satuan pixel. State Monster adalah saat pemain memilih monsternya sendiri dan monster tersebut bisa melakukan aksi. saat state map dalam kondisi normal. letakkan di dalam method paintComponent() di class panelInfo. Deklarasikan baris di bawah ini pada lokasi variable di dalam class InfoPanel: Chara actChara. Informasi giliran hanya ditampilkan pada saat State dari object menu sama dengan Normal. Selain menu yang ditampilkan. Namun. Informasi tersebut tampil sesuai pemain yang sedang mendapat giliran. private final int curMov = 40. Sedangkan. State Normal adalah saat tidak ada event tertentu terjadi. Karena menu yang ditampilkan tergantung pada kondisi state menu yang berjalan.loadImage(GameManager . Anda tinggal mengatur lokasi penampilan informasi tersebut. koordinat y. dan curIndex menyimpan lokasi kursor relatif terhadap menu yang ada. . Menumenu tersebut akan muncul sesuai event yang terjadi. State Move adalah saat monster melakukan aksi berpindah pada map. } Setelah itu. juga tersedia space untuk menampilkan informasi monster yang sedang aktif. Anda hanya perlu teliti mengatur lokasi koordinat Gambar 2.

Yang dimaksud event di sini adalah apa yang akan terjadi saat pemain menekan 2 tombol utama. Alur program saat state map = Normal. pada state Summon dan Monster berbeda. Satu-satunya class yang memiliki hak akses tersebut adalah class GameFrame.setFocusable(true). Kode yang perlu Anda buat cukup sederhana. Z dan X. ada beberapa hal yang mungkin terjadi. koordinat penyerang juga dapat diketahui.114 KNOW-HOW CODING 07/2009 implements KeyListener di dalam class InfoPanel monster juga ditampilkan. Pada saat pemain menekan tombol Z. maka state menu akan berubah menjadi variable curIndex yang telah Anda buat sebelumnya. Anda harus membuatnya di dalam class tersebut. Deklarasikan variable tersebut pada class MapPanel. Artinya class InfoPanel hanya menampilkan bawah saja. Coba Anda lihat pada Gambar 4. Summon dan focus kursor berpindah juga ke class Kursor bisa bergerak ke atas jika kursor tidak berada InfoPanel. Yaitu. perlu Tapi jika lokasi tersebut tidak ada monster dan juga ditangkap kondisi state menu yang terjadi. maka state menu menjadi Monster dan focus kursor berpindah ke class InfoPanel. Summon. Untuk state bukan area pemanggilan. informasi monster saja. yang menggambarkan alur program. Sebut saja method-method tersebut adalah action.setFocusable(false). Pada saat state ini. perlu dibuatkan method khusus pada class yang memiliki hak mengakses object ip dari class InfoPanel. Menu pengJangan lupa untuk mendeklarasikan object dari inner class gantian giliran akan ditampilkan. Demikian juga pada saat aksi penyerangan. Sehingga pada saat aksi perpindahan. private int startX. jika pada posisi kursor terdapat monster. Karena pada saat state Normal. Jelas bahwa penempatan kode yang mengaturnya akan berada di inner class MapControl yang telah Anda buat sebelumnya. terjadi adalah state menu berubah menjadi End. Sedangkan untuk state Monster. atau lokasi tersebut adalah area pemanggilan. ip. Sedangkan karena jumlah menu untuk monster. Memindahkan Fokus ke InfoPanel Untuk memindahkan focus ke class InfoPanel. Posisi kursor disimpan pada monster. lokasi awal monster bisa dikosongkan. menu aksi Pada penggunaannya. Namun sebelum itu.repaint(). Gambar 5.setActChara(actChara). Jika pada lokasi tersebut terdapat monster. Gunanya adalah agar lokasi awal monster tersimpan. private InfoControl ic. Jika ya. Hanya saja. method ini akan variable ini akan diisi dengan lokasi kursor. Tapi jika tidak memenuhi tersebut. Contoh menu pada posisi teratas. ada dua kemungkinan awal yang bisa ditangkap. yang perlu Anda tangkap kedua kondisi tersebut. mp. Beberapa kasus terjadi pada setiap state-nya. Sedangkan pada saat pemain menekan tombol X. Listing f di atas adalah salah satu contoh inner Jika lokasi tersebut merupakan area pemanggilan class yang digunakan. Jadi. yang kursor hanya bisa bergerak sampai menu ketiga. Alur program saat state map = Move. kan. Buatlah juga method setter nilai tersebut untuk memudahkan Gambar 4. hanya seperti baris di bawah ini: public static void toInfo(Chara actChara) { ip. maka tidak akan dilakukan apa-apa. Anda perlu membuat method-method apa yang akan dipanggil saat event itu terjadi. private int startY. Lalu inisialisasi object dan masukkan sebagai KeyListener dari class InfoPanel dengan menambahkan kode di bawah ini ke dalam constructor InfoPanel: ic = new InfoControl(). akan dilakukan pengecekan lagi apakah monster tersebut milik pemain yang sedang mendapat giliran dan monster tersebut dapat melakukan aksi. addKeyListener(ic). sebelum pemanggilan method toInfo Anda perlu memdeklarasikan variable yang akan menyimpan koordinat sementara dari monster yang dipilih. ketika pemain menekan tombol Z. } Event pada MapPanel Kita masuk ke masalah event pada MapPanel. terdapat 4 menu. Menu pemanggilan juga akan ditampilGambar 3. . Pada saat state map = Normal. class InfoPanel. ip. Focus kursor berpindah ke InfoControl ini dalam area variable class InfoPanel. maka state menu menjadi cukup saat pemain menekan panah atas atau Show.

ORANGE). maka monster dihilangkan dari arena. Kemudian informasi jumlah kastil yang dimiliki ditambah. if(map. Method ini hanya akan memanggil method repaint() pada object ip dari class InfoPanel. method ini memanggil method infoUpdate(). maka area akan di-reset. } Menampilkan Damage dan Game Over Pada saat penyerangan. g. Jika ya dan kastil tersebut bukan milik pemain yang sedang mendapat giliran. } Kembali ke masalah event pada MapPanel.End.BOLD.getPosX(). Pada baris terakhir. Anda bisa membuat method sederhana tersebut seperti pada baris di bawah ini: public void isGameOver() { GameManager. Rumus penyerangan ini dibuat sederhana saja. maka program akan memanggil method attack(). nilai DEF dari monster yang diserang juga diambil. Alur tersebut hampir sama dengan saat state map = Move. Method ini akan mengurangi HP dari monster yang diserang. Jika ya. Anda harus menambahkan baris di bawah ini: if(showDamage) { g.drawString(Integer. pengesetan di dalam class MapPanel juga. jika lokasi kursor adalah area penyerangan. Jika ya. Method move() juga diletakkan dalam class MapPanel. Method attack() ini juga memanggil method isGameOver(). Untuk lebih jelasnya. private int damage. dicek apakah monster tersebut telah mati atau tidak. Setelah itu. Kemudian dicek apakah yang dipindahkan adalah hero.changeTurn().turn. Alur program saat state map = Attack. dibuat nilai acak yang akan menambah atau mengurangi serangan antara 0 sampai 1/8 dari nilai serangan awal. public void setStart() { startX = curPosX. apakah tempat perpindahan monster adalah sebuah kastil. } Selanjutnya. akan dicek apakah lokasi kursor terletak pada area perpindahan. startY = curPosY. Font. Setelah itu. Jika ya. lalu dikalkulasikan dalam variable damage yang menjadi nilai serangan monster.setFont(new Font(Font. Variable damage pada method attack() dideklarasikan global di area variable class MapPanel. Jika kastil tersebut milik lawan.Buatlah juga variable showDamage yang merupakan kondisi apakah damage perlu ditampilkan atau tidak.getPosY()) == null) { GameManager. Method move() akan memindahkan monster dari titik awal (yang telah disimpan dalam variable startX dan startY) ke titik tempat kursor berada. Pada saat state map = Move. g. area perpindahan di-reset menjadi false dengan memanggil method setAreaFalse() dari object map. private boolean showDamage. fungsi tombol Z dan X berubah juga. pada method paintComponent(). Coba Anda lihat alurnya pada Gambar 5.turn. Jika pemain menekan tombol Z. maka permainan berakhir. maka method move() akan dipanggil. posisi hero pada object turn juga harus diubah. tileXToPixel(curPosX. jika monster yang diserang adalah hero lawan.changeTurn(). maka state akan diubah menjadi Normal kembali.SANS_SERIF. GameManager. Setelah itu.setColor(Color.repaint(). Baris awal akan memindahkan monster dari posisi awal ke posisi kursor. Lalu status canAttack dari penyerang diset false agar monster tersebut tidak bisa menyerang lagi pada giliran itu. dan hero tersebut mati. Perbedaannya adalah adanya pengecekan apakah state map berubah menjadi End atau tidak. State map End menandakan permainan sudah berakhir karena salah satu hero sudah mati (game over).07/2009 CODING KNOW-HOW 115 Gambar 6. Pada state ini. public static void infoUpdate() { ip. 20)). Jika pemain menekan tombol X. lalu state map menjadi Normal. Method ini akan mendapatkan nilai ATK dari monster penyerang.map = State. state menu menjadi Monster yang akan menampilkan menu monster kembali. Jangan lupa untuk mengubah state map menjadi Normal kembali. Setelah itu. Anda bisa menampilkan informasi damage yang terjadi. artinya pemain sedang memilih lokasi untuk memindahkan monster. Alur programnya dapat Anda lihat pada Gambar 6. HP dari monster yang bertahan akan dikurangi dengan damage. ada event yang berbeda saat state map = Attack. } GameManager. Tidak lupa untuk mengeset monster untuk tidak bisa berpindah lagi pada giliran itu. maka kepemilikan kastil beserta gambarnya akan diubah. Method isGameOver() akan mengecek apakah setelah penyerangan hero lawan menghilang dari arena. Buat method tersebut dan letakkan pada class GameFrame. Listing g adalah contoh method move() sederhana yang digunakan dalam game ini.getChara(GameManager. curPosY) + tileOffsetX * r + margin + 15. Setelah itu.toString(damage). informasi jumlah kastil yang dimiliki lawan juga akan berkurang. Tapi jika belum game over. coba perhatikan listing h. State Attack adalah saat monster akan melakukan penyerangan. Setelah itu dicek lagi. setelah itu fokus dipindahkan kembali ke InfoPanel. . Artinya.

Inner Class MapControl Setelah membuat semua method yang akan digunakan saat penekanan tombol Z dan X. tidak ada menu yang ditampilkan. Saat state menu = End. State menu ada 4 macam. method toMap() akan memindahkan fokus ke MapPanel. Aksi wait akan membuat monster menunggu sampai giliran berakhir. mode penyerangan. ss. Class tersebut dibuat inherit pada class JWindow milik library Java. g. setelah itu akan hilang dan berganti program utama. Sejenis seperti method toInfo(). Namun. Anda harus membuat method dari tersebut di dalam class MapPanel. dan end. Sedangkan pada saat state menu = Show. yang dilakukan bisa pemanggilan. Jadi penampilan damage hanya pada saat monster. KeyPressed() akan terus berjalan selama tombol ditekan. Listing m berikut ini salah satu contoh class SplashScreen sederhana. sekarang saatnya Anda mengatur event pada InfoPanel. Aksi move akan melakukan pengesetan area perpindahan. showDamage = false. Sesuai kondisi state menu-nya. tampilan damage tersebut menghilang. dan ada yang tanpa parameter. Font. Penulis membuatnya seperti pada listing k. Listing j adalah contoh method-method yang digunakan. Anda tinggal mengatur tampilannya saja. menu yang ditampilkan adalah aksi yang dapat dilakukan monster. Dalam method main. g. karena semua aksi akan berdampak pada object di MapPanel. Semua status monster diubah Lebih Menarik dengan SplashScreen Untuk memperkuat kesan pertama pemain. . dan wait (menunggu). Sedangkan. Setelah itu. atau mengakhiri giliran. show. Perbedaan dengan KeyPressed() adalah method ini hanya menjalankan aksi dari satu tombol saja. Method toMap() dengan parameter akan menangkap posisi kursor yang kemudian akan di-switch sesuai state menu yang terjadi. mode menunggu.Pergantian giliran juga diikuti dengan penambahan mana dari pemain. Anda bisa menuliskan listing i di dalam inner class tersebut. maka giliran akan berganti. ada yang dengan parameter. Sama seperti pada MapPanel. Contoh tampilan splash screen. 200. Gambar 7. yaitu normal. monster. Jika pemain menekan tombol Z.setFont(new Font(Font. Inner Class InfoControl Langkah berikutnya Anda tinggal mengatur switch pada inner class InfoControl yang telah Anda buat. lalu membuat state map menjadi Move agar monster bisa melakukan perpindahan. Masing-masing aksi itu menjalankan method tertentu. 300). Cara membuatnya. Kemudian method showSplash() akan menampilkan method tersebut sesuai waktu yang diinginkan. Listing l adalah contoh method tersebut. summon.drawString(“Game Over”. Anda bisa mengisi alur yang terjadi pada inner class MapControl yang telah Anda buat sebelumnya. atribut canSelected diubah menjadi false. Jika pemain menekan tombol Z.setColor(Color. } menjadi true agar dapat melakukan aksi pada giliran berikutnya. maka nilai curIndex yang merupakan lokasi kursor akan ditangkap dan di-switch sesuai monster yang dipanggil. letakkan dalam method KeyTyped(). 80)). Anda perlu menambahkan baris ini pada bagian paling atas. lalu membuat state map menjadi Attack agar monster bisa menyerang. Kali ini. Yang terjadi adalah pemain yang mendapat giliran akan berhasil memanggil monsternya jika memenuhi kondisi sesuai game rule. menu yang ditampilkan hanya satu. Anda bisa menambahkan splash screen yang akan tampil saat game Anda dijalankan kali pertama. yaitu state menu. mode perpindahan.showSplash(). Parameter dari constructor class ini adalah waktu penampilan splash screen tersebut dalam satuan milisecond. Seperti alur yang telah kita bahas sebelumnya.116 KNOW-HOW CODING 07/2009 curPosY * p + tileOffsetY * p + margin). Lalu. } if(GameManager.map == State. sehingga monster tersebut tidak dapat dipilih lagi. Begitu kursor digerakkan. Jadi Anda harus membuat method tersebut di class GameFrame. attack (menyerang). Aksi attack akan melakukan pengesetan area penyerangan. pengaturan ini sedikit berbeda dengan MapControl. Tampilan ini hanya akan muncul beberapa detik. menu yang ditampilkan adalah menu pemanggilan monster. Memindahkan Fokus ke MapPanel Pada listing di atas terdapat pemanggilan method static toMap(). Method tersebut terbagi 2. Saat state menu = Summon. Gunanya adalah untuk membuat object dari class tersebut dengan waktu penampilan selama 4 detik. Aksi-aksi tersebut adalah move (berpindah). Tambahkan juga baris di bawah ini ke dalam method keyPressed() pada inner class MapControl. Dalam program. method showSplash() dipanggil untuk menampilkannya.BOLD. di InfoPanel ini event yang terjadi sesuai dengan state-nya.SANS_SERIF. Saat state menu = Monster.End) { g.ORANGE). SplashScreen ss = new SplashScreen(4000). Method ini akan menangkap tombol yang diketikkan. buatlah class baru bernama SplashScreen. Event pada InfoPanel Setelah selesai mengatur event pada MapPanel. yaitu untuk mengakhiri giliran.

folder map. //untuk menu Show. Anda akan menemukan file dengan nama yang sama seperti nama project Anda. 220. Semua komputer dapat menjalankannya asalkan komputer tersebut telah terinstal JRE (Java Runtime Environment). Buatlah folder baru dengan lokasi dan nama sesuka Anda.drawString(Integer.drawString(Integer.turn. dan build.setOwner(GameManager.getMonster()). Jangan lupa untuk menghilangkan asosiasi file jar dengan software kompresi lain.menu == State. if(GameManager. GameManager. game yang Anda buat telah selesai. Untuk melakukannya.Summon || GameManager. Gambar 8. Coba Anda mainkan bersama teman. GameManager.getPosY(). Caranya adalah Anda harus membuat versi jar dari program Anda. Setelah itu. Frost). Anda juga harus meng-copy juga folder map dan chara. Tidak hanya itu. map. Setelah selesai mengatur semuanya. GameManager. Dengan ini. map. Jika semua yang Anda lakukan sudah benar.drawString(Integer. Flare). dan folder chara.1. File tersebut secara otomatis ditempatkan pada folder dist yang terletak di dalam folder project Anda.loadChara(“Frost”).getPosX().getPosX().turn. g.getMana()).getPosY().Frost. //untuk menu } GameManager.toString(GameManager . 159).resetAllChara().map = State.setOwner(GameManager. Chara Frost = gm. Font.setPos(0.Normal || GameManager. test.BLACK).turn.changeTurn().getHeight() . Fungsi tombol tersebut adalah menghapus semua file hasil compile sebelumnya. switch(GameManager. 124).menu == State. Sebab tentunya akan sangat merepotkan jika Anda meminta teman Anda untuk mencoba sementara teman Anda tidak mempunyai NetBeans. 260.toString(GameManager Listing b GameManager. klik tombol Clean and Build Main Project pada toolbar NetBeans.End) { Image turn = null. 0). g. Jadi.turn.turn) { case Frost: turn = gm. Keduanya dari Universitas Ma Chung. Listing c g. Tombol Clean and Build. Flare.1).turn = Player. game yang telah Anda buat telah selesai. Windra Swastika adalah Dosen Teknik Informatika dan M.SANS_SERIF. seperti Winrar. //untuk map dan menu Attack. Frost. coba Anda klik ganda file jar tersebut. 124).setChara(GameManager. GameManager. Listing a package devilishchildren.turn. .changeTurn(). //untuk menu Monster. copy file berekstensi jar tersebut ke dalam folder Anda. dengan skenario yang lebih baik dan perhitungan statistik yang lebih mantap dalam pembuatan sistemnya. 315. di level folder yang sama dengan folder src.turn. Sebab Winrar akan membaca file jar sebagai file kompresi biasa. Fauzil Haqqi adalah Mahasiswa Teknik Informatika. yang berisi file-file teks informasi map dan chara Anda (bukan folder yang berisi gambar) ke dalam folder milik Anda tersebut. map. 18)).PLAIN.07/2009 CODING KNOW-HOW 117 Mendistribusikan Hasil Secara garis besar.loadImage(GameManager . //untuk map Summon. Folder tersebut akan Anda gunakan sebagai folder utama tempat game Anda.Normal.loadChara(“Flare”). Di dalam folder dist tersebut.getWidth() . maka program akan berjalan dengan tampilan awal splash screen milik Anda.turn. g.turn. Jika masih ada pertanyaan.turn).setChara(GameManager. Malang.setPos(map. Chara Flare = gm.toString(GameManager . Tapi Anda perlu melakukan sesuatu agar game tersebut dapat dimainkan tanpa harus membuka source-nya menggunakan NetBeans. //untuk map Move. GameManager.menu = State.setFont(new Font(Font . public enum State { Normal. map. kemudian meng-compile-nya ulang dan menempatkannya dalam sebuah file kompresi Java berekstensi jar. dalam folder Anda hanya akan berisi file jar.setColor(Color.getCastle()). Anda juga bisa mengembangkan dasar pembuatan game strategi ini ke tahap yang lebih lanjut. GameManager.Normal. //untuk menu End.turn. GameManager.menu == State.turn). sehingga Winrar akan secara otomatis berjalan saat Anda mengeksekusi file jar. Anda bisa menghubungi blog milik penulis yang terletak pada kolom lebih lanjut. g.

“menuEnd.png”). } break.menu == State. “menuFrost.loadImage(GameManager .loadImage(GameManager .menu == State. } } if(GameManager.SANS_SERIF.Attack) { g. 13. 480.menu == State.drawImage(curImg.toString( actChara.png”).getATK()).Monster || GameManager. this).menu == State. 553.map == State.drawImage(actChara.Summon) { Image menu = null. break. 30)).imagesFolder.drawString(Integer. } } repaint(). this).png”).menu == State. this). public void keyReleased(KeyEvent e) { } Listing g public void move() { . switch(GameManager. break.PLAIN. 480.imagesFolder.Move || GameManager. 10. 480. 54). break. 10.map == State.toString( actChara.Summon || Listing d if(GameManager.drawString(actChara.PLAIN. g.loadImage(GameManager . “turnFrost. case Flare: turn = gm. g. 159). } } } g. 553. 260.drawString(Integer. 553. this).png”).menu == State. g.toString( actChara.menu) { case Summon: if(curIndex < 3) { Listing e if(GameManager.drawString(Integer. Font. case Flare: menu = gm. this).getDEF()).getMaxHP()). Listing f private class InfoControl implements KeyListener { public void keyTyped(KeyEvent e) { } public void keyPressed(KeyEvent e) { int keyCode = e.loadImage(GameManager .Monster) { Image menu = gm. if(GameManager. 190. 89). } } } GameManager.imagesFolder.setFont(new Font(Font . break.getKeyCode(). 553.getMOVr()). g. 89).imagesFolder. g.imagesFolder. curPos + curIndex * curMov. “menuFlare.SANS_SERIF.VK_UP: if(curIndex > 0) { --curIndex.getATKr()). case KeyEvent. g.getName(). g. switch(keyCode) { case KeyEvent.getFace().setFont(new Font(Font .loadImage(GameManager .drawImage(menu. 10. } } } ++curIndex. 10.End) { g.getHP()) + “ / “ + Integer. 480. 13.toString( actChara.imagesFolder.turn) { case Frost: menu = gm. if(GameManager. “turnFlare.drawImage(menu. g. break.drawImage(turn. Font.drawString(Integer. “menuMonster. 44).drawImage(menu.menu == State. 13.drawString(Integer.Monster || GameManager.End) { Image menu = gm. this).png”).118 KNOW-HOW CODING 07/2009 .menu == State. } g. 18)).toString( actChara. break. case Monster: if(curIndex < 2) { ++curIndex.png”).toString( actChara. g.VK_DOWN: switch(GameManager. 124).Show || GameManager. } g.

} if(map. curPosY. map.toInfo(map.isUpperCase(keyChar)) { keyChar = Character. dChara. curPosY)) { move().setChara(startX.turn) { GameManager.menu = State. if(Character.setChara(curPosX.Summon. map. if(actChara. String name.getChara( startX. curPosY). name).getOwner(curPosX.setCanMove(false). } else { name = “castleFlare.getOwner() == GameManager.getATK() * 3 .menu = State. } GameFrame.setCanAttack(false).getChara(curPosX. Image img = gm.isChara(startX.getChara(startX.getDEF().turn == Player.menu = State. showDamage = true.Normal. dChara). break.setOwner(curPosX.setAreaFalse(). if(map.turn && actChara.map = State. GameFrame. if(map.turn. aChara). } GameManager.isSummonArea( startX. } map.nextInt(damage/8). img). break. } break. GameFrame. int range = new Random().map = State. GameManager. GameManager.toLowerCase(keyChar).map) { case Normal: switch(keyChar) { case ‘z’: setStart().nextBoolean() ? range : -range.getOwner(curPosX. } else { GameManager. curPosY) == GameManager.setDeath(curPosX.changeTurn().Show.setAreaFalse(). range = new Random().turn.changeCastle(1). GameFrame. startY). GameManager. null). startY)) { GameManager.End. Listing i case Attack: . case Move: switch(keyChar) { case ‘z’: if(map.infoUpdate(). mChara).isArea(curPosX. } switch(GameManager. curPosY). Listing h public void attack() { Chara aChara = map. map.menu = State.setPos(curPosX. curPosY). startY).dChara.turn) { GameManager. curPosY) && map.isCastle(curPosX. GameManager.Frost) { name = “castleFrost. damage = aChara.toInfo(null).menu = State.getPosY()) { GameManager.setChara(startX. if(map. damage += range.infoUpdate().changeTurn().getKeyChar().Monster. } } public void keyTyped(KeyEvent e) { char keyChar = e. case ‘x’: GameManager. curPosY) != GameManager. map. curPosY.turn. startY)) { Chara actChara = map .Monster.07/2009 CODING KNOW-HOW 119 Chara mChara = map.png”. } break. } map.setChara(curPosX.toInfo(null).turn. map. Chara dChara = map.loadImage( GameManager. mChara.turn).changeCastle(-1).getChara(startX. startY). GameManager.turn.toInfo(actChara). if(startX == GameManager. aChara. startY.getChara(startX. isGameOver(). GameFrame.png”. case ‘x’: map. GameFrame.setImage(curPosX. } } break.mapFolder. startY.changeHP(-damage). } break. startY)).Normal. map. curPosY.isCanSelected()) { GameManager.getPosX() && startY == GameManager. if(GameManager. curPosY.

startY.turn.isArea(curPosX. GameFrame. map.turn. GameManager.End) { GameManager. int mana = newChara.resetAllChara().turn.turn.setFocusable(true).changeMana(7).turn.Normal. } } ip.setMoveArea(actChara.getMana() >= mana && GameManager. switch(keyChar) { case ‘z’: GameFrame. break.map = State.changeMana(100 GameManager. startY). 0). startX.turn).setCanSelected(false). if(GameManager. break. map. } Listing k public void keyTyped(KeyEvent e) { char keyChar = e. startY.getMana(). break. } GameManager.menu = State. wChara).loadChara(name). switch(GameManager.turn) { case Frost: switch(index) { case 0: mp.isCanMove()) { GameManager.map = State.turn.getChara(startX. GameManager. Listing l public void moveMode() { Chara actChara = map.getCastle() > GameManager.isUpperCase(keyChar)) { Listing j public void summonTask(String name) { Chara newChara = gm.Move.setAttackArea(actChara. map.changeMonster(1).getMOVr().map = State. ip. GameManager.Normal. GameManager.setFocusable(false). if(Character.changeMana(-mana).getChara(startX.getChara(startX.summonTask(“Durandal”).getMana()). } public static void toMap() { mp.120 KNOW-HOW CODING 07/2009 switch(keyChar) { case ‘z’: if(map. startY).menu) { case Summon: switch(GameManager. case ‘x’: map.infoUpdate(). startY.setChara(startX.setFocusable(true).toLowerCase(keyChar). } } public void waitTask() { Chara wChara = map.toInfo(map.Normal.setOwner(GameManager.getATKr().setFocusable(false).getChara( startX. curIndex = 0. map.Monster. case ‘x’: GameFrame.turn. 0). if(GameManager. startX.map = State.turn. } else { GameManager. GameManager. if(actChara. } } break.map != State.getMonster()) { newChara. newChara). map.getMana() > 93) { GameManager. } break.changeTurn(). if(actChara.setAreaFalse().toMap(). curIndex = 0. } } public static void toMap(int index) { mp. if(GameManager. public void attackMode() { Chara actChara = map.Normal.isCanAttack()) { GameManager. curPosY)) { attack().setAreaFalse(). } } } } } keyChar = Character. GameFrame. startY. } public void endTask() { map.getKeyChar().toMap(curIndex). break.menu = State.Attack. wChara.turn.map = State. . startY)). GameManager. startY).setChara(startX.

try { Thread. int width = 620. break. } import java. Color ora = new Color(50.BorderFactory.getWidth(). case Flare: switch(index) { case 0: mp.JWindow.repaint(). case Monster: switch(index) { case 0: mp.gamedev.awt.blogspot.summonTask(“Hollow”). break.menu = State. break.setBackground(Color. } break. 10)).endTask(). } GameManager.getHeight().swing. import javax. case 2: mp. setVisible(true). import javax. case 3: mp.org import java.swing.com http://www.getScreenSize().CENTER). ip.summonTask(“Death”). break.waitTask().kit .summonTask(“Minotaur”).imagesFolder. “splash. } setVisible(false). case 1: mp.moveMode(). public class SplashScreen extends JWindow { private int duration.WHITE).attackMode(). private GameManager gm.setBorder(BorderFactory . int scrHeight = (int)gm. (scrHeight-height)/2. LEBIH LANJUT http://fauzilhaqqi.add(logo.awt.Normal. } } Listing m package devilishchildren. int height = 170. } break.sleep(duration). import javax.getMessage()).loadImage(GameManager . } catch(Exception e) { System. break.getScreenSize(). case 2: mp.summonTask(“Kraken”).Color. break. import javax. case 1: mp. . case 3: mp. import java.Image. } break.JLabel.summonTask(“Tiamat”). BorderLayout. } public void showSplash() { JPanel content = (JPanel)getContentPane().awt. break.kit . public SplashScreen(int d) { duration = d. height).net http://www. content.JPanel. gm = new GameManager(). content.summonTask(“Phoenix”).ImageIcon. JLabel logo = new JLabel (new ImageIcon(splash)).summonTask(“Succubus”). 50. int scrWidth = (int)gm. case 2: mp.gamedevid. 255). break. import javax. break.swing.swing. width. mp. case End: mp. Image splash = gm.repaint().swing. content.BorderLayout.println(e. } break.png”).out.07/2009 CODING KNOW-HOW 121 case 1: mp. break. setBounds((scrWidth-width)/2.createLineBorder(ora. 50.

You're Reading a Free Preview

Download
scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->