4. IMPLEMENTASI SISTEM
Setelah proses desain selesai dilakukan, maka pada bab ini akan dibahas
bagaimana implementasi sistem kerja dari program perancangan dan pembuatan
aplikasi
Game Racing Android
3 Dimensi ini. Program ini dibuat dengan
menggunakan
software Eclipse
yang merupakan
software
yang digunakan dalam
pemrograman untuk aplikasi java dan Android.Selain itu dalam mempermudah
pemrograman digunakanlah
framework Libgdx
yang merupakan
framework
dengan
life cycle
yang mudah untuk dimengerti dan dikhususkan untuk
pemrograman
game
sehingga mengurangi waktu pemrograman yang lambat
dikarenakan pemrograman dengan cara biasa yang mengharuskan penggunaan
fungsi-fungsi yang memang belum diperuntukkan untuk pemrograman
game
.
Tabel 4.1. Daftar
class
Nama
class
Nomor dari segmen
class
Start
Menu
MenuBuy
MenuLoad
MenuMap
MenuOption
MenuPesawat
MyGame
Score
Tombol
ItemBonus
Pesawat
4.1.1.
4.2.1
4.2.2
4.2.3
4.2.4
4.2.5
4.2.6
4.2.7
4.2.8
4.3.1
4.3.2
4.3.3
Tabel 4.2. Daftar prosedur dan fungsi
Nama prosedur atau fungsi
Bagian
class
segmen
cekluncurbonusAI
naikturun
cektabrakpesawatdepan
jalanAI
jalanAI2
jalanAI3
setjalanpathAI
caripathuser
Pesawat
Pesawat
Pesawat
Pesawat
Pesawat
Pesawat
Pesawat
Pesawat
4.3.3.1
4.3.3.2
4.3.3.3
4.3.3.4
4.3.3.5
4.3.3.6
4.3.3.7
4.3.3.8
4.1.
Implementasi Class Extend Game
Class Extend Game
ini merupakan
main class
dari
framework Libgdx
dimana
class
ini meng
implement
ApplicationListener
dan menjadi pusat dari
class-class
yang lain yang ada dalam
project Libgdx
. Maka dari itu di
class
ini
akan dilakukan deklarasi
object
dari
file
suara serta variabel-variabel yang
nantinya dibutuhkan sebagai
properties
class lain.
Berikut merupakan segmen 4.1.1. yang merupakan isi
source code class
Start
:
Segmen 4.1.1.
Class Start
package com.libgdx; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import android.os.Environment; import com.badlogic.gdx.Game; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.GdxRuntimeException; public class Start extends Game
{
private Music[] bgm,effect; private float bgmvol = 0.5f; private float effectvol=0.5f; private String namauser; private int indexkendaraan; private int indexmap; private int money; private int indexlevel; private int ranking; private int jenismenuload; private int[] statuspesawat;
public void create() { indexlevel=1; indexmap=0; indexkendaraan=0; namauser="racer"; statuspesawat=new int[4]; statuspesawat[0]=1; for(int i=1;i<4;i++) { statuspesawat[i]=0; } money=0;
File sdDir = Environment.getExternalStorageDirectory(); String path = sdDir.getAbsolutePath() + "/LIBGDX/"; File sgDir = new File(path);
if (!sgDir.exists()) { sgDir.mkdirs(); try {
sgDir.createNewFile(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace();
} }
else {
try {
FileHandle
audioFileHandle=Gdx.files.external("LIBGDX/volume");
InputStream fstream = audioFileHandle.read(); DataInputStream in = new DataInputStream(fstream); String strline; while((strline=in.readLine())!=null) { if(strline.startsWith("B")) {
String[] tokens = strline.split(" ");
bgmvol=Float.valueOf(tokens[1])/100 ; }
if(strline.startsWith("E")) {
String[] tokens = strline.split(" ");
effectvol=Float.valueOf(tokens[1])/100 ; }
}
in.close();
} catch (GdxRuntimeException ex) {
// TODO Auto-generated catch block String strline; strline="B "+Float.toString(bgmvol*100)+"\nE "+Float.toString(effectvol*100); OutputStreamWriter out=new OutputStreamWriter(Gdx.files.external("LIBGDX/volume").write(false)); try { out.write(strline); out.flush(); out.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace();
}
} catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace();
} } bgm=new Music[3]; effect=new Music[3]; bgm[0]=Gdx.audio.newMusic(Gdx.files.internal("audio/oldschool.mid" )); bgm[0].setLooping(true); bgm[1]=Gdx.audio.newMusic(Gdx.files.internal("audio/c2.MP3")); bgm[1].setLooping(true); bgm[2]=Gdx.audio.newMusic(Gdx.files.internal("audio/c3.MP3")); bgm[2].setLooping(true); effect[0]=Gdx.audio.newMusic(Gdx.files.internal("audio/engine.wav" )); effect[0].setLooping(true); effect[1]=Gdx.audio.newMusic(Gdx.files.internal("audio/go1.wav")); effect[2]=Gdx.audio.newMusic(Gdx.files.internal("audio/last.wav")) ; bgm[0].play(); for(int i=0;i<3;i++) { bgm[i].setVolume(bgmvol); } for(int i=0;i<3;i++) { effect[i].setVolume(effectvol); } ranking=0; setScreen(new Menu(this,null,null,null)); } }
Pada
Class Start
ini berisi semua fungsi dan variabel yang digunakan untuk
menampung
profil user
serta pilihan-pilihannya di setiap
menu
nya nanti dan juga
pemanggilan semua
file audio
yang dibutuhkan dan pembuatan
file
untuk
setting
pada
memory external
apabila
user
baru pertama kali menjalankan
game
atau
menghapus isi
memory external
yang berisi
file game
ini. Lalu
class
ini akan
menetapkan
Class Menu
menjadi tampilan awal dengan fungsi
setScreen(new
Menu(this,null,null,null))
dengan
this
merupakan
Class Start
yang dikirimkan ke
tiap
class Screen
dan
null
sebagai isi dari parameter
constractor Class Menu
yang
mengindikasi sebelumnya berasal dari
Class
yang mana.
4.2.
Implementasi Class Implements Screen
Class
yang
meng
implements
Screen
ini
semacam
class
mini
ApplicationListeners
.
Class
ini memiliki fungsi
render(), pause(), resume(),
dan
resize()
selain itu fungsi
hide()
dan
show().
Ketika fungsi
setScreen(screen)
dipanggil maka fungsi
hide()
dari
screen
sekarang dipanggil dan
screen
yang baru
akan menjadi
screen
sekarang dan fungsi
show()
akan dipanggil, setelah itu fungsi
render()
akan dipanggil setiap
frame
dari
game
. Dalam class ini fungsi
dispose()
tidak akan dipanggil melainkan fungsi
hide()
yang akan dipanggil. Sehingga
proses dari
screen
sebelumnya akan tetap berjalan.
Berikut merupakan source code Class MenuOption dari segmen 4.2.5. :
Segmen 4.2.5.
Class MenuOption
package com.libgdx; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import android.util.Log; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.Screen; import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class MenuOption implements Screen{ private int WIDTH = 480;
private int HEIGHT = 320;
private PerspectiveCamera camera; private Texture backgroundtexture; private SpriteBatch batch;
private Tombol
back,save,layarkendaraan,tbgm,teffect,ubgm,ueffect,vbgm,veffect; private int sensivity=0;
private int sensivitymax=3;
private boolean cback,csave,cbgm,ceffect,keyback,cplayeffect; private int timeplayeffect=0;
private int timeplayeffectmax=20; private float wbgm,weffect; private boolean hapusawal; private float volbgm,voleffect; Menu menu;
Start start;
public MenuOption(Start s,Menu m) { hapusawal=false; menu=m; start=s; backgroundtexture = new Texture(Gdx.files.internal("texture/backgroundmenu.jpg")); batch=new SpriteBatch(); csave=false; cback=false; cbgm=false; ceffect=false;
keyback=false; cplayeffect=false; Gdx.input.setCatchBackKey(true); volbgm=start.getvolumeaudio(0); voleffect=start.getvolumeaudio(1); }
public void dispose() { backgroundtexture.dispose(); batch.dispose(); back.dispose(); save.dispose(); layarkendaraan.dispose(); tbgm.dispose(); teffect.dispose(); ubgm.dispose(); ueffect.dispose(); vbgm.dispose(); veffect.dispose(); }
public void pause() { }
public void render(float arg0) { cektombol();
Gdx.gl.glEnable(GL10.GL_TEXTURE_2D);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT );
camera.update();//tanpa update camera tidak jalan camera.apply(Gdx.gl10); batch.begin(); batch.draw(backgroundtexture, 0, 0,WIDTH,HEIGHT); batch.end(); layarkendaraan.gambar(); tbgm.gambar(); teffect.gambar(); ubgm.gambar();
ueffect.gambar(); vbgm.gambar(); veffect.gambar(); back.gambar(); save.gambar(); if(hapusawal==false) { if(menu!=null) { menu.dispose(); } hapusawal=true; } }
public void resize(int arg0, int arg1) {
camera = new PerspectiveCamera(67,arg0, arg1); WIDTH=arg0; HEIGHT=arg1; save=new Tombol(-140,250,140,50,"save2.png",arg0,arg1,10,10); save.setletaktekan(-140,250, 140, 50); save.setujunganimasi(50,-140,0,50); back=new Tombol(480,250,140,50,"back12.png",arg0,arg1,10,10); back.setletaktekan(480,250, 140, 50); back.setujunganimasi(290,480,340,290); tbgm=new Tombol(-150,40,150,40,"bgm2.png",arg0,arg1,10,10); tbgm.setujunganimasi(60,-150,0,60); teffect=new Tombol(-150,130,150,40,"effect2.png",arg0,arg1,10,10); teffect.setujunganimasi(60,-150,0,60); ubgm=new Tombol(500,90,400,20,"ukuran2.png",arg0,arg1,20,20); ubgm.setletaktekan(470,90, 440, 20); ubgm.setujunganimasi(60,500,480,50); ueffect=new Tombol(500,170,400,20,"ukuran2.png",arg0,arg1,20,20); ueffect.setletaktekan(480,170, 440, 20); ueffect.setujunganimasi(60,500,480,50);
vbgm=new Tombol(480,90,200,20,"volume2.png",arg0,arg1,20,20); vbgm.setujunganimasi(60,480,480,60); vbgm.setwidthvolume2(volbgm, 400); veffect=new Tombol(480,170,200,20,"volume2.png",arg0,arg1,20,20); veffect.setujunganimasi(60,480,480,60); veffect.setwidthvolume2(voleffect, 400); layarkendaraan=new Tombol(-460,10,460,200,"layarkendaraan2.png",arg0,arg1,20,20); layarkendaraan.setujunganimasi(10,-460,-460,10); }
public void resume() { } public void hide() {
// TODO Auto-generated method stub }
public void show() {
// TODO Auto-generated method stub }
}
Pada
Class MenuOption
ini pertama kali pada
constractor
akan ditetapkan
nilai-nilai awal yang akan ditampilkan dalam bentuk
bar
panjang
horizontal
yang
mewakili
volume
awal yang sebelumnya telah tercatat di
file
atau deklarasi baru
yang sebelumnya telah dilakukan oleh
Class Start
. Lalu gambar-gambar yang
dibutuhkan pertama kali akan diambil dan dideklarasikan oleh
object
dari
Class
Tombol
pada prosedur
resize(int arg0, int arg1)
, karena untuk menetapkan
jalannya untuk semua device maka akan diambil dulu panjang dan tinggi device
dari fungsi tersebut dengan hasil
arg0
adalah panjang dan
arg1
adalah lebar. Dan
pada fungsi
render()
ini terdapat suatu pengecekan untuk melakukan
dispose()
terhadap
screen
sebelumnya supaya tidak memperberat kerja
device
. Pengecekan
ini dilakukan di fungsi
render()
supaya ketika perpindahan screen gambar
background
dari
menu
tidak hilang. Prosedur ini memiliki struktur yang sama
dengan prosedur pada
Class Menu
Pesawat dan
Class Menu
yang lainnya yang
ada pada segmen
class
4.2., hanya saja sebagian
class
seperti
class Menu
Pesawat
memiliki sedikit tambahan yaitu variabel
sensitivity
yang berguna untuk
mengurangi
sensitivity
penekanan
user
terhadap tombol kiri dan kanan ketika
memilih kendaraan yang akan dipakai bertanding. Tetapi sebagian besar isi dari
class
ini dan
class
menu lainnya seperti
class Menu, MenuBuy, MenuLoad
, dan
MenuMap
hampir sama, hanya beda pada fungsi
dispose menu
sebelumnya dan
banyaknya tombol yang diperlukan.
Selain untuk
menu Implements Screen
juga digunakan untuk
screen
utama
jalannya pertandingan dalam
game
yaitu dalam
class MyGame
. Berikut
merupakan sebagian
sourcecode
dari
class MyGame
:
Segmen 4.2.7
Class MyGame
package com.libgdx; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import android.util.Log; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.Screen; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Camera; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g3d.loaders.obj.ObjLoader; import com.badlogic.gdx.utils.GdxRuntimeException;
public class MyGame implements Screen{ private float WIDTH=480;
private float HEIGHT=320; private Camera camera; public Pesawat[] p; private Texture mapt; private Mesh map;
private SpriteBatch batch; private Texture HPtexture; private Texture iconbonus; private Texture[] HPbar; private BitmapFont font;
private float widthmap,heightmap; private Texture galaxyt;
private Mesh galaxy;
private Pixmap cekmap,cekfinish;
private float[] pathx,pathz,pathy,startx,starty,startz; private int
jumlahpath,jumlahpesawat,i,j,k,indexpitawal,indexpitakhir,indexuser; private boolean hapusawal;
MenuMap menumap;
private int jumlahbonus; private ItemBonus[] bonus; private int[] statuspath; private int[] indexceklap; private int jumlahceklap; private boolean lastlap=false; Start start;
private Texture warning,rem,pitstop; private Texture[] panelmulai;
private int waktutunggu; boolean startgame;
private int indexpanel=0; private int ranking; private boolean tampillap; private int waktutampillap; private int waktutunggumax;
public MyGame(Start s,MenuMap mm) { jumlahbonus=20; bonus=new ItemBonus[20]; for(i=0;i<jumlahbonus;i++) {
bonus[i]=new ItemBonus(); } batch=new SpriteBatch(); HPbar=new Texture[2]; panelmulai=new Texture[3]; panelmulai[0] = new Texture(Gdx.files.internal("texture/stop.png")); panelmulai[1] = new Texture(Gdx.files.internal("texture/ready.png"));
panelmulai[2] = new Texture(Gdx.files.internal("texture/go.png")); iconbonus = new
Texture(Gdx.files.internal("texture/iconbonus2.png"));
warning = new Texture(Gdx.files.internal("texture/warning2.png")); pitstop = new Texture(Gdx.files.internal("texture/pitstop.png")); rem = new Texture(Gdx.files.internal("texture/rem.png"));
HPbar[0] = new Texture(Gdx.files.internal("texture/barhp.png")); HPbar[1] = new Texture(Gdx.files.internal("texture/barhp2.png")); hapusawal=false; menumap=mm; startgame=false; waktutunggu=0; start=s; tampillap=false; jumlahpesawat=5; waktutampillap=200; waktutunggumax=200;
galaxyt = new Texture(Gdx.files.internal("texture/galaxy.jpg")); galaxy = ObjLoader.loadObj(Gdx.files.internal("obj/galaxy.obj").read(),true); ranking=0; setpathmap(start.getindexmap()); setkendaraan(start.getindexlevel(),start.getindexkendaraan()); Gdx.input.setCatchBackKey(true); } }
Sourcecode
diatas merupakan
constractor
dari
class MyGame
yang
menjadi awal untuk mendeklarasikan dan memberi nilai awal dari variabel, serta
menentukan jumlah kendaraan dan
bonus.
4.3.
Implementasi Class Object Pendukung
Class-class ini berguna sebagai pembentuk object yang terdapat dalam
menu dan game yang dijalankan. Object dari kelas ini akan mewakili
masing-masing object yang akan ditampilkan pada background.
Berikut merupakan segmen
class
4.3.1. yaitu
class Tombol
:
Segmen 4.3.1.
Class Tombol
package com.libgdx; import android.util.Log; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class Tombol { private float x,y;
private float kecepatan,kecepatan2; private float width,height;
private Texture texture; private float xt,yt;
private float widtht,heightt; private float ujunganimasiawal; private float ujunganimasiakhir; private float ujunganimasitengah; private float ujunganimasitekan; private float wlayar,hlayar; private boolean
canimasiawal,canimasiakhir,cektekan,canimasitengah; private SpriteBatch batch;
private BitmapFont font; private String textfont; private boolean cekfont; float xfont,yfont;
public Tombol(float xx,float yy, float w,float h,String textur,float wl,float hl,float k,float k2)
{ cekfont =false; texture = new Texture(Gdx.files.internal("texture/"+textur)); wlayar=wl; hlayar=hl; width=w*wlayar/480; height=h*hlayar/320; x=xx*wlayar/480; y=hlayar-(yy*hlayar/320)-height; batch=new SpriteBatch(); canimasiakhir=false; canimasiawal=false; canimasitengah=false; cektekan=false; kecepatan=k*wlayar/480; kecepatan2=k2*hlayar/320; font = new BitmapFont(Gdx.files.internal("font/digifacewide.fnt"), Gdx.files.internal("font/digifacewide.png"), false); font.setScale(wlayar/480); textfont=""; } }
Class
ini merupakan
class
yang sebagian besar dipakai oleh
class-class
menu
pada segmen
class
4.2.
class
ini memiliki fungsi-fungsi seperti mengatur
peletakan tombol pada layar, mengecek penekanan tombol, memberikan
text
pada
tombol, menampilkan tombol dengan gambar dari
file
, serta mengatur jalan
animasi
dari tombol saat awal dan perpindahan screen. Selain class tombol juga
terdapat class ItemBonus yang mengatur semua item bonus.
Berikut merupakan
source code
dari segmen
class
4.3.2 yaitu
class
ItemBonus
:
Segmen 4.3.2.
Class ItemBonus
package com.libgdx; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g3d.loaders.obj.ObjLoader; public class ItemBonus {
//status 0=set //status 1=siap; private float x,y,z; private float width; private int jenis;
private int status,indexpathAI,indextempat; private Mesh[] model;
private Texture[] texture; private float[] head; private float rotatefh; private float kecepatan; private int indexpemegang; private Mesh tanda;
private Texture ttanda;
public ItemBonus() { width=1; x=0; y=0; z=0; jenis=0; status=0;
indextempat=0; head=new float[2]; texture=new Texture[6]; texture[0] = new Texture(Gdx.files.internal("bonus/ranjau.jpg")); texture[1] = new Texture(Gdx.files.internal("bonus/kecepatan.jpg")); texture[2] = new Texture(Gdx.files.internal("bonus/pelindung.jpg")); texture[3] = new Texture(Gdx.files.internal("bonus/misil0.jpg")); texture[4] = new Texture(Gdx.files.internal("bonus/misil1.jpg")); texture[5] = new Texture(Gdx.files.internal("bonus/misil2.jpg")); model=new Mesh[4]; model[0] = ObjLoader.loadObj(Gdx.files.internal("bonus/ranjau.obj").read(),true); model[1] = ObjLoader.loadObj(Gdx.files.internal("bonus/kecepatan.obj").read(),true); model[2] = ObjLoader.loadObj(Gdx.files.internal("bonus/pelindung.obj").read(),true); model[3] = ObjLoader.loadObj(Gdx.files.internal("bonus/misil.obj").read(),true); rotatefh=0; kecepatan=4; indexpemegang=-1; tanda = ObjLoader.loadObj(Gdx.files.internal("bonus/tanda.obj").read(),true); ttanda = new Texture(Gdx.files.internal("bonus/tanda.jpg"));
} }
Class ItemBonus ini merupakan class yang mengatur Mesh item bonus
yang bersebaran di lintasan. Class ini berhubungan dengan fungsi dari class
Pesawat yang juga melakukan pengecekan terhadap item bonus. Dalam class ini
terdapat beberapa fungsi penting yaitu:
Berikut merupakan
source code
dari segmen
class
4.3.3 yaitu
class
Pesawat:
Segmen 4.3.3.
Class
Pesawat
package com.libgdx; import android.util.Log; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g3d.loaders.obj.ObjLoader;
public class Pesawat {
private Mesh model,cek; private Texture texture; private float x,y,z;
private float rotatef,rotatefh; private float[] bataskiri; private float[] bataskanan; private float[] batasdepan; private float kecepatan; private float kecepatanmax; private float kecepatanmin;
private float selisihkecepatan,boost; private float xcam,ycam,zcam;
private int indexpathAI; private float[] sayapkiri; private float[] sayapkanan; private float[] headtembak; private float[] ekortembak;
private float[] depankiri,depankanan,belakangkiri,belakangkanan; private float acceleration;
private float HPmax; private float rotatev; private float rotatefh2;
private float accelerationbonus;
private boolean pegangbonus,effectbonus; private int jenisbonus,jeniseffect,indexbonus; private float HPterakhir;
private int timeeffect;
private boolean cekjalanAI1,masukpit,cekgarisfinish; private int lap;
private int ceklapnow; private boolean selesai;
public Pesawat(String pesawat,String textur,float xx,float yy,float zz) { headtembak=new float[2]; ekortembak=new float[2]; texture = new Texture(Gdx.files.internal("kendaraan/"+textur)); model = ObjLoader.loadObj(Gdx.files.internal("kendaraan/"+pesawat).read(),true); x=xx; y=yy; z=zz; rotatef=0; rotatefh=0; rotatev=0; rotatefh2=0; headtembak[0]=x; headtembak[1]=z-30; ekortembak[0]=x; ekortembak[1]=z+10; pegangbonus=false; jenisbonus=-1; effectbonus=false; timeeffect=0; boost=0; accelerationbonus=1;
masukpit=false; lap=0; ceklapnow=0; cekgarisfinish=false; xcam=xx; ycam=yy+2; zcam=zz+9; indexpathAI=0; cekjalanAI1=true; selesai=false; } }
Class
Pesawat ini merupakan
class
yang mengatur
Mesh
dari kendaraan,
AI(Artificial Intellligent)
, pengecekan tabrak, serta penyetiran
user
terhadap
kendaraan yang nantinya akan ditampilkan di
class MyGame
dengan fungsi
gambar().
Class
ini memiliki fungsi untuk menetapkan
path
baik
user
maupun
AI
ketika mengitari lintasan. Berikut merupakan beberapa fungsi dan prosedur yang
penting dalam
class Pesawat
:
Segmen 4.3.3.1. cekluncur
bonus
AI
public boolean cekluncurbonusAI(int levelgame,float[] dkanan,float[] dkiri,float[] bkanan,float[] bkiri)
{ if(pegangbonus==true) { waktupegangbonus++; if(waktupegangbonus>2000) { levelgame=1; waktupegangbonus=0; } if(levelgame==1) { pegangbonus=false; effectbonus=false; if(jenisbonus==1) { timeeffect=0;
effectbonus=true; jeniseffect=1; boost=2; } else if(jenisbonus==2) { timeeffect=0; effectbonus=true; jeniseffect=2; HPterakhir=HP; } return true; } else if(levelgame==2) { if(jenisbonus==0) { if(cektabrakpesawatdepan(dkanan, dkiri, bkanan, bkiri, ekortembak[0], ekortembak[1])==false)
{ pegangbonus=false; effectbonus=false; return true; } } else if(jenisbonus==1) { pegangbonus=false; timeeffect=0; effectbonus=true; jeniseffect=1; boost=2; return true; } else if(jenisbonus==2) { pegangbonus=false; timeeffect=0; effectbonus=true; jeniseffect=2; HPterakhir=HP; return true; }
else if(jenisbonus==3 || jenisbonus==4 || jenisbonus==5)
{
if(cektabrakpesawatdepan(dkanan, dkiri, bkanan, bkiri, batasdepan[0], batasdepan[1])==false)
{ pegangbonus=false; effectbonus=false; return true; } else {
float[] headtembak=new float[2]; boolean cek=true; int i=0; float r=(-90-rotatefh); do { headtembak[0]=(float) (batasdepan[0]+Math.cos(Math.toRadians(r))*i); headtembak[1]=(float) (batasdepan[1]+Math.sin(Math.toRadians(r))*i); if(cektabrakpesawatdepan(dkanan, dkiri, bkanan, bkiri, headtembak[0], headtembak[1])==false)
{
cek=false; }
i+=2;
}while(i<=(jarakhead/2) && cek==true); if(cek==false) { pegangbonus=false; effectbonus=false; return true; } } } } else if(levelgame==3) { if(jenisbonus==0) { if(cektabrakpesawatdepan(dkanan, dkiri, bkanan, bkiri, ekortembak[0], ekortembak[1])==false)
{ pegangbonus=false; effectbonus=false; return true; } } else if(jenisbonus==1) { pegangbonus=false; timeeffect=0; effectbonus=true; jeniseffect=1; boost=2; return true; } else if(jenisbonus==2) { pegangbonus=false; timeeffect=0; effectbonus=true; jeniseffect=2; HPterakhir=HP; return true; }
else if(jenisbonus==3 || jenisbonus==4 || jenisbonus==5)
{
if(cektabrakpesawatdepan(dkanan, dkiri, bkanan, bkiri, batasdepan[0], batasdepan[1])==false)
{ pegangbonus=false; effectbonus=false; return true; } else {
float[] headtembak=new float[2]; boolean cek=true; int i=0; float r=(-90-rotatefh); do { headtembak[0]=(float) (batasdepan[0]+Math.cos(Math.toRadians(r))*i);
headtembak[1]=(float) (batasdepan[1]+Math.sin(Math.toRadians(r))*i);
if(cektabrakpesawatdepan(dkanan, dkiri, bkanan, bkiri, headtembak[0], headtembak[1])==false)
{
cek=false; }
i+=2;
}while(i<=jarakhead && cek==true); if(cek==false) { pegangbonus=false; effectbonus=false; return true; } } } } } return false; }
Fungsi di atas adalah untuk mengatur apa yang dilakukan AI berdasarkan
level
apabila AI mendapatkan
item bonus
. Apabila
level
yang dipilih
user
adalah
level
1 atau
easy
maka AI akan melepaskan atau meluncurkan segala jenis
item
bonus
yang dibawa. Sedangkan apabila
user
memilih
level 2
atau
medium
maka
apabila di belakang AI terdapat kendaraan lain dan AI sedang memegang ranjau
maka AI akan segera menjatuhkan ranjau tersebut dan apabila di depan AI
terdapat kendaraan lain dan berada dalam setengah jarak tembak maka AI akan
menembakkan tembakan
item
serangan. Untuk
level 3
atau
expert
sama seperti
medium,
hanya saja jarak tembak tidak dikurangi. Dan apabila AI telah memegang
item
lebih dari waktu pegang, maka AI akan meluncurkan
item
tersebut. Selain itu
item
yang dapat menambah kecepatan dan pelindung akan segera dipakai apabila
didapatkan.
Segmen 4.3.3.2. naikturun
public void naikturun(float[] ptx,float[] pty,float[] ptz) {
tinggi=Math.abs(pty[indexpathAI]-y); float jarakpath; jarakpath=(float) Math.sqrt(Math.pow(ptx[indexpathAI]-x, 2)+Math.pow(ptz[indexpathAI]-z, 2)); double sudut; sudut=Math.atan(tinggi/jarakpath); float jaraktinggi = 0; if(pty[indexpathAI]>y) { if(Math.toDegrees(sudut)>rotatev) { if(rotatev+1<=Math.toDegrees(sudut)) { rotatev=rotatev+1f; } else { rotatev=(float) Math.toDegrees(sudut); } } jaraktinggi=(float) (Math.sin(sudut)*kecepatan); } else if(pty[indexpathAI]<y) { if(Math.toDegrees(sudut)*-1<rotatev) { if(rotatev-1>=Math.toDegrees(sudut)*-1) { rotatev=rotatev-1f; } else { rotatev=(float) Math.toDegrees(sudut)*-1; } } jaraktinggi=(float) (Math.sin(sudut)*kecepatan*-1); }
if(Math.toDegrees(sudut)<=1 && Math.toDegrees(sudut)>=0) {
if(0>rotatev) {
if(rotatev+2<=0) { rotatev=rotatev+2f; } else { rotatev=0; } } if(0<rotatev) { if(rotatev-2>=0) { rotatev=rotatev-2f; } else { rotatev=0; } } } y=y+jaraktinggi; ycam=ycam+jaraktinggi; }
Fungsi di atas digunakan untuk mengatur kendaraan untuk dapat menaiki
dan menuruni bukit dari lintasan yang ada berdasarkan path yang ada. Seperti
yang telah dijelaskan pada bab 3 dalam
source code
ini dicari ketinggian
kendaraan berdasarkan kecepatan kendaraan, selain itu juga arah
mesh
ke atas dan
ke bawah dengan variabel rotatev sesuai dengan besar sudut antara kendaraan
dengan tinggi
path.
Segmen 4.3.3.3. cektabrakpesawatdepan
public boolean cektabrakpesawatdepan(float[] dkanan,float[] dkiri,float[] bkanan,float[] bkiri,float bx,float bz)
{
float jarakbatas1,jarakbatas2; double sudut;
float t1,t2; boolean c1,c2;
float lebar=(float) Math.sqrt(Math.pow(dkiri[0]-bkiri[0],2)+Math.pow(dkiri[1]-bkiri[1], 2));
float panjang=(float) Math.sqrt(Math.pow(dkiri[0]-dkanan[0],2)+Math.pow(dkiri[1]-dkanan[1], 2)); jarakbatas1=(float) Math.sqrt(Math.pow((dkiri[0]-bx), 2)+Math.pow((dkiri[1]-bz), 2)); jarakbatas2=(float) Math.sqrt(Math.pow((bkiri[0]-bx), 2)+Math.pow((bkiri[1]-bz), 2)); sudut=Math.acos((Math.pow(lebar, 2)+Math.pow(jarakbatas2, 2)-Math.pow(jarakbatas1, 2))/(2*lebar*jarakbatas2)); t1=(float) (jarakbatas2*Math.sin(sudut)); jarakbatas1=(float) Math.sqrt(Math.pow((bkanan[0]-bx), 2)+Math.pow((bkanan[1]-bz), 2)); jarakbatas2=(float) Math.sqrt(Math.pow((dkanan[0]-bx), 2)+Math.pow((dkanan[1]-bz), 2)); sudut=Math.acos((Math.pow(lebar, 2)+Math.pow(jarakbatas2, 2)-Math.pow(jarakbatas1, 2))/(2*lebar*jarakbatas2)); t2=(float) (jarakbatas2*Math.sin(sudut)); if(Math.floor(t1+t2)==Math.floor(panjang)) { c1=false; } else { c1=true; } jarakbatas1=(float) Math.sqrt(Math.pow((dkanan[0]-bx), 2)+Math.pow((dkanan[1]-bz), 2)); jarakbatas2=(float) Math.sqrt(Math.pow((dkiri[0]-bx), 2)+Math.pow((dkiri[1]-bz), 2)); sudut=Math.acos((Math.pow(panjang, 2)+Math.pow(jarakbatas2, 2)-Math.pow(jarakbatas1, 2))/(2*panjang*jarakbatas2)); t1=(float) (jarakbatas2*Math.sin(sudut)); jarakbatas1=(float) Math.sqrt(Math.pow((bkiri[0]-bx), 2)+Math.pow((bkiri[1]-bz), 2)); jarakbatas2=(float) Math.sqrt(Math.pow((bkanan[0]-bx), 2)+Math.pow((bkanan[1]-bz), 2)); sudut=Math.acos((Math.pow(panjang, 2)+Math.pow(jarakbatas2, 2)-Math.pow(jarakbatas1, 2))/(2*panjang*jarakbatas2)); t2=(float) (jarakbatas2*Math.sin(sudut)); if(Math.floor(t1+t2)==Math.floor(lebar)) {
c2=false; } else { c2=true; }
if(c1==false && c2==false) {
return false; }
return true; }
Fungsi di atas digunakan untuk melakukan pengecekan apakah suatu
kendaraan telah menabrak kendaraan lain dengan menggunakan rumus persamaan
segitiga yang ada pada bab 3.
Segmen 4.3.3.4. jalanAI
public boolean jalanAI(Pixmap px,float w,float h,float[] dkanan,float[] dkiri,float[] bkanan,float[] bkiri)
{
boolean cek1=true; boolean cek2=true; boolean cek3=true;
if(cektabrak(px, batasdepan[0], batasdepan[1], w, h)==false) {
kecepatan=0;
if(cektabrak(px, bataskiri[0], bataskiri[1],w,h)==false) {
setirAI(acceleration); }
else if(cektabrak(px, bataskanan[0], bataskanan[1],w,h)==false) { setirAI(acceleration*-1); } cek1=false; }
{
kecepatan=kecepatanmin; setirAI(acceleration); cek1=false;
}
else if(cektabrak(px, bataskanan[0], bataskanan[1],w,h)==false) {
kecepatan=kecepatanmin; setirAI(acceleration*-1); cek1=false;
}
if(cektabrakpesawatdepan(dkanan, dkiri, bkanan,bkiri, batasdepan[0], batasdepan[1])==false) { kecepatan=kecepatanmin; if(cektabrakpesawatdepan(dkanan, dkiri, bkanan,bkiri,bataskiri[0], bataskiri[1])==true) { setirAI(acceleration*-1); }
else if(cektabrakpesawatdepan(dkanan, dkiri, bkanan,bkiri,bataskanan[0], bataskanan[1])==true) { setirAI(acceleration); } cek2=false; }
else if(cektabrakpesawatdepan(dkanan, dkiri, bkanan,bkiri,bataskiri[0], bataskiri[1])==false) { kecepatan=kecepatanmin; setirAI(acceleration); cek2=false; }
else if(cektabrakpesawatdepan(dkanan, dkiri, bkanan,bkiri,bataskanan[0], bataskanan[1])==false) { kecepatan=kecepatanmin; setirAI(acceleration*-1); cek2=false; }
if(cektabrakpesawatdepan(dkanan, dkiri, bkanan,bkiri,sayapkiri[0], sayapkiri[1])==false || cektabrak(px,sayapkiri[0], sayapkiri[1], w, h)==false)
{
setirAI(acceleration); cek3=false;
}
else if(cektabrakpesawatdepan(dkanan, dkiri,
bkanan,bkiri,sayapkanan[0], sayapkanan[1])==false || cektabrak(px, sayapkanan[0], sayapkanan[1], w, h)==false)
{ setirAI(acceleration*-1); cek3=false; } if(cektabrakpesawatdepan(dkanan, dkiri, bkanan,bkiri,belakangkiri[0], belakangkiri[1])==false || cektabrak(px,belakangkiri[0], belakangkiri[1], w, h)==false)
{
setirAI(acceleration); return true;
}
else if(cektabrakpesawatdepan(dkanan, dkiri,
bkanan,bkiri,belakangkanan[0], belakangkanan[1])==false || cektabrak(px,belakangkanan[0], belakangkanan[1], w, h)==false)
{ setirAI(acceleration*-1); return true; } if(cek1==false ||cek2==false||cek3==false) { return false; } return true; }
Fungsi di atas merupakan prioritas paling utama dalam melakukan
pengecekan AI, karena fungsi di atas akan melakukan pengecekan terhadap
penabrakan dinding dan kendaraan lain dan melakukan tindak lanjut terhadap apa
yang terjadi dengan melakukan pembelokan sesuai dengan bagian yang ditabrak.
Segmen 4.3.3.5. jalanAI2
public boolean jalanAI2(float xbonus,float zbonus,int statusbonus) {
float test;
test = (batasdepan[0]-x)*(xbonus-x) + (batasdepan[1]-z)*(zbonus-z);
float[] jarakbonus=new float[3];
jarakbonus[0]=(float) Math.sqrt(Math.pow(batasdepan[0]-xbonus, 2)+Math.pow(batasdepan[1]-zbonus, 2));
if(test>0 && jarakbonus[0]<=40 && statusbonus==1 && pegangbonus==false && effectbonus==false)
{
menujupath(xbonus, zbonus); return true;
}
else if(test>0 && jarakbonus[0]<=20 && statusbonus==3 ) { if(level==2 || level==3) { float xc,zc,xc2,zc2; xc=rotatex(batasdepan[0]-x,batasdepan[1]-z,acceleration)+x; zc=rotatez(batasdepan[0]-x,batasdepan[1]-z,acceleration)+z; jarakbonus[1]=(float) Math.sqrt(Math.pow(xc-xbonus, 2)+Math.pow(zc-zbonus, 2)); xc2=rotatex(batasdepan[0]-x,batasdepan[1]-z,acceleration*-1)+x; zc2=rotatez(batasdepan[0]-x,batasdepan[1]-z,acceleration*-1)+z; jarakbonus[2]=(float) Math.sqrt(Math.pow(xc2-xbonus, 2)+Math.pow(zc2-zbonus, 2)); if(jarakbonus[1]>=jarakbonus[2]) { setirAI(acceleration); } else { setirAI(acceleration*-1); } return true; } } return false; }
Fungsi di atas merupakan prioritas ke dua dalam melakukan pengecekan
AI, karena fungsi di atas akan melakukan pengecekan terhadap penghindaran
jebakan dan serangan serta pengambilan
item bonus
yang terlihat. Dan apabila
level easy
yang
user
pilih maka AI tidak dapat melakukan penghindaran terhadap
ranjau.
Segmen 4.3.3.6. jalanAI3
public void jalanAI3(float[] ptx,float[] ptz) {
menujupath(ptx[indexpathAI], ptz[indexpathAI]); }
Fungsi di atas merupakan prioritas terakhir dalam melakukan pengecekan
AI, karena fungsi di atas hanya akan membuat AI berjalan sesuai
path
yang telah
ditentukan sesuai dengan rumus
steering
yang ada pada bab 3.
Segmen 4.3.3.7. setjalan
path
AI
public void setjalanpathAI(float[] ptx,float[] ptz,int indexpitstart,int indexpitfinish)
{
float[] jarakpath=new float[9]; int[] indexpath=new int[9]; int[] operator=new int[9]; operator[0]=0; operator[1]=1; operator[2]=2; operator[3]=3; operator[4]=4; operator[5]=-1; operator[6]=-2; operator[7]=-3; operator[8]=-4; for(int i=0;i<9;i++) { indexpath[i]=indexpathAI+operator[i]; if(HP>0.1*HPmax) {
if(indexpath[i]>=indexpitstart) { if(operator[i]<0) { indexpath[i]=0; } else { indexpath[i]=operator[i]; } } } if(indexpath[i]>=indexpitfinish+1) { if(operator[i]<0) { indexpath[i]=0; } else { indexpath[i]=operator[i]; } } if(indexpath[i]<0) { indexpath[i]=0; } jarakpath[i]=(float) Math.sqrt(Math.pow(ptx[indexpath[i]]-x, 2)+Math.pow(ptz[indexpath[i]]-z, 2)); } int index=indexpath[0]; float min=jarakpath[0]; for(int i=0;i<9;i++) { if(jarakpath[i]<min) { min=jarakpath[i]; index=indexpath[i]; } }
float[] jarakpath2=new float[2]; int[] indexpath2=new int[2]; int[] operator2=new int[2]; operator2[0]=0;
operator2[1]=1; //operator2[2]=-1; for(int i=0;i<2;i++) { indexpath2[i]=index+operator2[i]; if(HP>0.1*HPmax) { if(indexpath2[i]>=indexpitstart) { if(operator2[i]<0) { indexpath2[i]=0; } else { indexpath2[i]=operator2[i]; } } } if(indexpath2[i]>=indexpitfinish+1) { if(operator2[i]<0) { indexpath2[i]=0; } else { indexpath2[i]=operator2[i]; } } if(indexpath2[i]<0) { indexpath2[i]=0; } jarakpath2[i]=(float) Math.sqrt(Math.pow(ptx[indexpath2[i]]-x, 2)+Math.pow(ptz[indexpath2[i]]-z, 2)); } ///// if(jarakpath2[0]<=30) { if(indexpath2[1]>=indexpathAI) { indexpathAI=indexpath2[1];
} else { if(HP>0.1*HPmax) { if(indexpathAI==indexpitstart-1) { indexpathAI=indexpath2[1]; } } else { if(indexpathAI==indexpitfinish) { indexpathAI=indexpath2[1]; } } } } else { if(indexpath2[0]>=indexpathAI) { indexpathAI=indexpath2[0]; } else { if(HP>0.1*HPmax) { if(indexpathAI==indexpitstart-1) { indexpathAI=indexpath2[0]; } } else { if(indexpathAI==indexpitfinish) { indexpathAI=indexpath2[0]; } } } }
float jarakpathbaru=(float) Math.sqrt(Math.pow(ptx[indexpathAI]-x, 2)+Math.pow(ptz[indexpathAI]-z, 2)); if(jarakpathbaru<7) { indexpathAI++; if(HP>0.1*HPmax) { if(indexpathAI>=indexpitstart) { indexpathAI=0; } } if(indexpathAI==indexpitfinish+1) { indexpathAI=0; } } if(indexpathAI>=indexpitstart+1) { kecepatan=kecepatanmin+0.3f; //HP=HPmax; } if(indexpathAI>=indexpitfinish) { HP=HPmax; } }
Fungsi di atas digunakan oleh AI untuk menentukan
path
yang akan dituju
serta mencari
path
apabila AI keluar dari jalur
path
dengan mencari
path
dari
path
AI terakhir ditambah dan dikurangi empat dan mengambil
path
terdekat serta
mengatur apakah AI harus masuk
pitstop
atau tidak. Pada
source code
di atas
dijelaskan pertama kali AI akan mencari
path
terdekat dari AI dari range empat
path
dari
path AI
terakhir, kemudian mencari range 3 dari
path
terdekat dan
apabila jarak AI sekarang lebih kecil dari 30 maka AI akan mencari
path
berikutnya.
Segmen 4.3.3.8. cari
pathuser
public void caripathuser(float[] ptx,float[] ptz,int indexpitstart,int indexpitakhir)
{
if(masukpit==false) {
float[] jarakpath=new float[9]; int[] indexpath=new int[9]; int[] operator=new int[9]; operator[0]=0; operator[1]=1; operator[2]=2; operator[3]=3; operator[4]=4; operator[5]=-1; operator[6]=-2; operator[7]=-3; operator[8]=-4; for(int i=0;i<9;i++) { indexpath[i]=indexpathAI+operator[i]; if(indexpath[i]>=indexpitakhir+1) { indexpath[i]=operator[i]; } if(indexpath[i]<0) { indexpath[i]=indexpitakhir; } jarakpath[i]=(float) Math.sqrt(Math.pow(ptx[indexpath[i]]-x, 2)+Math.pow(ptz[indexpath[i]]-z, 2)); } int index=indexpath[0]; float min=jarakpath[0]; for(int i=0;i<9;i++) { if(jarakpath[i]<min) { min=jarakpath[i]; index=indexpath[i]; }
}
float[] jarakpath2=new float[3]; int[] indexpath2=new int[3]; int[] operator2=new int[3]; operator2[0]=0; operator2[1]=1; operator2[2]=-1; for(int i=0;i<3;i++) { indexpath2[i]=index+operator2[i]; if(indexpath2[i]>=indexpitakhir+1) { indexpath2[i]=operator2[i]; } if(indexpath2[i]<0) { indexpath2[i]=indexpitakhir; } jarakpath2[i]=(float) Math.sqrt(Math.pow(ptx[indexpath2[i]]-x, 2)+Math.pow(ptz[indexpath2[i]]-z, 2)); } if(jarakpath2[0]<=10) { float test; int i=0; boolean cek=true; do { test = (batasdepan[0]-x)*(ptx[indexpath2[i]]-x) + (batasdepan[1]-z)*(ptz[indexpath2[i]]-z); if(test>0) { index=indexpath2[i]; cek=false; } i++;
}while(i<3 && cek==true); indexpathAI=index;
} else {
} }
float jarakpathpit=(float)
Math.sqrt(Math.pow(ptx[indexpitstart]-x, 2)+Math.pow(ptz[indexpitstart]-z, 2));
if(jarakpathpit<=20 && masukpit==false) { masukpit=true; indexpathAI=indexpitstart; acceleration+=3; } if(masukpit==true) { kecepatan=kecepatanmin+0.3f; jarakpathpit=(float) Math.sqrt(Math.pow(ptx[indexpathAI]-x, 2)+Math.pow(ptz[indexpathAI]-z, 2)); if(jarakpathpit<8) { indexpathAI++; if(indexpathAI>=indexpitakhir+1) { HP=HPmax; indexpathAI=0; masukpit=false; acceleration-=3; } } } }