Pendahuluan
Salah satu elemen penting yang mampu membuat game menarik adalah simulasi fisika.
Simulasi yang akurat akan membuat objek dan karakter di game bergerak dengan akurat
juga sesuai hukum fisika. Di tutorial ini, kita akan belajar tentang simulasi fisika 2D di Unity
dengan mengembangkan game Pong.
Pong adalah salah satu game komputer awal dan sederhana, yang pertama dikembangkan
dengan konsep simulasi tenis meja 2D oleh Allan Alcorn, dan dipublikasi oleh Atari.
Tampilan game Pong asli dapat dilihat di gambar di bawah.
Game Pong dimainkan oleh dua pemain. Masing-masing pemain mengendalikan sebuah
raket berbentuk persegi panjang yang terletak di kiri dan kanan scene, serta bisa bergerak
secara vertikal. Pada setiap ronde, sebuah bola akan bergerak dari tengah menuju salah
satu pemain. Pemain tersebut harus mencegah bola tersebut melewati raketnya. Jika tidak,
lawan akan mendapat skor dan bola akan kembali ke tengah. Game scene-nya dibatasi oleh
empat buah dinding yang tak terlihat di tiap sisinya. Jika mengenai dinding atas atau bawah,
bola akan terpantul. Sementara, jika bola menyentuh dinding di belakang raket seorang
pemain, lawannya akan mendapat poin.
Sebelum memulai implementasi game Pong, kita perlu mengenali terlebih dahulu beberapa
komponen dasar simulasi fisika 2D di Unity. Di tutorial ini, kita akan menggunakan
komponen-komponen berikut.
3. Collider 2D digunakan untuk mendeteksi benturan (collision) antar objek 2D. Bentuk
sebuah collider biasanya menyerupai bentuk kasar objek aslinya, namun tidak harus
terlalu persis demi efisiensi komputasi. Sebuah collider juga bisa diatur
sebagai trigger, yang mendeteksi event ketika objek lain masuk dan bertumpang tindih
(overlap) dengan area objek ini, tanpa perlu mensimulasi tumbukan. Ini dapat
digunakan ketika event ini hanya mempengaruhi aturan main game yang diatur
melalui skrip, seperti meningkatkan skor salah satu pemain, atau mendeteksi ketika
seorang karakter memasuki ruangan tertentu. Unity menyediakan berbagai
bentuk collider, yaitu lingkaran, box/segi empat, poligon (harus tertutup), edge (tidak
harus tertutup), kapsul, dan composite (kombinasi box dan poligon).
Untuk isian Project name, ketik Pong. Lalu, masukkan direktori projek. Folder Pong nanti
akan dibuat di direktori tersebut. Untuk Template, pastikan bahwa kita memilih 2D. Terakhir,
klik Create Project. Tampilan window berikut akan muncul, dan kita bisa memulai
pengembangan Pong.
Implementasi Game Pong - Kamera
Untuk mengembangkan game Pong, ada beberapa elemen yang perlu diimplementasikan,
yaitu kamera, pemain/raket (termasuk input dan pergerakannya), bola (termasuk
pergerakannya), dinding (visual dan sistem Physics-nya), dan game manager (termasuk
pemberian skor dan tampilan GUI).
Prototype game Pong ini dibuat melalui pengembangan lebih jauh dari projek berikut:
Kamera
Ketika membuat projek baru, Unity otomatis membuat satu scene baru dengan
nama SampleScene, yang terletak di folder Assets > Scene. Untuk tutorial ini, scene ini kita
namai ulang menjadi Pong dengan cara klik kanan SampleScene di panel Project, lalu
klik Rename, dan ketik nama barunya. Cara lainnya adalah dengan menekan F2 di scene
tersebut dan mengetikkan nama barunya.
Jika dilihat di panel Hierarchy, scene ini sudah memuat satu kamera utama (Main Camera).
Sebagai permulaan, ganti warna tampilan menjadi hitam dengan klik kamera di Hierarchy,
lalu klik Background di panel Inspector untuk memunculkan tampilan Color seperti di bawah.
Klik di sisi bawah roda kotak warna, atau masukkan nilai R, G, B, A = 0, 0, 0, 255.
Kemudian, ubah ukuran (Size) kamera di Inspector menjadi 10. Ini akan memperbesar
cakupan game scene yang akan muncul di kamera. Tampilan akhir kamera utama
di Inspector adalah sebagai berikut.
Implementasi Game Pong - Raket
Dalam game ini, raket bisa direpresentasikan sebagai sprite (gambar 2D) persegi panjang
putih. Kita akan menggunakan sprite berukuran 30x200. Sprite dapat dibuat di program
ilustrasi apapun, seperti MS Paint. Beri nama file ini racket.jpg, dan letakkan di folder Assets.
Drag file raket ini ke panel Hierarchy, dan beri nama Player1. Tampilan Unity adalah sebagai
berikut.
Nanti kita akan memindahkan raket ini ke sisi kiri layar, tetapi sebelum itu kita akan
menjadikan raket tersebut objek Physics terlebih dahulu. Hal ini dapat dilakukan dengan
menambah komponen Rigidbody dan Collider ke kedua raket.
Komponen Rigidbody membuat pergerakan sebuah objek di Unity dipengaruhi hukum fisika,
misalnya gaya, gravitasi, dan impulse. Untuk menambahkan komponen Rigidbody, klik
Player1. Lalu, di panel Inspector, klik Add Component, pilih Physics 2D > Rigidbody 2D.
Pastikan bahwa yang dipilih adalah Physics 2D, karena pilihan satunya (Physics) adalah
untuk objek 3D. Di konfigurasinya di panel Inspector, untuk Body Type, pilih Kinematic. Ini
akan menghilangkan efek hukum fisika di raket tersebut. Kita juga bisa nanti dengan mudah
mengendalikan raket tersebut lewat skrip C#.
Komponen lain yang perlu ditambahkan adalah collider, yang digunakan untuk mendeteksi
tubrukan sebuah objek dengan objek lainnya. Jika tubrukan terdeteksi, kita bisa mendesain
bagaimana respon objek-objek yang bertubrukan tersebut. Seperti ditulis di tutorial
pengenalan komponen-komponen fisika, ada berbagai macam bentuk collider,
misalnya box, circle, dan polygon. Untuk objek raket ini, kita akan memilih bentuk box.
Masih dalam kondisi Player1 terpilih, untuk menambahkan komponen Collider, lalu di
panel Inspector, klik Add Component. Pilih Physics 2D > Box Collider 2D. Sama seperti
sebelumnya, pastikan bahwa yang dipilih adalah Physics 2D. Kemudian, pastikan bahwa
ukuran collider sesuai dengan ukuran objek. Caranya, masih dalam kondisi Player1 terpilih,
di panel Inspector, bagian komponen Box Collider 2D, klik Edit Collider. Akan muncul kotak
dengan garis batas hijau muda seperti berikut.
Jika bentuk collider tidak sesuai dengan bentuk objek, geser garis-garis batas tersebut
dengan klik + tahan di titik-titik hijau, lalu tarik ke arah yang diinginkan.
Berikutnya, kita harus membuat raket-raket ini dapat dikendalikan pemain. Untuk itu, kita
akan menambahkan script C# ke masing-masing raket. Namun, sebelum melanjutkan lebih
jauh, kita akan sedikit membahas anatomi skrip C# di Unity.
Seperti biasanya di bahasa pemrograman C#, setiap file wajib memiliki nama yang sama
dengan nama kelas utama di dalamnya. Ketika file skrip C# dibuat di Unity,
secara default file ini akan memuat kelas dengan nama yang sama dengan nama file-nya.
Kelas ini merupakan subclass dari MonoBehaviour, yang membuat kelas ini berinteraksi
dengan sistem internal Unity. Dua metode secara otomatis dibuat di kelas ini,
yaitu Start() dan Update(). Metode Start() akan dijalankan tiap kali objek dengan skrip ini
menjadi aktif (termasuk ketika pertama dibuat), sehingga metode ini berfungsi seperti
sebuah konstruktor. Di sisi lain, metode Update() akan dijalankan pada setiap frame selama
objek ini aktif.
Untuk membuat skrip untuk pemain, dengan Player1 terpilih, klik Add Component > New
Script, ketik PlayerControl seperti di bawah, lalu klik Create and Add. Langkah ini akan
membuat script PlayerControl.cs yang tertambahkan di objek Player1.
Klik dua kali di skrip ini (bisa di panel Project ataupun Inspector), dan file-nya akan terbuka di
editor (di tutorial ini, yang digunakan adalah Visual Studio, tapi editor lain juga bisa
digunakan). Tampilannya adalah sebagai berikut.
Untuk memastikan bahwa komponen-komponen Unity sudah dimuat, cek bahwa di bagian
atas script tertulis:
using UnityEngine;
Script ini memuat kelas PlayerControl, yang akan melakukan tiga hal, yaitu:
Untuk menggerakkan raket, kita akan menggunakan input keyboard. Kita akan
mendeklarasikan dua variabel bertipe KeyCode, yaitu upButton untuk bergerak ke atas
dan downButton untuk ke bawah. Secara default, kita atur kedua variabel ini menjadi tombol
W untuk ke atas dan S untuk ke bawah. Nantinya ini bisa diatur lagi lewat Unity untuk
pemain yang berbeda.
// Kecepatan gerak
public float speed = 10.0f;
// Batas atas dan bawah game scene (Batas bawah menggunakan minus (-))
public float yBoundary = 9.0f;
// Skor pemain
Di dalam kelas ini, terdapat metode Start() yang dijalankan tiap kali objek menjadi aktif
(termasuk pertama kali dikonstruksi). Di dalam metode ini, kita perlu memuat rigidBody2D
sebagai berikut, untuk dikendalikan melalui script ini.
rigidBody2D = GetComponent<Rigidbody2D>();
Metode lain yang terletak di kelas ini adalah Update(), yang akan dijalankan pada
setiap frame. Ada dua hal yang perlu dilakukan, yaitu menggerakkan raket, dan memastikan
bahwa raket tidak keluar dari batas game scene. Proses pertama dapat dilakukan dengan
kode berikut.
// Dapatkan kecepatan raket sekarang.
Vector2 velocity = rigidBody2D.velocity;
Pada titik ini, posisi raket bisa berada di luar batas game scene. Menggunakan variable
yBoundary yang sudah kita deklarasikan sebelumnya untuk membatasi ruang gerak raket,
kode di bawah akan membuat posisi raket tetap di yBoundary jika raket tersebut melewati
batas atas, atau -yBoundary jika melewati batas bawah.
Elemen terakhir dari skrip ini adalah manajemen skor. Di atas, kita sudah mendeklarasikan
variable score yang menyimpan skor pemain yang berasosiasi dengan raket tertentu. Skor
pemain nanti akan diatur setelah nantinya kita mengimplementasikan dinding. Proses ini
memerlukan tiga metode berikut, yaitu IncrementScore() untuk menaikkan skor pemain
sebanyak 1 poin, ResetScore() untuk mengembalikan skor ke 0, dan property Score untuk
mengakses variabel skor dari kelas lain.
Jika kita kembali ke window Unity, akan terlihat komponen skrip C# terletak di objek Player1.
Ada beberapa variabel yang bisa dikonfigurasi. Untuk Player1, kita akan menggunakan
nilai default, yaitu tombol W untuk bergerak ke atas (Up Button), S untuk ke bawah (Down
Button), speed = 10, dan yBoundary = 9.
Kita sekarang selesai mengkonfigurasikan Player1, dan akan membuat objek Player2. Untuk
mudahnya, kita akan menggunakan prefab, yang dapat menyimpan sebuah objek sebagai
file dan digunakan kembali. Menggunakan prefab untuk membuat objek-objek serupa tidak
hanya cepat, tetapi juga menjaga sinkronisasi antar objek yang berasal dari prefab yang
sama.
Untuk membuat prefab, pastikan Player1 masih berada di posisi (0,0,0), lalu tarik ke
direktori aktif di panel Project, dan namai ulang menjadi Player. Kemudian, tarik kembali
prefab Player ke Hierarchy, dan beri nama objek ini Player2. Ubah posisi Player1 menjadi (-
15,0,0), dan Player2 menjadi (15,0,0). Ini tidak akan memutuskan koneksi kedua objek
dengan prefab. Terakhir, untuk Player2, beri tombol lain untuk menggerakannya, yaitu P
untuk ke atas, dan L untuk ke bawah. Tampilan saat ini, dengan Player2 dipilih, adalah
sebagai berikut.
Implementasi Game Pong - Bola
Setelah membuat raket, kita sekarang akan mengimplementasikan bola, termasuk tampilan
dan pergerakannya. Di tutorial ini, bola akan mengikuti gerak lurus beraturan (GLB/linear
motion).
Untuk tampilannya, kita akan menggunakan file di bawah ini. Perhatikan bahwa background-
nya transparan, supaya kita tetap bisa melihat background game ini.
Simpan file ini di folder Assets dengan nama ball.jpg, lalu tarik ke panel Hierarchy. Objek
bola dengan nama Ball akan tampil di Scene seperti berikut. Perhatikan bahwa objek ini
secara otomatis berisi komponen Sprite Renderer, yang akan menampilkan file gambar bola
di atas di layar.
Seperti halnya objek Raket, kita akan menambahkan tiga komponen ke objek bola,
yaitu rigidbody, collider, dan skrip kontrol bola. Untuk rigidbody, tambahkan komponen
Rigidbody2D. Berbeda dengan raket, pergerakan bola akan dipengaruhi gaya fisik. Maka,
untuk body type-nya kita atur menjadi dynamic.
Setelah mengatur Rigidbody, tambahkan komponen Circle Collider 2D ke objek ini. Circle
dipilih karena paling menyerupai bentuk bolanya. Pastikan bahwa
ukuran collider menyerupai ukuran bolanya, seperti berikut.
Untuk mengatur pergerakan bola, kita perlu mendefinisikan physics material. Untuk
membuatnya, klik kanan di panel Project (folder Assets), lalu pilih Create > Physics Material
2D. Beri nama material ini BallPhysicsMaterial2D. Beri nilai friction = 0, dan bounciness = 1.
Lalu, tarik file ini ke variabel Material di komponen Circle Collider 2D.
Terakhir, kita tambahkan skrip bernama BallControl untuk mengontrol bola ini. Kita
tentukan aturan pergerakan sebagai berikut.
1. Tiap kali sebuah set permainan dimulai, bola akan di-reset ke tengah layar.
2. Setelah dua detik, bola akan secara acak bergerak ke kiri atau ke kanan relatif
terhadap sumbu horizontal.
Pertama-tama, deklarasikan beberapa variabel berikut.
// Rigidbody 2D bola
private Rigidbody2D rigidBody2D;
Lalu, kita definisikan metode ResetBall() untuk mengembalikan bola ke tengah layar dan
membuatnya tidak bergerak (poin nomor 1).
void ResetBall()
{
// Reset posisi menjadi (0,0)
transform.position = Vector2.zero;
Setelah itu, tulis metode PushBall() untuk menginisialisasi gerakan bola. Karena
menggunakan sistem dinamika (dan bukan kinematika), bola didorong menggunakan gaya
dengan memanggil metode rigidBody2D.AddForce(). Komponen x gaya ini ditentukan
besarnya nilai variabel xInitialForce, dengan arah yang ditentukan secara acak. Sementara
itu, komponen y ditentukan secara acak dengan nilai minimum -yInitialForce dan nilai
maksimum yInitialForce.
void PushBall()
{
// Tentukan nilai komponen y dari gaya dorong antara -yInitialForce dan yI
nitialForce
else
}
}
Berikutnya, kita definisikan metode RestartGame() yang akan dipanggil setiap kali game
diulang, yaitu saat pertama kali game dimulai, atau ketika bola masuk melewati raket
seorang pemain. Di metode ini, Invoke() digunakan untuk memanggil fungsi lain setelah
waktu yang ditentukan (dalam detik).
void RestartGame()
{
// Kembalikan bola ke posisi semula
ResetBall();
Terakhir, di dalam metode Start(), kita tulis metode untuk memulai game sebagai berikut.
void Start()
{
rigidBody2D = GetComponent<Rigidbody2D>();
// Mulai game
RestartGame();
}
Kembali ke Unity, pilih objek Ball. Akan terlihat bahwa di komponen skrip Ball Control ada
box untuk menentukan besarnya gaya yang diberikan ke bola. Di sini, kita isi X Initial Force =
50 dan Y Initial Force = 15.
Perlu diingat bahwa respon bola ketika bertumbukan dengan raket akan ditangani oleh
simulasi fisika, dan tidak perlu diimplementasikan di skrip ini.
Jika Unity dijalankan, bisa dilihat bahwa setelah 2 detik, bola akan bergerak ke arah yang
ditentukan secara acak. Jika berbenturan dengan raket, bola akan memantul. Namun
demikian, jika melewati tampilan preview game, bola tersebut akan berjalan terus. Untuk
mencegah hal ini, di bagian berikutnya kita akan mengimplementasikan dinding.
Implementasi Game Pong - Dinding
Dinding dibuat untuk membatasi arena game dan mencegah bola bergerak terlalu jauh.
Dalam tutorial ini, dinding akan dibuat menjadi empat objek yang tak terlihat, tetapi masing-
masing memiliki colliders. Perbedaan dari keempat objek ini adalah, dinding di atas dan
bawah hanya akan memantulkan bola, sementara dinding di kiri dan kanan tidak
memantulkan bola, melainkan menambah skor pemain (akan diimplementasikan di bagian
berikut) dan me-reset game.
Pertama-tama, buat objek kosong untuk mengelompokkan keempat dinding dengan klik
kanan di panel Hierarchy, lalu pilih Create Empty. Klik kanan di objek tersebut,
pilih Rename, dan beri nama Walls.
Klik kanan di Walls, lalu pilih Create Empty. Akan terbentuk objek baru di bawah Walls. Beri
nama BottomWall. Kemudian, berikan komponen Box Collider 2D, dan edit bentuknya
supaya menempel di sisi bawah layar kamera. Alternatifnya, atur offset-nya menjadi (0, -9.5),
serta size-nya menjadi (33.6, 1), keduanya untuk masing-masing nilai X dan Y. Pastikan
opsi IsTriggered tidak terpilih.
Untuk membuat dinding atas, klik Bottom Wall di panel Hierarchy, lalu buat salinannya (Ctrl +
C, lalu Ctrl + V; atau langsung Ctrl + D) masih di bawah objek Walls. Beri nama objek baru
ini Top Wall, lalu beri nilai Offset Y menjadi 9.5. Nilai parameter lainnya sama dengan Bottom
Wall.
Seperti tertulis sebelumnya, dinding samping akan sedikit berbeda. Sama seperti
sebelumnya, kita bisa membuat duplikat salah satu dinding untuk membuat dinding kiri.
Beri nama objek baru ini Left Wall, lalu atur offset-nya menjadi (-17.3, 0), serta size-nya
menjadi (1, 18), keduanya untuk masing-masing nilai X dan Y. Yang berbeda adalah, pastikan
opsi IsTriggered terpilih. Ini akan membuat dinding ini semata-mata menjadi trigger yang
mempengaruhi simulasi fisika.
Untuk mengatur perilaku objek saat menjadi trigger, kita tambahkan skrip baru yang akan
kita beri nama SideWall. Skrip ini memuat variabel player, sebagai berikut, yang akan
mengasosiasikan dinding ini dengan seorang pemain.
// Pemain yang akan bertambah skornya jika bola menyentuh dinding ini.
public PlayerControl player;
Untuk kali ini, kita hanya menambahkan metode OnTriggerEnter2D() di skrip SideWall.
// Akan dipanggil ketika objek lain ber-collider (bola) bersentuhan dengan din
ding.
void OnTriggerEnter2D(Collider2D anotherCollider)
{
// Jika objek tersebut bernama "Ball":
if (anotherCollider.name == "Ball")
{
// Tambahkan skor ke pemain
player.IncrementScore();
// Jika skor pemain belum mencapai skor maksimal...
if (player.Score < gameManager.maxScore)
{
// ...restart game setelah bola mengenai dinding.
anotherCollider.gameObject.SendMessage("RestartGame", 2.0f, SendMe
ssageOptions.RequireReceiver);
}
}
}
Metode OnTriggerEnter2D() akan dipanggil ketika bola mengenai dinding. Perhatikan bahwa
metode ini memiliki parameter anotherCollider bertipe Collider2D, yang berarti objek yang
mengenai harus memiliki komponen Collider2D. Jika objek tersebut bernama “Ball”, skor
pemain yang bersangkutan akan ditambah. Jika skor pemain masih belum mencapai skor
maksimal sesuai konfigurasi di GameManager, game akan di-restart (bola kembali ke tengah
dan diluncurkan kembali). Perlu dicatat bahwa kondisi ketika salah satu pemain menang
(mencapai skor maksimal) akan ditangani oleh GameManager.
Pada bagian ini, metode SendMessage() akan memanggil metode ResetBall() di skrip yang
termuat di objek Ball setelah 2 detik, dan mengembalikan bola ke tengah.
Argumen SendMessageOptions.RequireReceiver memastikan bahwa objek Bola memuat
komponen dengan metode bernama “ResetBall”. Jika tidak, sebuah exception akan diberikan.
Kembali ke Unity, dapat dilihat bahwa di skrip SideWall di objek Left Wall dan Right Wall, ada
opsi untuk menentukan pemain yang mendapat skor ketika bola menyentuh dinding ini.
Untuk Left Wall, tarik Player2 ke opsi ini. Untuk Right Wall, masukkan Player1. Gambar
konfigurasi masing-masing dinding adalah sebagai berikut.
Tampilan akhir semua dinding, ketika objek Walls diklik, dapat dilihat seperti di bawah ini.
Di tutorial berikut, kita akan sedikit memodifikasi skrip SideWall untuk berinteraksi
dengan Game Manager.
Untuk membuat objeknya, klik kanan di panel Hierarchy, dan pilih Create Empty. Beri nama
objek ini Game Manager. Pastikan posisinya ada di (0, 0, 0). Kemudian, tambahkan skrip
dengan klik Add Component di panel Inspector, langsung ketik GameManager di box, klik New
Script, lalu klik Create and Add.
// Pemain 1
public PlayerControl player1; // skrip
private Rigidbody2D player1Rigidbody;
// Pemain 2
public PlayerControl player2; // skrip
private Rigidbody2D player2Rigidbody;
// Bola
public BallControl ball; // skrip
private Rigidbody2D ballRigidbody;
private CircleCollider2D ballCollider;
// Skor maksimal
public int maxScore;
Untuk menampilkan GUI dan menangani respon GUI, kita menggunakan metode OnGUI().
Metode ini akan melakukan beberapa hal, yaitu:
Langkah terakhir di tutorial ini adalah memodifikasi skrip SideWall yang dibuat di tutorial
sebelumnya, supaya dinding di samping juga bisa berinteraksi dengan Game Manager untuk
mengakses skor maksimal dan membandingkannya dengan skor pemain saat bola
melewati dinding ini.
Lalu, di window Unity, tarik objek Game Manager ke properti Game Manager di
komponen SideWall untuk objek Left Wall dan Right Wall.
Setelah kita mengimplementasikan kelima elemen ini, game Pong bisa dimainkan.
Skrip pertama yang akan kita modifikasi adalah PlayerControl. Ini dilakukan untuk nantinya
mengakses informasi tumbukan antara raket seorang pemain dengan bola. Modifikasi
dilakukan di skrip PlayerControl, dan bukan BallControl, karena kita akan menampilkan
informasi dari kedua pemain secara bersamaan, dan tidak ingin menimpa informasi dari
pemain lain.
Untuk merekam titik kontak dengan bola, definisikan metode OnCollisionEnter2D, yang akan
dipanggil raket pemain mengalami tumbukan. Jika tumbukan tersebut adalah dengan bola,
rekam titik kontak pertamanya menggunakan metode GetContact.
Kita juga akan memodifikasi skrip BallControl untuk merekam titik tumbukan terakhir.
Informasi ini digunakan untuk menghitung garis pantulan gerakan bola.
Nilai awal variabel ini ketika game dimulai adalah sesuai lokasi bola. Maka, tambahkan baris
berikut di metode Start().
trajectoryOrigin = transform.position;
Variabel ini akan di-update tiap kali bola bertumbukan dengan objek lain, sesuai lokasi bola
tersebut. Untuk merekam informasi ini, tulis metode OnCollisionExit2D seperti berikut.
// Ketika bola beranjak dari sebuah tumbukan, rekam titik tumbukan tersebut
private void OnCollisionExit2D(Collision2D collision)
{
trajectoryOrigin = transform.position;
}
Modifikasi terakhir kelas ini adalah membuat properti untuk mengakses variabel tersebut.
Kode berikut akan ditambahkan di akhir metode OnGUI() di kelas GameManager untuk
menampilkan tombol aktivasi/deaktivasi debug window, beserta debug window tersebut.
Pertama-tama, buat percabangan berikut.
Di dalam percabangan ini, kita harus mengkonfigurasi warna debug window dengan
memodifikasi properti di kelas GUI. Properti ini bersifat global (mempengaruhi semua
elemen antarmuka grafis), sementara kita akan membuat modifikasi ini hanya berpengaruh
terhadap debug window. Oleh karena itu, kita akan menyimpan warna GUI lama untuk nanti
digunakan kembali.
Sekarang, kita akan mengakses nilai-nilai variabel fisika yang akan ditampilkan dan
menyimpan semuanya menjadi sebuah teks. Penjelasan singkat variabel-variabel ini adalah
sebagai berikut.
1. Massa (mass) adalah properti intrinsik sebuah objek, yang dalam konteks dinamika,
menjelaskan resistansi objek tersebut terhadap perubahan pergerakan. Variabel ini
diakses melalui rigidbody.
2. Kecepatan (velocity) merupakan sebuah vektor yang mendeskripsikan perubahan
posisi objek tersebut terhadap waktu. Variabel ini diakses melalui rigidbody.
3. Laju (speed) merupakan besarnya (magnitude) kecepatan. Variabel ini diakses
melalui rigidbody.
4. Momentum sebuah objek menjelaskan seberapa susahnya menghentikan sebuah
objek dari gerakan semulanya. Semakin besar massa dan kecepatan sebuah objek,
makin susah benda tersebut dihentikan. Oleh karena itu, jika massa dan kecepatan
masing-masing dilambangkan sebagai m dan v, momentum p dapat dihitung sebagai
p = mv. Variabel ini tidak dapat diakses dari Unity, dan akan dihitung menggunakan
rumus tersebut.
5. Friction adalah gaya gesek yang diterapkan sebuah objek terhadap objek lain. Variabel
ini diakses melalui collider.
6. Impulse, secara teoritis, adalah total gaya yang diterapkan kepada sebuah objek
selama rentang waktu tertentu. Namun demikian, dalam konteks game engine,
impulse biasa diartikan sebagai gaya instan dengan nilai besar yang diterapkan
kepada sebuah objek, untuk menyederhanakan penghitungan. Impulse dapat diakses
dari titik tumbukan (ContactPoint2D) dan terdiri dari komponen normal (searah vektor
normal permukaan di titik tumbukan) dan tangensial (tegak lurus vektor normal).
Setelah membuat teks yang ditampilkan, buat debug window-nya dan tampilkan teks
tersebut. Debug window akan tampil sebagai text area di bagian tengah bawah layar.
Perlu diingat bahwa kode sampai dengan baris di atas harus ditulis di dalam percabangan.
Yang perlu diperhatikan dalam menampilkan prediksi lintasan ini adalah bahwa gerakan
belum terjadi, dan kita perlu melakukan simulasi untuk menentukan apakah akan terjadi
tumbukan. Salah satu metode yang banyak digunakan adalah menggunakan raycasting,
yaitu dengan “menembakkan” sebuah sinar (ray) dari sebuah titik (pusat bola) sesuai arah
gerak bola, dan melihat apakah sinar ini akan mengenai objek lain. Namun, cara ini tidak
akurat, karena titik tumbukan tidak akan berada di pusat bola, melainkan di pinggir bola.
Lokasi persis titik ini juga belum diketahui. Oleh karena itu, kita akan menggunakan
mekanisme circle casting, yaitu dengan melakukan simulasi pergerakan lingkaran sesuai
arah gerak bola. Lingkaran dipilih karena menyerupai bentuk collider bola.
Tantangan lain adalah menentukan garis lintasan. Karena kalkulasi akan dilakukan berdasar
titik tumbukan di pinggir bola, kita mungkin terpikir untuk menggambar garis dari titik
pinggir bola saat ini ke titik pinggir bola saat tumbukan. Kelemahan cara ini adalah terlihat
tidak intuitif bagi pemain. Oleh karena itu, kita akan menggambar garis dari titik pusat bola
saat ini ke titik pusat bola saat tumbukan. Cara ini masih terlihat kurang intuitif, karena titik
pantulan tidak akan terlihat di objek lain yang bertumbukan. Solusinya, kita akan
menampilkan bola bayangan, yang menandakan lokasi bola saat terjadi tumbukan.
Di tutorial ini, kita menggunakan plugin untuk menggambar garis dari artikel berikut.
https://www.knowledgescoops.com/2019/07/creating-dotted-line-in-unity_29.html
https://github.com/KunalT6569/DottedLineInUnity2D/raw/master/Exported%20Asset/Dotte
dLineAsset.unitypackage
Double click dan instal paket tersebut. Akan muncul tampilan berikut.
Objek kedua yang dibuat adalah bola bayangan. Buat duplikat objek Ball, dan beri nama
objek baru ini BallAtCollision. Kita tidak akan melakukan simulasi fisika dengan objek ini
maupun membuat pemain mengontrol gerakan bola bayangan. Jadi, hapus
komponen Rigidbody 2D, Circle Collider 2D, dan skrip BallControl. Perlu diperhatikan bahwa
kotak di sebelah nama objek di panel Inspector harus dikosongkan (tidak ada tanda
centang), karena kita tidak akan menampilkan objek ini dari awal. Terakhir, untuk membuat
objek ini sedikit transparan, klik Color, dan beri nilai komponen A (untuk Alpha) menjadi 80.
Tampilan konfigurasinya adalah sebagai berikut.
Kembali ke objek Trajectory, kita buat skrip baru Trajectory (klik Add Component > New Script,
ketik Trajectory, lalu klik Create and Add). Di dalam kelas Trajectory, deklarasikan variabel-
variabel terkait bola, sekaligus collider dan rigidbody-nya, beserta objek bola bayangan.
Variabel ball dan ballAtCollision nanti akan kita inisialisasi dari panel Inspector di Unity.
Sementara, metode Start() akan memuat collider dan rigidbody bola.
Lintasan bola akan ditampilkan dan diperbarui di setiap frame. Implementasi proses
kalkulasi dan penampilan bola dilakukan di metode Update(). Pertama-tama, buat
variabel drawBallAtCollision, yang akan menentukan apakah kita akan menggambar bola
bayangan.
// Inisiasi status pantulan lintasan, yang hanya akan ditampilkan jika lint
asan bertumbukan dengan objek tertentu.
bool drawBallAtCollision = false;
Lalu, deklarasikan offsetHitPoint, yaitu lokasi titik tengah bola saat tumbukan terjadi.
Physics2D.CircleCastAll(ballRigidbody.position, ballCollider.radius,
ballRigidbody.velocity.normalized);
Kode berikut digunakan untuk mencari titik tumbukan pertama dengan collider lain, dan
collider tersebut bukan milik bola.
Untuk menggambar garis lintasan, titik awalnya adalah lokasi bola saat ini. Sementara,
penghitungan titik akhirnya dilakukan di titik-titik di atas sebagai berikut.
Pertama-tama, tentukan titik tumbukan bola dengan objek ini, beserta vektor normal objek
pada titik ini. Perlu diingat lagi bahwa titik tumbukan berada di pinggir bola.
// Garis lintasan akan digambar dari titik tengah bola saat ini ke
titik tengah bola pada saat tumbukan,
// yaitu sebuah titik yang di-offset dari titik tumbukan berdasar
vektor normal titik
tersebut sebesar
// jari-jari bola.
Hitung offsetHitPoint dengan menggeser titik tumbukan sepanjang vektor hitNormal sesuai
radius bola.
// Gambar garis lintasan dari titik tengah bola saat ini ke titik
tengah bola pada saat bertumbukan
DottedLine.DottedLine.Instance.DrawDottedLine(ball.transform.posit
ion, offsetHitPoint);
Bola akan terpantul jika bertumbukan dengan objek selain dinding samping, yang
diidentifikasi dengan adanya kompone skrip SideWall. Pada kasus ini, arah datangnya bola
(inVector) merupakan vektor yang berasal dari titik tumbukan sebelumnya dengan
menuju offsetHitPoint yang dinormalisasi menjadi vektor unit. Perhatikan bahwa titik asal
vektor ini bukan dari titik tengah bola, untuk menjaga konsistensi garis. Vektor pantulan
dihitung menggunakan metode Vector2.Reflect, dengan menggunakan arah datang bola
dan vektor normal objek pada titik tumbukan.
Setelah mengetahui arah datang dan arah pantulan, kita bisa menggambar garis pantulan.
Garis ini hanya akan digambar jika arah pantulan tidak segaris dengan vektor normal (dot
product-nya tidak sama dengan -1 atau 1). Ini bisa terjadi ketika penghitungan arah
pantulan terjadi ketika bola persis menyentuh objek tersebut. Jika tidak segaris, gambar
garis pantulan dari offsetHitPoint, dan titik yang digeser dari offsetHitPoint ke arah vektor
pantulan, sebanyak jarak tertentu (kita gunakan jarak 10 unit). Beri
nilai drawBallAtCollision menjadi true, dan (di luar proses penggambaran garis pantulan)
keluar dari loop.
Lalu, di metode OnGUI(), bagian untuk menampilkan tombol “Toggle Debug Info”,
tambahkan baris berikut.
trajectory.enabled = !trajectory.enabled;
Setelah semua modifikasi skrip ini dilakukan, kita inisialisasi beberapa atribut yang
diperlukan di Unity. Di panel Hierarchy, pilih objek Game Manager, lalu akan muncul
komponen skrip GameManager di Inspector. Tarik objek Trajectory ke atribut Trajectory di
komponen ini. Kemudian, pilih objek Trajectory, dan akan muncul komponen
skrip Trajectory di Inspector. Tarik objek Ball ke atribut Ball, dan objek BallAtCollision ke
atribut Ball At Collision. Terakhir, deaktivasi skrip Trajectory (hilangkan centang di sebelah kiri
judul skrip). Skrip ini hanya aktif ketika game pemain mengeklik tombol “Toggle Debug Info”.
Contoh tampilan debug window dan lintasan bola ketika dimainkan adalah sebagai berikut.
Membuat Aplikasi Mandiri (Standalone)
Unity memiliki fitur untuk mengekspor/building prototipe game kita ke berbagai macam
format, misalnya Windows executable dan Android app. Sebagai contoh sederhana, di sini
kita akan membuat Windows executable supaya pemain bisa memainkan game ini tanpa
Unity.
Di tutorial ini, untuk menyederhanakan, kita hanya akan membuat game dengan rasio
resolusi 16:9. Di window Unity, pilih File > Build Settings. Akan muncul window berikut.
Klik Build, maka akan muncul window dialog untuk memilih lokasi tempat aplikasi akan
dibuat. Sebagai contoh, masuklah ke dalam folder projek game Pong ini, lalu buat
folder Build, dan pilih folder tersebut. Klik Select Folder. Struktur file yang dihasilkan adalah
sebagai berikut.
Perlu dicatat bahwa konfigurasi game ini adalah sesuai template di Unity. Pertama-tama,
jalankan file Pong.exe. Pemain akan melakukan konfigurasi grafik dan input terlebih dahulu
sebagai berikut.
Setelah selesai mengkonfigurasi dan klik “Play!”, Dan game Pong bisa dimainkan.
Pong - Tugas
1. Kekurangan dari implementasi bola di tutorial ini adalah lajunya yang tidak stabil, dan
bisa berbeda setiap kali bola mendapat gaya yang besarnya berbeda-beda saat bola
mulai diluncurkan di set permainan baru . Modifikasilah kode tutorial ini supaya besar
gaya yang diberikan kepada bola besarnya sama(kecepatan bola sama, kemanapun
arahnya).
Petunjuk: lakukan implementasi di metode BallControl.PushBall(), dan ingat bahwa
yang dibuat sama adalah besar gayanya, bukan gayanya itu sendiri.
2. Bonus apabila dikerjakan: Tambahkan mekanika baru
o Membuat power-up yang akan memperpanjang raket secara sementara
o Bola api acak yang jika terkena raket membuat pemain otomatis kalah pada set ini