Anda di halaman 1dari 32

Part 3 – Pong

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.

Untuk mengembangkan Pong, kita perlu memahami bagaimana mengimplementasikan


simulasi fisika 2D, aturan main, serta sistem input/outputnya di Unity. Di dalam tutorial ini,
prototipe game akan dibuat dulu sebelum variabel-variabel fisika dibahas lebih jauh. Berikut
ini kisi-kisi materi di tutorial ini.

1. Pemperkenalan komponen-komponen fisika 2D yang dapat ditemui di Unity, dan


akan digunakan di implementasi game Pong.
2. Pembuatan proyek 2D di Unity, sebagai titik awal pengembangan Pong.
3. Penjelasan komponen-komponen yang diperlukan dalam membuat game Pong, serta
implementasinya.
4. Pembahasan lebih jauh tentang beberapa variabel fisika di game ini melalui
implementasi debug information.
5. Pembuatan file aplikasi mandiri (standalone) dari prototipe game ini.

Peserta diasumsikan sudah mengenali konsep-konsep dasar mekanika, penggunaan Unity


(termasuk instalasinya), dan bahasa pemrograman C#. Tutorial ini menggunakan Unity
2018.3.3f1.

Sekilas Komponen-Komponen Fisika 2D di


Unity
Unity memiliki physics engine 2D (dan juga 3D) yang dapat dimanfaatkan untuk
mengimplementasikan gerakan untuk benda tegar (rigid body) ataupun fluida. Untuk benda
tegar sendiri, gerakan dapat disimulasikan secara kinematis (tidak dipengaruhi gaya)
maupun dinamis (dipengaruhi gaya). Pergerakan sebuah objek juga bisa "dibebaskan" dari
simulasi fisika dan dikendalikan input dari pemain, tanpa melepas pengaruh objek tersebut
dari objek lain.

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.

1. Rigidbody 2D merupakan representasi sebuah benda tegar di Unity. Kita bisa


menentukan tipe objek tersebut: kinematic jika tidak dipengaruhi gaya (berguna jika,
misalnya, objek ini akan dikendalikan pemain), dynamic jika dipengaruhi gaya,
atau static jika objek ini tidak bergerak sama sekali, namun tetap mempengaruhi
perilaku fisika benda lain. Beberapa konfigurasi lain dapat diatur sesuai tipe objek
tersebut, seperti massa, simulated (mengaktifkan/menonaktifkan objek dari simulasi
fisika), besarnya beberapa gaya yang mempengaruhi, serta material objek tersebut,
yang dapat diatur melalui Physics Material 2D (poin berikut). Tampilan komponen
Rigidbody 2D di panel Inspector untuk masing-masing tipe objek dapat dilihat di
bawah.
2. Physics Material 2D menentukan nilai friction (gaya gesek) dan bounciness (gaya pantul)
sebuah objek. Friction bernilai 0 berarti objek licin seperti es, sementara nilai 1 berati
objek kasar seperti karet. Bounciness bernilai 0 berarti objek tidak akan memantul
(seluruh energi bola teredam), sementara nilai 1 berarti objek akan memantul
sempurna tanpa kehilangan tenaga. Physics Material 2D dapat dipasang di
komponen Rigidbody 2D ataupun Collider 2D.

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).

Dengan bantuan skrip, reaksi objek tersebut ketika bertumbukan ataupun


bertumpang tindih dengan berbagai objek yang berbeda dapat ditentukan. Reaksi ini
dapat ditentukan dengan mengimplementasikan
metode OnCollisionEnter2D, OnCollisionExit2D,
dan OnCollisionStay2D untuk collider biasa, ataupun OnTriggerEnter2D, OnTriggerExit2D,
dan OnTriggerStay2D untuk sebuah trigger. Hanya metode yang akan digunakan yang
perlu diimplementasikan. Gambar di bawah menunjukkan konfigurasi salah satu
jenis collider 2D, yaitu Circle Collider 2D. Supaya fungsi ini dapat digunakan, salah satu
dari kedua objek terkait harus memiliki Rigidbody 2D.
Membuat Proyek 2D di Unity
Pertama-tama, buka Unity, dan akan muncul tampilan sebagai berikut.

Klik New, dan akan muncul tampilan berikut.

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:

Will Oldham. Make a Pong Game with Unity


2D. https://www.awesomeincu.com/tutorials/unity-pong/

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:

1. Merespon input dari pemain


2. Menentukan arah dan kecepatan raket
3. Membandingkan posisi raket dengan batas game scene-nya

Pertama-tama, kita akan mendeklarasikan variabel-variabel berikut, beserta penjelasan dan


nilai default-nya di dalam kelas PlayerControl. Perlu diingat bahwa variabel-
variabel public akan muncul di Inspector, sementara variabel-variabel private tidak muncul.
Penjelasan masing-masing variabel ditulis sebagai komen di atas variabel tersebut.

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.

// Tombol untuk menggerakkan ke atas


public KeyCode upButton = KeyCode.W;

// Tombol untuk menggerakkan ke bawah


public KeyCode downButton = KeyCode.S;

// Kecepatan gerak
public float speed = 10.0f;

// Batas atas dan bawah game scene (Batas bawah menggunakan minus (-))
public float yBoundary = 9.0f;

// Rigidbody 2D raket ini


private Rigidbody2D rigidBody2D;

// Skor pemain

private int score;

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;

// Jika pemain menekan tombol ke atas, beri kecepatan positif ke komponen


y (ke atas).
if (Input.GetKey(upButton))
{
velocity.y = speed;
}

// Jika pemain menekan tombol ke bawah, beri kecepatan negatif ke komponen


y (ke bawah).
else if (Input.GetKey(downButton))
{
velocity.y = -speed;
}

// Jika pemain tidak menekan tombol apa-apa, kecepatannya nol.


else
{
velocity.y = 0.0f;
}

// Masukkan kembali kecepatannya ke rigidBody2D.


rigidBody2D.velocity = 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.

// Dapatkan posisi raket sekarang.


Vector3 position = transform.position;

// Jika posisi raket melewati batas atas (yBoundary), kembalikan ke batas


atas tersebut.
if (position.y > yBoundary)
{
position.y = yBoundary;
}

// Jika posisi raket melewati batas bawah (-yBoundary), kembalikan ke bata


s atas tersebut.
else if (position.y < -yBoundary)
{
position.y = -yBoundary;
}
// Masukkan kembali posisinya ke transform.
transform.position = position;

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.

// Menaikkan skor sebanyak 1 poin


public void IncrementScore()
{
score++;
}

// Mengembalikan skor menjadi 0


public void ResetScore()
{
score = 0;
}

// Mendapatkan nilai skor


public int Score
{
get { return score; }
}

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.

Konfigurasi sisanya untuk rigidbody adalah sebagai berikut.

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;

// Besarnya gaya awal yang diberikan untuk mendorong bola


public float xInitialForce;
public float yInitialForce;

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;

// Reset kecepatan menjadi (0,0)


rigidBody2D.velocity = 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

float yRandomInitialForce = Random.Range(-yInitialForce, yInitialForce);

// Tentukan nilai acak antara 0 (inklusif) dan 2 (eksklusif)

float randomDirection = Random.Range(0, 2);

// Jika nilainya di bawah 1, bola bergerak ke kiri.

// Jika tidak, bola bergerak ke kanan.

if (randomDirection < 1.0f)

// Gunakan gaya untuk menggerakkan bola ini.


rigidBody2D.AddForce(new Vector2(-xInitialForce, yRandomInitialForce))
;

else

rigidBody2D.AddForce(new Vector2(xInitialForce, yRandomInitialForce));

}
}

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();

// Setelah 2 detik, berikan gaya ke bola


Invoke("PushBall", 2);
}

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.

Sekarang, kita akan membuat dinding atas dan bawah dulu.

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.

Implementasi Game Pong - Game Manager


Konfigurasi dan tampilan GUI game Pong akan kita implementasikan dengan membuat
objek Game Manager. Komponen penting dari objek ini adalah skrip GameManager, yang
memuat aturan game, dan menampilkan skor para pemain.

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.

Skrip GameManager membuat variabel-variabel berikut, yang digunakan untuk menentukan


objek-objek yang mewakili pemain 1, pemain 2, dan bola. Variabel public bertipe skrip
digunakan untuk mengakses skrip-skrip ini dari GameManager, sedangkan
variabel private bertipe Rigidbody2D dan (turunan dari) Collider2D akan digunakan untuk
mengakses atribut-atribut fisika saat implementasi debug window. Terakhir,
variabel maxScore menentukan skor maksimal sebuah game.

// 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;

Pertama-tama, kita inisialisasi ketiga variabel Rigidbody2D.

// Inisialisasi rigidbody dan collider


private void Start()
{
player1Rigidbody = player1.GetComponent<Rigidbody2D>();
player2Rigidbody = player2.GetComponent<Rigidbody2D>();
ballRigidbody = ball.GetComponent<Rigidbody2D>();
ballCollider = ball.GetComponent<CircleCollider2D>();
}

Untuk menampilkan GUI dan menangani respon GUI, kita menggunakan metode OnGUI().
Metode ini akan melakukan beberapa hal, yaitu:

• Menampilkan skor pemain 1 di kiri atas dan pemain 2 di kanan atas


• Menampilkan tombol restart untuk memulai game dari awal (mengembalikan bola ke
tengah dan membuat skor kedua pemain menjadi 0)
• Menentukan pemenang yang skornya mencapai skor maksimal, dan menampilkan teks
kemenangan di kiri, jika pemain 1 menang, atau di kanan, jika pemain 2 menang.

// Untuk menampilkan GUI


void OnGUI()
{
// Tampilkan skor pemain 1 di kiri atas dan pemain 2 di kanan atas
GUI.Label(new Rect(Screen.width / 2 - 150 - 12, 20, 100, 100), "" + player
1.Score);
GUI.Label(new Rect(Screen.width / 2 + 150 + 12, 20, 100, 100), "" + player
2.Score);

// Tombol restart untuk memulai game dari awal


if (GUI.Button(new Rect(Screen.width / 2 - 60, 35, 120, 53), "RESTART"))
{
// Ketika tombol restart ditekan, reset skor kedua pemain...
player1.ResetScore();
player2.ResetScore();

// ...dan restart game.


ball.SendMessage("RestartGame", 0.5f, SendMessageOptions.RequireReceiv
er);
}

// Jika pemain 1 menang (mencapai skor maksimal), ...


if (player1.Score == maxScore)
{
// ...tampilkan teks "PLAYER ONE WINS" di bagian kiri layar...
GUI.Label(new Rect(Screen.width / 2 - 150, Screen.height / 2 - 10, 200
0, 1000), "PLAYER ONE WINS");

// ...dan kembalikan bola ke tengah.


ball.SendMessage("ResetBall", null, SendMessageOptions.RequireReceiver
);
}
// Sebaliknya, jika pemain 2 menang (mencapai skor maksimal), ...
else if (player2.Score == maxScore)
{
// ...tampilkan teks "PLAYER TWO WINS" di bagian kanan layar...
GUI.Label(new Rect(Screen.width / 2 + 30, Screen.height / 2 - 10, 2000
, 1000), "PLAYER TWO WINS");

// ...dan kembalikan bola ke tengah.


ball.SendMessage("ResetBall", null, SendMessageOptions.RequireReceiver
);
}
}

Kembali ke window Unity, kita perlu mengkonfigurasi skrip GameManager. Tarik


objek Player1 ke properti Player 1, objek Player2 ke properti Player 2, dan objek Ball ke
properti Ball. Atur skor maksimal di properti Max Score, misalnya untutk tutorial ini kita akan
menggunakan nilai 5. Gambar konfigurasi skrip GameManager dapat dilihat di bawah.

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.

Di kelas SideWall, deklarasikan variabel baru berikut.


// Skrip GameManager untuk mengakses skor maksimal
[SerializeField]

private GameManager gameManager;

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.

Menampilkan Debug Information -


Modifikasi Skrip
Bagian ini menjelaskan cara menampilkan sejumlah debug information yang memuat nilai-
nilai variabel fisika di game. Disebut debug information karena berguna dalam
proses debugging, yaitu mendeteksi error dalam game dan menyelesaikannya. Ada dua buah
antarmuka yang akan kita buat, yaitu debug window, untuk menampilkan nilai-nilai variabel
fisika, dan prediksi lintasan (trajectory) bola. Akan ada beberapa skrip yang dimodifikasi di
tutorial ini.

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.

Di skrip PlayerControl deklarasikan variabel lastContactPoint sebagai berikut.

// Titik tumbukan terakhir dengan bola, untuk menampilkan variabel-variabel fi


sika terkait tumbukan tersebut
private ContactPoint2D lastContactPoint;

Di dalam kelasnya, definisikan properti publik untuk mengakses informasi tersebut.

// Untuk mengakses informasi titik kontak dari kelas lain


public ContactPoint2D LastContactPoint
{
get { return lastContactPoint; }
}

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.

// Ketika terjadi tumbukan dengan bola, rekam titik kontaknya.


void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.name.Equals("Ball"))
{
lastContactPoint = collision.GetContact(0);
}
}

Kita juga akan memodifikasi skrip BallControl untuk merekam titik tumbukan terakhir.
Informasi ini digunakan untuk menghitung garis pantulan gerakan bola.

Deklarasikan variabel trajectoryOrigin sebagai berikut.

// Titik asal lintasan bola saat ini


private Vector2 trajectoryOrigin;

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.

// Untuk mengakses informasi titik asal lintasan


public Vector2 TrajectoryOrigin
{
get { return trajectoryOrigin; }

Menampilkan Debug Information -


Membuat Debug Window
Di tutorial ini, kita akan membuat sebuah debug window untuk menampilkan nilai-nilai
variabel fisika yang berlaku di game ini. Perilaku antarmuka debug window adalah sebagai
berikut.

• Kita akan menggambar tombol “Toggle Debug Info”


• Jika pemain mengeklik tombol tersebut, akan muncul sebuah debug window yang
menampilkan nilai-nilai variabel fisika
• Jika tombol ini diklik lagi, jendela tersebut akan disembunyikan.

Untuk membuat tombol “Toggle Debug Window”, kita tambahkan


variabel isDebugWindowShown di kelas GameManager.
// Apakah debug window ditampilkan?
private bool isDebugWindowShown = false;

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.

// Jika isDebugWindowShown == true, tampilkan text area untuk debug window


.
if (isDebugWindowShown)
{
}

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.

// Simpan nilai warna lama GUI


Color oldColor = GUI.backgroundColor;

Kemudian, kita buat warna background debug window menjadi merah.

// Beri warna baru


GUI.backgroundColor = Color.red;

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).

// Simpan variabel-variabel fisika yang akan ditampilkan.


float ballMass = ballRigidbody.mass;
Vector2 ballVelocity = ballRigidbody.velocity;
float ballSpeed = ballRigidbody.velocity.magnitude;
Vector2 ballMomentum = ballMass * ballVelocity;
float ballFriction = ballCollider.friction;

float impulsePlayer1X = player1.LastContactPoint.normalImpulse;


float impulsePlayer1Y = player1.LastContactPoint.tangentImpulse;
float impulsePlayer2X = player2.LastContactPoint.normalImpulse;
float impulsePlayer2Y = player2.LastContactPoint.tangentImpulse;

// Tentukan debug text-nya


string debugText =
"Ball mass = " + ballMass+ "\n" +
"Ball velocity = " + ballVelocity + "\n" +
"Ball speed = " + ballSpeed + "\n" +
"Ball momentum = " + ballMomentum + "\n" +
"Ball friction = " + ballFriction + "\n" +
"Last impulse from player 1 = (" + impulsePlayer1X + ", " + impuls
ePlayer1Y + ")\n" +
"Last impulse from player 2 = (" + impulsePlayer2X + ", " + impuls
ePlayer2Y + ")\n";

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.

// Tampilkan debug window


GUIStyle guiStyle = new GUIStyle(GUI.skin.textArea);
guiStyle.alignment = TextAnchor.UpperCenter;
GUI.TextArea(new Rect(Screen.width/2 - 200, Screen.height - 200, 400,
110), debugText, guiStyle);

Lalu, kembalikan warna GUI ke warna lama.

// Kembalikan warna lama GUI


GUI.backgroundColor = oldColor;

Perlu diingat bahwa kode sampai dengan baris di atas harus ditulis di dalam percabangan.

Terakhir, untuk membuat tombol “Toggle Debug Info” yang akan


menampilkan/menyembunyikan debug window di atas, tulis kode berikut.

// Toggle nilai debug window ketika pemain mengeklik tombol ini.


if (GUI.Button(new Rect(Screen.width/2 - 60, Screen.height - 73, 120, 53),
"TOGGLE\nDEBUG INFO"))
{
isDebugWindowShown = !isDebugWindowShown;

Menampilkan Lintasan Bola


Prediksi lintasan (trajectory) bola akan ditampilkan sebagai garis putus-putus dari bola
sesuai arah gerak bola. Jika akan terjadi tumbukan, prediksi lintasan pantulannya juga akan
dihitung dan ditampilkan.

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

Download asset berupa paket Unity berikut.

https://github.com/KunalT6569/DottedLineInUnity2D/raw/master/Exported%20Asset/Dotte
dLineAsset.unitypackage

Double click dan instal paket tersebut. Akan muncul tampilan berikut.

Klik import, dan aset-aset tersebut akan diletakkan di folder Assets.


Untuk menampilkan prediksi lintasan bola, ada dua objek yang perlu dibuat. Objek pertama
adalah Trajectory, sebagai representasi lintasan tersebut. Buat objek baru (klik kanan di
panel Hierarchy, lalu klik Create Empty), dan beri nama Trajectory. Tambahkan komponen
skrip DottedLine dari plugin yang baru saja kita instal (di panel Inspector, klik Add Component,
lalu ketik “Dotted Line” dan pilih skrip tersebut). Untuk material Dot, tarik file Dot Sprite
(lokasinya sesuai gambar di atas) ke atribut Dot. Beri nilai Size dan Delta masing-masing
0.055 dan 0.1. Kedua variabel ini menandakan ukuran titik dan jarak antar titik di garis
lintasan.

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.

// Skrip, collider, dan rigidbody bola


public BallControl ball;
CircleCollider2D ballCollider;
Rigidbody2D ballRigidbody;

// Bola "bayangan" yang akan ditampilkan di titik tumbukan


public GameObject ballAtCollision;

Variabel ball dan ballAtCollision nanti akan kita inisialisasi dari panel Inspector di Unity.
Sementara, metode Start() akan memuat collider dan rigidbody bola.

// Inisialisasi rigidbody dan collider


void Start()
{
ballRigidbody = ball.GetComponent<Rigidbody2D>();
ballCollider = ball.GetComponent<CircleCollider2D>();
}

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.

// Titik tumbukan yang digeser, untuk menggambar ballAtCollision


Vector2 offsetHitPoint = new Vector2();

Sekarang, lakukan proses circle casting, dengan memanggil metode Physics2D.CircleCastAll().


Proses ini dilakukan dari lokasi bola saat ini, dengan mempertimbangkan radius bola dan
arah gerak bola saat ini. Dari proses ini, kita akan mendapat daftar lokasi tumbukan
(circleCastHit2DArray).

// Tentukan titik tumbukan dengan deteksi pergerakan lingkaran


RaycastHit2D[] circleCastHit2DArray =

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 setiap titik tumbukan, ...


foreach (RaycastHit2D circleCastHit2D in circleCastHit2DArray)
{
// Jika terjadi tumbukan, dan tumbukan tersebut tidak dengan bola
// (karena garis lintasan digambar dari titik tengah bola)...
if (circleCastHit2D.collider != null &&
circleCastHit2D.collider.GetComponent<BallControl>() == null)
{
...
}
}

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.

// Tentukan titik tumbukan


Vector2 hitPoint = circleCastHit2D.point;

// Tentukan normal di titik tumbukan


Vector2 hitNormal = circleCastHit2D.normal;

Hitung offsetHitPoint dengan menggeser titik tumbukan sepanjang vektor hitNormal sesuai
radius bola.

// Tentukan offsetHitPoint, yaitu titik tengah bola pada saat bert


umbukan
offsetHitPoint = hitPoint + hitNormal * ballCollider.radius;

Kemudian, gambar garis dari posisi bola sekarang ke offsetHitPoint.

// 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.

Kode untuk melakukan proses di atas adalah sebagai berikut.

// Kalau bukan sidewall, gambar pantulannya


if (circleCastHit2D.collider.GetComponent<SideWall>() == null)
{
// Hitung vektor datang
Vector2 inVector = (offsetHitPoint - ball.TrajectoryOrigin).no
rmalized;

// Hitung vektor keluar


Vector2 outVector = Vector2.Reflect(inVector, hitNormal);

// Hitung dot product dari outVector dan hitNormal. Digunakan


supaya garis lintasan ketika
// terjadi tumbukan tidak digambar.
float outDot = Vector2.Dot(outVector, hitNormal);
if (outDot > -1.0f && outDot < 1.0)
{
// Gambar lintasan pantulannya
DottedLine.DottedLine.Instance.DrawDottedLine(
offsetHitPoint,
offsetHitPoint + outVector * 10.0f);

// Untuk menggambar bola "bayangan" di prediksi titik tumb


ukan
drawBallAtCollision = true;
}
}

// Hanya gambar lintasan untuk satu titik tumbukan, jadi keluar da


ri loop
break;

Bagian terakhir skrip Trajectory adalah untuk menampilkan/menyembunyikan bola


bayangan. Jika bola akan memantul dari objek lain, update posisi ballAtCollision
menjadi offsetHitPoint, dan tampilkan bola bayangannya. Jika tidak, sembunyikan bola
bayangan.

// Jika true, ...


if (drawBallAtCollision)
{
// Gambar bola "bayangan" di prediksi titik tumbukan
ballAtCollision.transform.position = offsetHitPoint;
ballAtCollision.SetActive(true);
}else
{
// Sembunyikan bola "bayangan"
ballAtCollision.SetActive(false);
}

Modifikasi skrip terakhir dilakukan di Game Manager. Deklarasikan variabel untuk


menyimpan objek Trajectory sebagai berikut.
// Objek untuk menggambar prediksi lintasan bola
public Trajectory trajectory;

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”.

Tampilan akhir kedua komponen skrip ini adalah sebagai berikut.

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.

Lakukan konfigurasi berikut.

1. Untuk platform, pilih PC, Mac & Linux Standalone.


2. Untuk target platform, pilih Windows.
3. Untuk Architecture, pilih x86 untuk 32 bit, atau x86_64 untuk 64 bit. Tutorial ini
menggunakan x86_64.
4. Untuk yang lainnya, gunakan konfigurasi default.

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

Anda mungkin juga menyukai