0% menganggap dokumen ini bermanfaat (0 suara)
6 tayangan130 halaman

Modul

Dokumen ini menjelaskan pengenalan dan penggunaan Unity sebagai game engine untuk pengembangan game 2D. Terdapat langkah-langkah untuk mengatur proyek, mengimpor aset, membuat objek game, serta menambahkan fisika dan skrip untuk interaksi. Selain itu, dijelaskan juga cara membuat prefab dan fitur-fitur dasar seperti gerakan pemain dan penembakan dalam game.

Diunggah oleh

rasyidhpanyar
Hak Cipta
© All Rights Reserved
Kami menangani hak cipta konten dengan serius. Jika Anda merasa konten ini milik Anda, ajukan klaim di sini.
Format Tersedia
Unduh sebagai PDF, TXT atau baca online di Scribd
0% menganggap dokumen ini bermanfaat (0 suara)
6 tayangan130 halaman

Modul

Dokumen ini menjelaskan pengenalan dan penggunaan Unity sebagai game engine untuk pengembangan game 2D. Terdapat langkah-langkah untuk mengatur proyek, mengimpor aset, membuat objek game, serta menambahkan fisika dan skrip untuk interaksi. Selain itu, dijelaskan juga cara membuat prefab dan fitur-fitur dasar seperti gerakan pemain dan penembakan dalam game.

Diunggah oleh

rasyidhpanyar
Hak Cipta
© All Rights Reserved
Kami menangani hak cipta konten dengan serius. Jika Anda merasa konten ini milik Anda, ajukan klaim di sini.
Format Tersedia
Unduh sebagai PDF, TXT atau baca online di Scribd

A.

Pendahuluan

Unity adalah cross-platform game engine dimana Unity adalah berfungsi sebagai
aplikasi "editor" untuk pengembangan game (Semacam halnya Photoshop adalah
aplikasi editor untuk manipulasi gambar).

Dalam Unity, dikenal namanya "Unity Project". Unity project secara umunya dibedakan
menjadi 2 yaitu Project 3D dan 2D. Dalam modul ini kita akan lebih lanjut membahas
membuat game dalam Unity Project 2D.

Contoh Tampilan Project Unity 3D dan 2D:

Sumber: ([Link]
Sumber: ([Link]

B. Download Assets
Assets Sprite untuk modul ini dapat di download di

[Link]
drive_link

C. Setting Up Project
1.​ Buka Unity Hub yang telah di download.
2.​ Pilih New pada pojok kanan atas untuk membuat Project baru.
3.​ Pilih Template 2D untuk membuat game 2D dan isi Project Name untuk Nama
Project Game yang ingin dibuat dan Location untuk lokasi project yang akan
ditempatkan.
4.​ Tekan Create dan menunggu loading dari Unity untuk membuat Project Game
2D baru.
D. Pengenalan Layout Unity

Scene View

●​ Sceneview adalah tempat dimana kita berinteraksi dengan world atau dunia
virtual yang telah kita buat. Di dalam Sceneview kita dapat pilih, memanipulasi,
menggerakkan (dan lain sebagainya) Camera, Lighting, dan GameObject lain
yang berada di dalam Scene tersebut.
●​ Didalam satu project game Unity bisa terdapat beberapa Scene. Biasanya jika
dalam project game tersebut terdapat sistem Tahapan Level maka 1 level
tersebut direpesentasikan dengan 1 Scene. Jika kita ingin membuat Level baru
dengan environment dan object yang mungkin berbeda, maka kita akan
membuat scene baru. Scene baru juga bisa dibuat untuk membuat main menu,
Score Detail Scene dan lain sebagainya.

Game View
●​ GameView adalah bentuk rendered dari scene yang telah dibangun dari perspektif
camera. Secara singkatnya GameView berfungsi untuk preview bagaimana
nantinya game kita jika dimainkan. Dengan GameView, kita bisa test memainkan
game yang kita buat sebelum diBuild menjadi game utuh. Untuk
menjalankan/test Game melalui GameView kita bisa menggunakan tombol play
berikut:

Project Window

●​ Project Window adalah window yang menampilkan semua files yang


berhubungan dengan project kita. Project Window juga berfungsi untuk navigate
dan mengatur/manage asset dan project files dalam suatu project. Semacam File
Explorer dalam Windows, kita dapat membuat folder dalam Project Window agar
para files bisa tersusun secara rapi (Semua Files yang berada di Project juga
bisa diakses/dilihat dari File Explorer Windows).

Hierarchy

●​ Hierarchy atau Hierarchy Window mengandung dan menampilkan semua


GameObject yang berhubungan dalam Scene yang sedang dikerjakan.
GameObject seperti camera, lighting ,model 3D, dsb yang digunakan dalam
Scene pasti akan tertampil dalam Hierarchy.
●​ Dalam Hierarchy dikenal namanya Parenting.

Inspector
●​ Inspector befungsi untuk mengatur properties dan pengaturan untuk hampir
semua yang ada di Unity Editor. Seperti GameObject, Unity Component, Assets,
Materials, dan lain sebagainya.
●​ GameObject adalah base class dari semua entitas yang berada dalam suatu
Scene. Secara umumnya entitas yang berada dalam Scene seperti Camera,
Lighting, Player, dan lain-lain base nya adalah GameObject. Dalam contoh
Lighting/Light Object merupakan GameObject dengan menambahkan Light
Component ke GameObject.
●​ Component adalah behaviour dari GameObject. Component yang terdapat di
GameObject bisa dilihat di Inspector Window. Transform yang mengatur posisi,
scale, dan rotasi suatu object merupakan salah satu Component Object.

Toolbar

●​ ​
Account Drop-down untuk mengakses Unity Accounts milik kalian.

●​ ​
Tombol Unity Cloud untuk membuka Unity Service window.
●​ ​
Undo History untuk melihat, mengulang, dan membatalkan aksi yang telah kalian
lakukan pada Editor.

●​ ​
Tombol Search akan membuka Search window yang digunakan pencarian yang
lebih advance pada Editor.

●​ ​
Layer Drop-down berguna untuk mengontrol penempatan GammeObejct pada
SceneViem.

●​ ​
Layout Drop-down berguna menyimpan dan mengedit Layout dari Editor kita
sesuai dari prefensi masing-masing.

E. Import Assets

Extract file Assets yang telah didownload sebelumnya pada


lokasi Project yang barusan dibuat.

Sehingga struktur project yang baru kurang lebih seperti


berikut ini.
F. Pengenalan GameObject pada Unity

Membuat Player
●​ Untuk membuat object player, seperti yang dijelaskan di atas pasti berasal dari
GameObject dasar. Nantinya GameObject yang dibuat menjadi Player akan
diberi beberapa component yang dibutuhkan sehingga object Player dapat
dimainkan. Component yang umum untuk membangun suatu player biasanya
adalah RigidBody,Collider,Script Movement, dan lain sebagainya (tergantung
bagaimana player mau dibuat). Component yang nanti kita akan gunakan akan
dijelaskan lebih lanjut.
●​ Buat GameObject kosong (Empty) dengan cara GameObject > Create Empty.

●​ Ganti nama GameObject ini menjadi Player.


●​ Pada Hierarchy, klik kanan pada Player dan pilih Create Empty dan ubah
namanya menjadi Graphic.

●​ Pada child Player Graphic ini, tambahkan component Sprite Renderer.


●​ Sprite Renderer adalah suatu component di Unity yang berfungsi untuk render
Sprite yang kita punya dan mengatur bagaimana Sprite tersebut tertampilkan di
Scene.
●​ Navigasi pada Assets/Sprites/Player dan pilih salah satu Sprite, dalam modul
ini kami menggunakan player_idle_0.png sebagai contoh.

●​ Klik pada sprite tersebut lalu pada Inspector ubah Pixels Per Unit menjadi 32 lalu
Apply.

●​ Drag Sprite tersebut menuju field Sprite pada component SpriteRenderer yang
ada pada GameObject Graphic.
●​ Jika berhasil, kita dapat melihat Player pada Scene View. Pilih Player lalu coba
pindahkan posisinya dengan menggunakan axis transform.
●​ Transform disini dapat diatur melalui Inspector Window(melalui Component
Transport) atau bisa langsung dipindahkan memakai Transport Axis (bisa
langsung menggunakan mouse untuk drag dan transform object yang diselect).

Mencoba Sprite Slicing untuk Forest Tile


●​ Pada Project Assets pilih Sprite forest_tile.png.

●​ Pada Inspector ubah Sprite Mode menjadi Multiple, Pixels Per Unit menjadi 32,
Mesh Type menjadi Full Rect lalu Apply.

●​ Pada Inspector lagi, klik button Sprite Editor


●​ Kemudian pada Sprite Editor pilih Slice lalu pilih Grid by Cell Size dan ganti Pixel
Size menjadi 16x16. Kemudian klik Apply.

●​ Sprite Slicing adalah membagi kumpulan Sprite (biasanya Sprite yang


objeknya sama tapi dengan detail yang berbeda akan dikumpulkan agar
tersusun secara rapi/Sprite Sheet) menjadi sprite individual. Namun sprite slicing
tidak hanya digunakan untuk Sprite sheet saja, tapi juga bisa pada sprite
individual yang sudah ada, kita bagi menjadi beberapa sprite individual yang
baru.
●​ Hasil slicing sprite dapat dilihat pada Project Window, maka setiap potongan
kotak dapat digunakan secara terpisah.
●​ Buat Game Object Empty dan ganti namanya menjadi Environment. Game
Object ini untuk menampung lingkungan / pijakan / dekorasi pada level nanti

●​ Coba cari kotak dengan nama forest_tile_57 dan drag and drop ke Game Object
Environment pada Hierarchy dan ubah namanya menjadi nama lain agar mudah
dikenali.

●​ Pada SpriteRenderer ubah Draw Mode menjadi Tiled.


●​ Sprite Tiling seperti kata dasarnya Tile. Seperti lantai yang tiap tile (ubin) nya
itu sama, sprite yang kita punya akan diduplikasi sehingga tidak perlu
memasukkan sprite satu-satu. Select object yang ingin kita tiling lalu kita tinggal
mengatur width dan/atau Height yang kita preferensikan.
●​ Modifikasi ukuran dan posisi Sprite dengan bantuan tools transform yang ada.

●​ Dengan cara yang sama coba cari forest_tile_44 dan coba hias level sedemikian
rupa agar indah dan cantik.
Membuat Level
●​ Pada seluruh sprite pada Project Window, ubah Pixels Per Unit nya menjadi 32.
Bisa dengan cara select menggunakan shift click pada sprite yang diinginkan.

●​ Pada inspector ubah Pixels Per Unit nya menjadi 32, lalu Apply. Lakukan pada
semua sprite yang ada (Bullet, Environment, Mushroom, Player dan UI).
●​ Dengan cara drag and drop dari Project Window ke Graphic dan jadikan sprite
tersebut sebagai child dari Environment, hias Level mu sesuai keinginan!

●​ Terkadang urutan tampilan sprite tidak benar, bisa diatur pada Order in Layer
pada setiap Sprite Renderer.
●​ Sprite Layer Order adalah suatu fitur yang digunakan untuk mengatur urutan
render dari suatu Sprite Renderer. Layer Order dengan nilai terbesar akan
berada pada posisi paling depan, sedangkan nilai terkecil akan berada pada
posisi paling bawah.

Menambahkan Physics
●​ Physics 2D adalah bagaimana mekanis fisika di game kita bekerja (dalam kasus
ini fisika 2 dimensi nya bagaimana). Physiscs di Unity bisa meliputi
Gravity,Velocity,Speed Rotation dan banyak lagi lainnya yang bisa kita atur
melalui Global Setting untuk Physics 2D.
Sumber: ([Link])
●​ Pada player menambahkan Rigidbody2D

●​ Centang Freeze Rotation Z pada constraint Rigidbody2D

●​ Tambahkan component Capsule Collider2D pada Player


●​ Capsule Collider 2D adalah Component yang berfungsi untuk menetapkan
batas bagaimana sebuah objek 2D dapat "bertabrakan"/Berinteraksi dengan
objek lain.
●​ Ubah ukuran Collider sesuai dengan sprite Player

●​ Pada Environment tambahkan Box Collider2D pada tanah yang dapat dipijak
Player dan sesuaikan ukuran collidernya
Membuat Prefab untuk Player
●​ Dalam suatu Project di Unity kita bisa menggunakan suatu object dalam
beberapa Scene (Karena biasanya setiap Scene memiliki object yang
berbeda-beda antara 1 Scene dengan Scene yang lain). Jadi jika kita ingin
menggunakan object tidak hanya di dalam satu Scene saja, kita dapat membuat
object tersebut menjadi Prefab.
●​ Pada Project Window, click kanan lalu Create > Folder untuk membuat folder
baru pada Assets lalu beri nama Prefabs.

●​ Buka Folder Prefabs tersebut, lalu pada Hierachy pilih Player dan drag pad
Project Assets untuk membuat prefab Player.
Test Play pada Game
●​ Edit mode adalah disaat kita dapat mengedit semua yang ada dalam Scene dan
perubnahan tersebut bersifat permanent/tersimpan sehingga apabila beralih ke
mode lain (Play Mode) perubahan yang kita lakukan tersebut tersimpan.
●​ Game mode adalah saat kita menjalankan play dan kita dapat berinteraksi dengan
game view. Saat berada di Game Mode kita tetap dapat melakukan perubahan di
scene view. Namun, perubahan yang kita lalukan hanya bersifat temporary
sehingga saat kuita kembalikan ke edit mode, perubahan yag kita lalukan akan
hilang. Game Mode dapat diaktifkan dengan menekan tombol play lalu tekan
tombol stop untuk kembali ke Edit mode.
●​ Lakukan test Play dengan menekan tombol Play

●​ Tampilan Game Mode, Player akan jatuh karena pengaruh Rigidbody2D

G. Membuat Entitas pada Game

Membuat Code Player


●​ Buat Folder baru dengan nama Scripts dan buat Script baru dengan Create > C#
Script dan beri nama PlayerController

●​ Drag Script PlayerController dan drag pada gameobject Player pada Hierarchy.
Atau bisa juga dengan klik Player dulu, lalu drag script PlayerController ke
Inspector.

●​ Jika kita menggunakan Engine Unity maka setiap script yang ingin kita buat dan
terapkan dalam engine harus menggunakan bahasa pemrograman C#. Script ini
dapat kita terapkan ke object yang kita inginkan sebagai salah satu component
GameObject.
●​ Klik dua kali script PlayerController dan masukkan Code Player berikut untuk
Code Input dan Jalan

using [Link];
using [Link];
using UnityEngine;

public class PlayerController : MonoBehaviour


{
public static PlayerController Instance { get; private set; }

[Header("Properties")]
[SerializeField] private SpriteRenderer graphic;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;
private Rigidbody2D rb2;

void Awake()
{
Instance = this;
}

void Start()
{
rb2 = GetComponent<Rigidbody2D>();
}

void Update()
{
MovementController();
}

void MovementController()
{
float x = [Link]("Horizontal");

Vector2 direction = [Link];


direction.x = x * moveSpeed;

[Link] = direction;

//sprite dibalik ketika arahnya ke kiri


if (direction.x < 0)
{
[Link] = true;
} else if (direction.x > 0)
{
[Link] = false;
}
}
}

●​ Blok/Bagian Awake() bekerja saat scene mulai/start.


●​ Blok/Bagian Start() bekerja sebelum first frame update
●​ Blok/Bagian Update() akan bekerja sekali tiap 1 frame (akan bekerja berkali-kali
secara terus menerus karena dalam game terdapat banyak frame per detik nya).
●​ Vector3: Representasi gerakan (vector) 3 Dimensi dalam script.
●​ Vector2: Representasi gerakan (vector) 2 Dimensi dalam script.
●​ private: Private adalah salah satu acces modifiers dalam pemrograman
berorientasi objek. Private sendiri berarti hanya dalam satu class yang sama
yang dapat mengakses method atau variabel tersebut.
●​ public: Public juga merupakan salah satu acces modifiers. kebalikannya dari
private, public berarti method atau variabelnya bisa dilihat oleh class yang lain.
●​ atribut [Serializable]: Atribut ini menandakan jika field yang diberi atribut ini
dapat diserialized (field dapat diformat dan datanya disimpan oleh Unity).
●​ atribut [SerializeField]: membuat field yang access modifiernya private dapat
diserializedkan.
●​ GetComponent: Berfungsi mendapatkan dan mengakses data dari Component
GameObject. Sehingga kita bisa mendapatkan hingga merubah value dari
Component GameObject melalui Script.
●​ Assign Child Player (Graphic) pada Field Graphic Player Controller.

●​ Coba Play dan test jalan dengan menggunakan Arrow Key kiri dan kanan.
Gimana, Keren kan !?
Membuat Fitur Player Menembak
●​ Buat GameObject baru dan beri nama Bullet lalu tambahkan child empty beri
nama Graphic

●​ Pada assets cari sprite Bullet dan ubah Pixel Per Unit menjadi 32 lalu Apply.

●​ Pada Graphic tambahkan component Sprite Renderer dan pada field sprite pilih
sprite Bullet dan ubah scale transform menjadi (0.4, 0.4, 0.4)
●​ Pada GameObject Bullet tambahkan Rigidbody2D dan Circle Collider2D. Pada
Rigidbody2D ubah Body Type menjadi Kinematik dan centang contraint Freeze
Rotation Z. Pada Circle Collider2D sesuaikan ukuran dan letak circle collider
dengan sprite bullet dan centang Is Trigger.
●​ IsTrigger adalah collider yang dapat menjalankan script saat Collider tersebut
menyentuh Trigger, Saat di Trigger, dan saat Exit dari object Trigger. IsTrigger di
Script dapat dapat diTrigger dengan fungsi OnTriggerEnter,OnTriggerStay,dan
OnTriggerExit.
●​ Buat Script untuk bullet dengan nama Bullet dan simpan pada folder Scripts. Lalu
tambahkan component script Bullet ini pada GameObject Bullet.
●​ Membuat prefab GameObject Bullet dan simpan prefab Bullet pada folder
Prefabs. Setelah itu hapus GameObject Bullet dari Hierarchy.

●​ Berikut adalah script untuk Bullet

using UnityEngine;
using [Link];

public class Bullet : MonoBehaviour


{
[SerializeField] private float speed = 2;
[SerializeField] private float damage = 2;
[SerializeField] private float dieTime = 5;

public string targetTag = "Enemy";

private Vector2 direction;

private Rigidbody2D rb2;

void Start()
{
rb2 = GetComponent<Rigidbody2D>();
}

void Update()
{
[Link] = [Link] * speed;

dieTime -= [Link];

if (dieTime < 0)
{
Destroy(gameObject);
}
}

public void Launch(Vector2 direction, string targetTag, float speed, float


damage)
{
[Link] = direction;
[Link] = speed;
[Link] = damage;
[Link] = targetTag;
}

public float GetDamage()


{
return damage;
}
}

●​ Pada Script PlayerController modifikasi agar player dapat melakukan shooting


bullet

using [Link];
using [Link];
using UnityEngine;

public class PlayerController : MonoBehaviour


{
public static PlayerController Instance { get; private set; }

[Header("Properties")]
[SerializeField] private SpriteRenderer graphic;

[Header("Status")]
public float health = 100;
public float attack = 5;

public float healthMax { private set; get; }

private bool isShooting = true;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;
[SerializeField] private float shootingTimeMax = 1.0f;
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private float bulletSpeed = 10;

[SerializeField] private Vector2 gunOffset;

private float shootingTime = 0;


private Rigidbody2D rb2;

void Awake()
{
Instance = this;
}

void Start()
{
rb2 = GetComponent<Rigidbody2D>();

shootingTime = shootingTimeMax;
healthMax = health;
}

void Update()
{

MovementController();
ShootController();

void MovementController()
{
float x = [Link]("Horizontal");

Vector2 direction = [Link];


direction.x = x * moveSpeed;

[Link] = direction;

//sprite dibalik ketika arahnya ke kiri


if (direction.x < 0)
{
[Link] = true;
} else if (direction.x > 0)
{
[Link] = false;
}
}

void ShootController()
{
isShooting = [Link](KeyCode.Z);

if (isShooting)
{
shootingTime -= [Link];
} else
{
shootingTime = shootingTimeMax;
}

if (isShooting && shootingTime < 0)


{
shootingTime = shootingTimeMax;
Shoot();
}
}

void Shoot()
{
int direction = ([Link] == false ? 1 : -1);

Vector2 gunPos = new Vector2(gunOffset.x * direction +


[Link].x, gunOffset.y + [Link].y);

GameObject bulletObj = Instantiate(bulletPrefab, gunPos,


[Link]);
Bullet bullet = [Link]<Bullet>();

if (bullet)
{
[Link](new Vector2(direction, 0),"Enemy", bulletSpeed,
attack);
}
}
}

●​ Assign prefab Bullet pada component PlayerController. Ubah property Gun


Offset menjadi (0.75, -0.5)
●​ Instantiate berfungsi untuk melakukan spawn game object. Biasanya
Instantiate dilakukan untuk melakukan spawn prefab pada posisi tertentu.
●​ Quaternion berfungsi untuk representasi rotasi dalam script. Jadi kita bisa
mendapatkan informasi bagaimana posisi rotasi object dengan memanggil fungsi
Quarterion.
●​ Coba Test Play dan Tahan Z untuk melakukan shooting.

Membuat Enemy
●​ Buat GameObject baru dan beri nama Mushroom lalu tambahkan child empty
beri nama Graphic

●​ Pada assets cari masuk ke Assets/Sprites/Mushroom dan ubah semua Pixel Per
Unit dari sprites tersebut menjadi 32 lalu Apply.
●​ Pada Graphic tambahkan component Sprite Renderer dan pada field sprite pilih
sprite mushroom_0 sebagai contoh.
●​ Pada GameObject Mushroom tambahkan Rigidbody2D dan Box Collider2D.
Pada Rigidbody2D centang contraint Freeze Rotation Z. Pada Box Collider2D
sesuaikan ukuran dan letak box collider dengan sprite mushroom.
●​ Sebelum membuat code untuk Enemy. Buat tag untuk Player, Bullet dan Enemy
dengan cara Klik Untagged lalu Add Tag.
●​ Jangan lupa untuk mengganti tag Mushroom ke tag Enemy

●​ Tambahkan juga tag Bullet pada Bullet dan tag Player pada Player
●​ Tag adalah representasi Object dalam bentuk "kata" yang dapat dikustomisasi.
Misal dalam satu scene kita mempunyai 2 Objek Balok yang sama. Tag dapat
membedakan GameObject yang sama tersebut jika memiliki purpose yang
berbeda-beda. Tag sangat penting untuk mengindentifikasi object game didalam
script.
●​ Tag dari tiap object pasti layernya diset default. Oleh karena itu player yang
sudah kita buat layernya sudah diset ke default.
●​ Buat Script baru dan beri nama EnemyController.

●​ Berikut adalah code untuk EnemyController.

using [Link];
using [Link];
using UnityEngine;

public class EnemyController : MonoBehaviour


{
//basic status yang ada di enemy
[Header("Status")]
public float health = 20;
public float attack = 5;

public Transform attackTarget;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;

// Update is called once per frame


void Update()
{
Movement();
FallDie();
}

protected virtual void Movement() {

//fungsi untuk mengurangi hp dari damage yang telah diterima


public void DamagedBy(float damage)
{
health -= damage;
if (health <= 0)
{
health = 0;
Die();
}
}

//Fungsi untuk menghancurkan GameObject ketika jatuh ke bawah disaat


//psosisi Y GameObject kurang dari -20
void FallDie()
{
if ([Link].y < -20)
{
Die();
}
}

//fungsi penghancuran GameObject


void Die()
{
Destroy(gameObject);
}

//fungsi mengambil nilai attack dari properti enemy


public float GetAttackDamage()
{
return attack;
}

// bekerja saat collider "menyentuh" trigger


private void OnTriggerEnter2D(Collider2D collision)
{
if ([Link] == "Bullet")
{
//fungsi mengambil nilai damage dari bullet terlebih dahulu
Bullet bullet = [Link]<Bullet>();
if ([Link] == "Enemy")
{
//lalu akan mengurangi darah dari GameObject ini ("enemy")
//menggunakan fungsi DamagedBy()
float damage = [Link]();
DamagedBy(damage);
Destroy([Link]);
}
}
}
}

●​ OnTriggerEnter bekerja saat collider "menyentuh" trigger.


●​ OnCollisionEnter prinsipnya sama seperti OnTriggerEnter namun bekerja saat
collider "bertabrak" atau bertemu dengan collider lain.
●​ Code EnemyController akan digunakan sebagai parent class dari enemy yang
akan kita buat. Jadi untuk menambah enemy baru kita dapat melakukan inherit
pada Class EnemyController ini.

Membuat Enemy Mushroom


●​ Buat Script baru dan beri nama EnemyMushroom

●​ Berikut adalah code script EnemyMushroom yang merupakan child class dari
EnemyController.

using [Link];
using [Link];
using UnityEngine;
public class EnemyMushroom : EnemyController
{
[Header("Mushroom")]
[SerializeField] SpriteRenderer graphic;

[SerializeField] GameObject bulletPrefab;


[SerializeField] private float bulletSpeed;

[SerializeField] private float attackMinDistance;


[SerializeField] private float attackTimeMax;

[SerializeField] private Vector3 shootOffset;


private float attackTime = 0;

protected override void Movement()


{
if (attackTarget)
{
float distance = [Link]([Link],
[Link]);
if (distance < attackMinDistance)
{
if ([Link].x < [Link].x)
{
[Link] = true;
} else
{
[Link] = false;
}

if (attackTime < 0)
{
Shoot();
attackTime = attackTimeMax;
}

attackTime -= [Link];
}
}
}

void Shoot()
{
int direction = ([Link] == false ? 1 : -1);

Vector3 shootOffsetDirection = shootOffset;

if (direction < 0)
{
shootOffsetDirection.x *= -1;
}

Vector3 shootPos = [Link] + shootOffsetDirection;

GameObject bulletObj = Instantiate(bulletPrefab, shootPos,


[Link]);
Bullet bullet = [Link]<Bullet>();
[Link](new Vector2(direction, 0), "Player", bulletSpeed,
attack);
}
}

●​ Tambahkan Component EnemyMushroom pada GameObject Mushroom. Isi field


graphic dengan child Graphic pada Mushroom dan Attack Target isi dengan
Game Object Player.

●​ Karena mushroom menyerang dengan cara shooting bullet juga maka kita
lakukan duplicate pada prefab Bullet dan ganti namanya menjadi EnemyBullet
lalu ubah warnanya menjadi merah.
●​ Pada BulletEnemy ubah TargetTag menjadi "Player". Ini akan membuat bullet
hanya dapat mengenai collider gameobject yang memiliki tag "Player". Seperti
halnya bullet milik player hanya dapat mengenai collider gameobject yang
memiliki tag "Enemy". Property TargetTag ini akan digunakan pada script - script
yang akan datang.

●​ Assign bullet pada component EnemyMushroom sebelumnya dengan


EnemyBullet. Atur konfigurasinya pada inspector seperti berikut.
●​ Membuat Prefab untuk Enemy Mushroom.

Membuat Fitur Player Loncat


●​ Sebelum membuat fitur loncat, pada setiap GameObject tanah yang memiliki
collider pada Environment, ubah layer nya menjadi Obstacle. Jika belum ada
tambahkan dengan Add Layer.
●​ Setelah itu modifikasi Script PlayerController sebagai berikut.

using [Link];
using [Link];
using UnityEngine;

public class PlayerController : MonoBehaviour


{
public static PlayerController Instance { get; private set; }

[Header("Properties")]
[SerializeField] private SpriteRenderer graphic;

[Header("Status")]
public float health = 100;
public float attack = 5;
public bool canBeMoved = true;

public float healthMax { private set; get; }

private bool isGrounded = true;


private bool isShooting = true;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;
[SerializeField] private float jumpForce = 5.0f;
[SerializeField] private float shootingTimeMax = 1.0f;
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private float bulletSpeed = 10;

[SerializeField] private Vector2 gunOffset;

private float shootingTime = 0;

[SerializeField] private float minGroundDistance = 1.5f;

private Rigidbody2D rb2;

void Awake()
{
Instance = this;
}

void Start()
{
rb2 = GetComponent<Rigidbody2D>();

shootingTime = shootingTimeMax;
healthMax = health;
}

void Update()
{
if (canBeMoved)
{
MovementController();
JumpController();
ShootController();
}
}

void MovementController()
{
float x = [Link]("Horizontal");
Vector2 direction = [Link];
direction.x = x * moveSpeed;

[Link] = direction;

//sprite dibalik ketika arahnya ke kiri


if (direction.x < 0)
{
[Link] = true;
}
else if (direction.x > 0)
{
[Link] = false;
}
}

void JumpController()
{
RaycastHit2D ray = [Link]([Link], [Link],
10, [Link]("Obstacle"));

if (ray && [Link] < minGroundDistance)


{
isGrounded = true;
}
else
{
isGrounded = false;
}

if ([Link]([Link]))
{
Jump();
}
}

void Jump()
{
if (isGrounded)
{
[Link]([Link] * jumpForce, [Link]);
}
}

void ShootController()
{
isShooting = [Link](KeyCode.Z);
if (isShooting)
{
shootingTime -= [Link];
}
else
{
shootingTime = shootingTimeMax;
}

if (isShooting && shootingTime < 0)


{
shootingTime = shootingTimeMax;
Shoot();
}
}

void Shoot()
{
int direction = ([Link] == false ? 1 : -1);

Vector2 gunPos = new Vector2(gunOffset.x * direction +


[Link].x, gunOffset.y + [Link].y);

GameObject bulletObj = Instantiate(bulletPrefab, gunPos,


[Link]);
Bullet bullet = [Link]<Bullet>();

if (bullet)
{
[Link](new Vector2(direction, 0), "Enemy", bulletSpeed,
attack);
}
}
}

●​ Ray dapat dimisalkan sebagai cahaya yang ditembakkan ke arah tertentu untuk
mendapatkan Raycast Hit. Dalam Unity Ray dapat digunakan sebagai pengukur
jarak dari posisi Ray ditembakkan ke arah yang dituju. Ray akan berhenti ketika
melewati jarak yang diinginkan atau menabrak suatu Collider tertentu.
●​ Raycast Hit merupakan hasil dari Ray yang ditembakkan. Terdapat banyak
property pada RaycastHit. Contohnya adalah posisi berhenti, jarak hit dan
banyak lainnya.
●​ Layer merupakan suatu golongan yang dapat digunakan untuk mengelompokkan
suatu game object pada scene. Namun fungsi layer tidak hanya terbatas untuk
pengelompokan saja. Terdapat fungsi penting, salah satunya ada pada Camera,
kita dapat mengatur layer mana saja yang dapat dirender oleh camra tersebut.
●​ Layer Mask merupakan suatu layer yang digunakan untuk masking collider. Salah
satu penggunaannya adalah saat melakukan Raycast dari titik tertentu, kita
dapat mencegah ray itu hanya dapat menabrak collider yang berada pada layer
"Obstacle" misalnya sehingga Raycast tidak terhenti pada collider Player.
●​ Coba Play Test lalu tekan Up Arrow untuk loncat dengan Player.

●​ ICE BREAKING : Coba edit Jump Force menjadi 20 untuk lompatan super atau
ganti Min Ground Distance menjadi 5 agar bisa jump on air.

Membuat Camera Follow


●​ Camera berfungsi sebagai object yang digunakan user/pemain untuk melihat
world dari game yang sudah dibuat. Tampilan pada GameView akan mengikuti
arah view camera yang telah diatur.
●​ Pada Camera terdapat property Clear Flags. Clear Flags merupakan suatu fitur
agar camera melakukan render pada background dengan cara yang diberikan.
Misalnya pada Skybox, camera akan melakukan render Skybox pada bagian
camera yang tidak merender game object, atau pada Solid Color sehingga
camera memberkian warna solid pada bagian camera yang tidak merender
game object.

●​ Mengubah warna Background Camera, coba ubah warna background camera


menjadi #03071C
●​ Selanjutnya adalah membuat suatu script agar Main Camera dapat mengikuti
pergerakan Player.
●​ Buat Script baru di folder Scripts dengan nama CameraFollow

●​ Berikut adalah kode script untuk CameraFollow

using UnityEngine;
using [Link];

public class CameraFollow : MonoBehaviour


{
public bool isFollowing = true;
public Transform target;

private Vector3 targetPos;


public Vector3 targetOffset;

[Range(0, 1.0f)] public float followRatio = 1.0f;

void Update()
{
if (target)
{
if (isFollowing)
{
targetPos = [Link] + targetOffset;
}

Vector3 newPos = [Link]([Link], targetPos,


followRatio);
newPos.z = [Link].z;

[Link] = newPos;
}
}
}

●​ Attribute Range merupakan salah satu attribute yang dapat mengubah field
menjadi Range dari suatu variable. Contohnya adalah menggunakan Range dari
0 sampai 1 sehingga nilai variable tersebut dapat diatur dari inspector dari 0
hingga 1.
●​ Lerp atau Linear Interpolation merupakan satu metode yang digunakan untuk
melakukan specify nilai tertentu. Misal terdapat suatu nilai dari 0 hingga 100,
dengan menggunakan Lerp dan ratio 0.5 maka nilai tersebut akan bernilai 50.
●​ Tambahkan component script CameraFollow pada Game Object Main Camera

●​ Assign Player pada field Target dan isi field yang lain sesuai kebutuhan
H. Membuat GameMaster yang mengontrol sebagian besar
Game

Membuat GameManager
●​ SceneManagement adalah salah satu library/module dalam script Unity yang berisi
berbagai fungsi untuk manage para scenes yang sudah kita buat di unity.
Bagaimana kita mengatur perpindahan dari scene A ke scene B, misal dari
scene Main menu ke Scene Level 1 atau sebaliknya dan berbagai fungsi lain.
●​ ActiveScene adalah Scene yang sedang running/active saat game berjalan.
●​ LoadScene berfungsi untuk memuat scene yang akan diakses
selanjutnya/berpindah ke scene yang dipilih.
●​ buildIndex: Setiap Scene pasti mempunyai index nya sendiri (diatur saat akan
build game). Sehingga jika ingin memanggil suatu Scene tinggal memanggil
index dari scene tersebut. Contoh
:[Link]([Link]().buildIndex + 1);
berarti kita mengakses Scene yang index nya lebih 1 dari Active Scene yang
sedang berjalan.
●​ Kita akan mengamalkan Singleton Pattern pada GameManager. Singleton
Pattern merupakan suatu metode menyimpan Instance dari class tersebut pada
suatu static property pada class itu sendiri. Hal ini digunakan untuk menghindar
dari referensi object yang berlebihan atau tidak cocok untuk direferensikan.
●​ Berikut adalah code untuk Script GameManager.

using [Link];
using [Link];
using UnityEngine;
using [Link];

public class GameManager : MonoBehaviour


{
public static bool isGameOver { get; private set; }
public static bool isLevelComplete { get; private set; }

private void Awake()


{
isGameOver = false;
isLevelComplete = false;
}

private void Update()


{
if (isLevelComplete)
{
if ([Link]([Link]))
{
NextLevel();
}
}
else if (isGameOver)
{
if ([Link]([Link]))
{
RetryGame();
}
}
}

public static void GameOver()


{
isGameOver = true;
}

public static void CompleteLevel()


{
isLevelComplete = true;
}

public static void NextLevel()


{
[Link]([Link]().buildIndex + 1);
}

public static void RetryGame()


{
[Link]([Link]().buildIndex);
}
}

Membuat ScoreManager
●​ Sama seperti GameManager, ScoreManager juga akan mengamalkan Singleton
Pattern.
●​ Berikut merupakan code untuk Script ScoreManager.

using UnityEngine;
using [Link];

public class ScoreManager : MonoBehaviour


{
public static ScoreManager Instance { get; private set; }

public static int currentEnemyProgress { get; private set; }


public static int targetEnemyProgress { get; private set; }

void Awake()
{
Instance = this;
}

private void Start()


{
EnemyController[] enemyControllers =
FindObjectsOfType<EnemyController>();

targetEnemyProgress = [Link];
currentEnemyProgress = 0;
}

public static void DefeatEnemy()


{
currentEnemyProgress += 1;

if (currentEnemyProgress >= targetEnemyProgress)


{
[Link]();
}
}
}

Membuat Game Master


●​ Buat GameObject Empty baru, lalu tambahkan component GameManager dan
ScoreManager
Membuat Fitur Player mati
●​ Setiap kali player terkena bullet dari Enemy atau player menyentuh Enemy atau
ketika player jatuh, kita dapat menambahkan fitur agar Player bisa mati sehingga
level akan di restart. Untuk itu modifikasi PlayerController sebagai berikut.

using [Link];
using [Link];
using UnityEngine;

public class PlayerController : MonoBehaviour


{
public static PlayerController Instance { get; private set; }

[Header("Properties")]
[SerializeField] private SpriteRenderer graphic;

[Header("Status")]
public float health = 100;
public float attack = 5;

public bool canBeMoved = true;

public float healthMax { private set; get; }

private bool isGrounded = true;


private bool isShooting = true;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;
[SerializeField] private float jumpForce = 5.0f;
[SerializeField] private float shootingTimeMax = 1.0f;
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private float bulletSpeed = 10;

[SerializeField] private Vector2 gunOffset;

private float shootingTime = 0;

[SerializeField] private float minGroundDistance = 1.5f;

private Rigidbody2D rb2;

void Awake()
{
Instance = this;
}

void Start()
{
rb2 = GetComponent<Rigidbody2D>();

shootingTime = shootingTimeMax;
healthMax = health;
}

void Update()
{
if (canBeMoved)
{
MovementController();
JumpController();
ShootController();
}

FallDie();
}

void MovementController()
{
float x = [Link]("Horizontal");

Vector2 direction = [Link];


direction.x = x * moveSpeed;

[Link] = direction;

//sprite dibalik ketika arahnya ke kiri


if (direction.x < 0)
{
[Link] = true;
} else if (direction.x > 0)
{
[Link] = false;
}
}

void JumpController()
{
RaycastHit2D ray = [Link]([Link], [Link],
10, [Link]("Obstacle"));

if (ray && [Link] < minGroundDistance)


{
isGrounded = true;
} else
{
isGrounded = false;
}

if ([Link]([Link]))
{
Jump();
}
}

void Jump()
{
if (isGrounded)
{
[Link]([Link] * jumpForce, [Link]);
}
}

void ShootController()
{
isShooting = [Link](KeyCode.Z);

if (isShooting)
{
shootingTime -= [Link];
} else
{
shootingTime = shootingTimeMax;
}

if (isShooting && shootingTime < 0)


{
shootingTime = shootingTimeMax;
Shoot();
}
}

void Shoot()
{
int direction = ([Link] == false ? 1 : -1);

Vector2 gunPos = new Vector2(gunOffset.x * direction +


[Link].x, gunOffset.y + [Link].y);

GameObject bulletObj = Instantiate(bulletPrefab, gunPos,


[Link]);
Bullet bullet = [Link]<Bullet>();

if (bullet)
{
[Link](new Vector2(direction, 0),"Enemy", bulletSpeed,
attack);
}
}

public void DamagedBy(float damage)


{
health -= damage;
if (health <= 0)
{
health = 0;
Die();
}
}

void FallDie()
{
if ([Link].y < -20)
{
Die();
}
}

void Die()
{
[Link] = false;
canBeMoved = false;
[Link]();
}
private void OnCollisionEnter2D(Collision2D collision)
{
if ([Link] == "Enemy")
{
float damage =
[Link]<EnemyController>().GetAttackDamage();
DamagedBy(damage);
}
}

private void OnTriggerEnter2D(Collider2D collision)


{
if ([Link] == "Bullet")
{
Bullet bullet = [Link]<Bullet>();
if ([Link] == "Player")
{
float damage = [Link]();
DamagedBy(damage);
Destroy([Link]);
}
}
}
}

I. Membuat UI untuk memperindah Game

Membuat UI
●​ UI atau kepanjangannya adalah User Interface adalah salah satu komponen
dalam game yang sangat penting. UI berfungsi sebagai sistem komponen visual
yang berfungsi menjembatani user/player dengan game yang kita buat.
Bagaimana player dari game kita berinteraksi dengan game, informasi penting
dari game yang ditampilkan ke player, status dari game kita (Game Over dan
sejenisnya) termasuk fungsi dari User Interface. UI dapat meliputi tampilan HUD
dalam game, tombol-tombol, hingga tampilan pengaturan game.
●​ Buat GameObject Canvas untuk UI
●​ Canvas adalah tempat dimana semua yang berhubungan dengan komponen UI
dalam game ditaruh dan diatur placementnya. Tampilan canvas bisa diatur
melalui Scene View.
●​ Select GameObject Canvas dan ubah konfigurasi component Canvas dan
Canvas Scaler sebagai berikut.
●​ Canvas Scaler adalah Component dari UI yang berfungsi mengatur overall scale
dan pixel density dari semua element UI yang berada di dalam Canvas. Oleh
karena itu, saat mengubah/mengatur di Canvas Scaler, semua elemen UI yang
berada di Canvas yang telah dipilih akan terpengaruh (dari segi ukuran (scale
dan pixel)).

Membuat Healthbar Player


●​ Pada Project Assets masuk ke folder UI, ubah semua Pixels Per Unit sprite
menjadi 32.
●​ Pada Hierarchy, klik kanan pada Canvas lalu Create Empty. Beri nama child
tersebut menjadi Healthbar

●​ Klik kanan lagi pada Healthbar, lalu pilih UI > Image. Lakukan sebanyak 3 kali
karena masing - masing untuk Healthbar Bg, Healthbar Border, Healthbar
sebelumnya.

●​ Sorting Order: Sorting order sistemnya seperti layer. object yang berada di
bawah object lain (di panel Hierarchy) akan ditampilkan lebih depan. Contoh:
Dapat dilihat dalam hierarchy object MainMenu dibawah Panel sehingga Object
MainMenu berada di depan panel hitam. Coba kita balik urutannya:

Bisa kita lihat saat order nya dibalik object panel akan membelakangi object main
menu.
●​ Untuk masing - masing Image UI tersebut, assign sprite yang sesuai. Sesuaikan
konfigurasinya seperti berikut agar healthbar terlihat rapi dan bagus.
●​ Berikut adalah hasil sementara dari Healthbar UI.

Membuat Score UI
●​ Pada Hierarchy, klik kanan pada Canvas lalu Create Empty. Beri nama child
tersebut menjadi EnemyProgress

●​ Klik kanan lagi pada EnemyProgress, lalu pilih UI > Text. Beri nama Text tersebut
menjadi ProgressText. UI Text ini untuk melakukan track pada score Player.
●​ UI Text adalah komponen UI yang menampilkan text pada tampilan layar player.
●​ Pada Component Text, ubah Text menjadi "4 of 10" sebagai contoh. Lalu ubah
juga Font Size, Horizontal Overflow dan Vertical Overflow nya.
●​ Klik kanan lagi pada EnemyProgress, lalu pilih UI > Image. Beri nama Image
tersebut menjadi ProgressCover. Image UI ini digunakan untuk hiasan score
saja.

●​ Berikut adalah tampilan sementara dari GameObject EnemyProgress.

Membuat Tampilan Game Over


●​ Pada Canvas, buat UI > Image dan beri nama GameOver untuk membuat
vignette. Ubah warnanya menjadi hitam dan alpha yang tipis.
●​ Lalu pada GameObject GameOver tambahkan child text untuk tulisan "Game
Over" dan "Press Space to Retry Level".
●​ Berikut adalah tampilan sementara dari GameOver.
●​ Lalu Disable GameOver, karena kita ingin GameOver ditampilkan saat Game
Over saja.

Membuat Tampilan Level Complete


●​ Duplicate UI GameOver dan ganti namanya menjadi LevelComplete

●​ Edit tulisan seperti yang diinginkan sehingga tampilan LevelComplete adalah


sebagai berikut.
●​ Disable juga LevelComplete, karena kita ingin LevelComplete ditampilkan saat
Level berhasil dimenangkan saja.

Membuat UIManager
●​ Agar UI dapat berubah seiring dengan Game dimainkan maka perlu sebuah
script untuk mengatur UI tersebut.
●​ Buat script baru pada folder Scripts dan beri nama menjadi UIManager.

●​ Berikut adalah code untuk UIManager

using [Link];
using [Link];
using UnityEngine;
using [Link];
using TMPro;

public class UIManager : MonoBehaviour


{
public TextMeshProUGUI enemyProgressText;
public Image playerHealthBar;
public float playerHealthBarFullX = 78;

public GameObject gameOverUI;


public GameObject levelCompleteUI;

public PlayerController player;

void Update()
{
if (enemyProgressText)
{
[Link] = [Link] + " of "
+ [Link];
}

if (playerHealthBar)
{
Vector2 size = [Link];
size.x = [Link] / [Link] * playerHealthBarFullX;

[Link] = size;
}

if (levelCompleteUI && [Link])


{
[Link]([Link]);
} else if (gameOverUI && [Link])
{
[Link]([Link]);
}
}
}

●​ Elemen UI yang berupa text dapat diubah melalui script/code. contoh nya adalah
script berikut: [Link] = [Link] +
" of " + [Link];. Nantinya UI Text yang ingin
diubah akan diattach ke Component script yang sudah terpasang di
GameMaster.
●​ Pada EnemyController panggil method DefeatEnemy() pada ScoreManager agar
progress dapat bertambah ketika Enemy menjalankan method Die().

using [Link];
using [Link];
using UnityEngine;

public class EnemyController : MonoBehaviour


{
[Header("Status")]
public float health = 20;
public float attack = 5;

public Transform attackTarget;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;

void Update()
{
Movement();

FallDie();
}

protected virtual void Movement()


{

public void DamagedBy(float damage)


{
health -= damage;
if (health <= 0)
{
health = 0;
Die();
}
}

void FallDie()
{
if ([Link].y < -20)
{
Die();
}
}

void Die()
{
Destroy(gameObject);
[Link]();
}
public float GetAttackDamage()
{
return attack;
}

private void OnTriggerEnter2D(Collider2D collision)


{
if ([Link] == "Bullet")
{
Bullet bullet = [Link]<Bullet>();
if ([Link] == "Enemy")
{
float damage = [Link]();
DamagedBy(damage);
Destroy([Link]);
}
}
}
}

●​ Kemudian tambahkan component UIManager pada GameObject GameMaster.


Isi konfigurasi UI seperti berikut ini.
●​ Coba mainkan dan kalahkan semua enemy!
UI Untuk Controller
●​ kita modifikasi script Player Controller untuk mengimplementasi UI tombol ke
dalam Gim. Berikut modfikasi dari scriptnya.

using [Link];
using [Link];
using UnityEngine;

public class PlayerController : MonoBehaviour


{
public static PlayerController Instance { get; private set; }

[Header("Properties")]
[SerializeField] private SpriteRenderer graphic;

[Header("Status")]
public float health = 100;
public float attack = 5;

public bool canBeMoved = true;

public float healthMax { private set; get; }

private bool isGrounded = true;


private bool isShooting = true;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;
[SerializeField] private float jumpForce = 5.0f;
[SerializeField] private float shootingTimeMax = 1.0f;
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private float bulletSpeed = 10;

[SerializeField] private Vector2 gunOffset;

private float shootingTime = 0;


private float x;
private bool moveLeft, moveRight;

[SerializeField] private float minGroundDistance = 1.5f;

private Rigidbody2D rb2;

void Awake()
{
Instance = this;
}
void Start()
{
rb2 = GetComponent<Rigidbody2D>();

shootingTime = shootingTimeMax;
healthMax = health;
}

void Update()
{
if (canBeMoved)
{
MovementController();
JumpController();
ShootController();
}

FallDie();

if (moveLeft)
{
//float x = [Link]("Horizontal");

Vector2 direction = [Link];


direction.x = -1 * moveSpeed;

[Link] = direction;

//sprite dibalik ketika arahnya ke kiri


if (direction.x < 0)
{
[Link] = true;
}
else if (direction.x > 0)
{
[Link] = false;
}
}

if (moveRight)
{
//float x = [Link]("Horizontal");

Vector2 direction = [Link];


direction.x = 1 * moveSpeed;

[Link] = direction;
//sprite dibalik ketika arahnya ke kiri
if (direction.x < 0)
{
[Link] = true;
}
else if (direction.x > 0)
{
[Link] = false;
}
}

void MovementController()
{
float x = [Link]("Horizontal");

Vector2 direction = [Link];


direction.x = x * moveSpeed;

[Link] = direction;

//sprite dibalik ketika arahnya ke kiri


if (direction.x < 0)
{
[Link] = true;
}
else if (direction.x > 0)
{
[Link] = false;
}
}

void JumpController()
{
RaycastHit2D ray = [Link]([Link], [Link],
10, [Link]("Obstacle"));

if (ray && [Link] < minGroundDistance)


{
isGrounded = true;
}
else
{
isGrounded = false;
}

if ([Link]([Link]))
{
Jump();
}
}

public void Jump()


{
if (isGrounded)
{
[Link]([Link] * jumpForce, [Link]);
}
}

void ShootController()
{
isShooting = [Link](KeyCode.Z);

if (isShooting)
{
shootingTime -= [Link];
}
else
{
shootingTime = shootingTimeMax;
}

if (isShooting && shootingTime < 0)


{
shootingTime = shootingTimeMax;
Shoot();
}
}

public void Shoot()


{
int direction = ([Link] == false ? 1 : -1);

Vector2 gunPos = new Vector2(gunOffset.x * direction +


[Link].x, gunOffset.y + [Link].y);

GameObject bulletObj = Instantiate(bulletPrefab, gunPos,


[Link]);
Bullet bullet = [Link]<Bullet>();

if (bullet)
{
[Link](new Vector2(direction, 0), "Enemy", bulletSpeed,
attack);
}
}
public void DamagedBy(float damage)
{
health -= damage;
if (health <= 0)
{
health = 0;
Die();
}
}

void FallDie()
{
if ([Link].y < -20)
{
Die();
}
}

void Die()
{
[Link] = false;
canBeMoved = false;
//[Link]
[Link]();
}

private void OnCollisionEnter2D(Collision2D collision)


{
if ([Link] == "Enemy")
{
float damage =
[Link]<EnemyController>().GetAttackDamage();
DamagedBy(damage);
}
}

private void OnTriggerEnter2D(Collider2D collision)


{
if ([Link] == "Bullet")
{
Bullet bullet = [Link]<Bullet>();
if ([Link] == "Player")
{
float damage = [Link]();
DamagedBy(damage);
Destroy([Link]);
}
}
}

public void MoveLeft()


{
moveLeft = true;
}

public void MoveRigth()


{
moveRight = true;
}

public void ResetMove()


{
moveRight = false;
moveLeft = false;
}
}

J. Membuat Scene Baru Agar Game Lebih Menyenangkan

Pengenalan pada Build Settings


●​ Build Settings adalah window yang isi pengaturan utamanya adalah memilih
target platform dari build dari game yang sudah kita buat. Namun dari Build
Settings kita juga dapat menambahkan scene dan mengatur urutan bagaimana
setiap scene akan dibuild.
●​ Pilih File > Build Settings pada Menu Bar untuk membuka Build Settings
●​ Saat ini hanya ada 1 scene, jika belum ada maka tambahkan dengan menekan
tombol Add Open Scenes

●​ Build Index: adalah index dari tiap scene yang akan dibuild. Index scene dimulai
dari '0' hingga banyak scene-1. Urutan Build Index berdasarkan penempatan
scene pada Build Settings (Urutan dari atas ke bawah).
Membuat Scene Baru
●​ Pada Project Window folder Scenes rename Scene sekarang menjadi "Level 1"

●​ Kemudian, lelakukan Duplicate Scene dari Scene Level 1 dengan Ctrl + D lalu
ubah namanya menjadi Level 2. Hal ini dapat diulangi untuk membuat level -
level selanjutnya.

●​ Buka Scene Level 2 dan memodifikasi Scene tersebut. Sebagai contoh


tambahkan enemy yang lebih banyak dari Level 1.

●​ Menambah scene pada build


●​ Buat Scene Baru lagi dan coba buat tampilan seperti berikut. Beri nama scene
tersebut End atau EndLevel.

●​ Kemudian tambahkan scene ini pada build


●​ Coba Play Game dari scene Level 1 dan mainkan game mu.

K. Build Game agar game dapat Dimainkan!

Pengenalan Platform
●​ Game yang ingin dibuild dapat dibuild ke versi berbagai platform. Misal kita
rancang game kita untuk dimainkan di android, maka kita akan set platform build
nya ke android. Begitu pula untuk yang lainnya.

Pengenalan Player Settings


●​ Melakukan Build untuk Windows. Klik Build bukan yang Build and Run

●​ Pilih lokasi build, disarankan folder kosong. Beri nama game dengan kata yang
kamu sukai.
●​ Tunggu hingga proses build selesai. Lalu coba Play Executable. Dalam modul ini
nama game adalah Unlucid. Run [Link] untuk membuka game.

L. Selesai !!

Game dapat dimainkan


M. Extra!! Menambahkan Animasi

Menambah Animasi pada Player


●​ Pada Project Window buat folder baru dan beri nama "Animations". Lalu pada
folder Animations buat folder lagi dengan nama Player. Folder Player akan
digunakan untuk menyimpan animasi dari Player.
●​ Masuk ke folder Animation lalu buat Animator dengan cara klik kanan lalu Create
> Animator Controller dan beri nama "PlayerAnimator".

●​ Animator atau Animator Controller merupakan salah satu component di Unity


yang digunakan untuk mengatur jalannya Animation pada suatu game object.
●​ Masih di folder Animations/Player klik kanan lalu Create > Animation untuk
membuat Animation Clip dan beri nama "PlayerIdle". Lakukan beberapa kali
untuk membuat Animation Clip bernama "PlayerJumpUp", "PlayerJumpDown",
"PlayerRun".

●​ Animation merupakan potongan clip animasi yang dapat digunakan pada


Animator. Contoh Animation adalah clip Run, Jump, Walk, Idle dan lain
sebagainya.
●​ Pada Hierarchy pilih Player, lalu tambahkan component Animator. Kemudian
assign PlayerAnimator sebelumnya pada component tersebut.

●​ Double klik pada PlayerAnimator untuk membuka Animator Window.


●​ Untuk setiap Animation Clip Player yang dibuat, drag and drop pada Animator
Window ini.

●​ Pada Animator terdapat Transition yang digunakan untuk merubah jalannya


animasi. Misal dari animasi Idle ke Run membutuhkan transition. Transition juga
dicontrol berdasarkan arahan yang diberikan User. Misal animasi Jump hanya
dapat dilakukan saat Idle atau Run, tetapi tidak bisa saat Sleep.
●​ Pada Animator Window, Klik kanan pada Any State lalu Make Transition ke
semua klip yang telah dimasukkan.
●​ Any State maksudnya adalah transition dapat dilakukan pada state manapun.
Sebagai contoh meskipun tidak ada transition dari PlayerIdle menuju PlayerRun,
maka Any State tetap dapat menjadi penghubung transisi antara PlayerIdle
menuju PlayerRun.
●​ Animation Clip dapat berupa looping yang dapat di atur. Seperti namanya
Animation Looping adalah animasi berulang, seperti Idle atau Running karena
Animasi akan bergerak terus menerus.
●​ Untuk setiap Animation Clip Player enable Loop Time.
●​ Untuk masing - masing Animation Clip Player kita tambahkan animasi di
dalamnya. Sebagai contoh berikut adalah PlayerIdle. Double click PlayerIdle
untuk memunculkan Animation Window.

●​ Tambahkan Property dengan Add Property lalu pilih


Graphic/SpriteRenderer/Sprite.
●​ Pada Project Window masuk ke folder Sprites/Player dan pilih semua sprite
player_idle lalu drag and drop ke Animation Window pada
Graphic/SpriteRenderer/Sprite tadi.

●​ Ubah Samples Rate menjadi 10 dan sesuaikan time-nya dengan gambar diatas.
●​ Lakukan hal yang sama pada PlayerJumpUp, PlayerJumpDown dan PlayerRun.
●​ Untuk berpindah Transition diperlukan parameter yang dapat mengatur jalannya
animasi. Misal dari Idle ke Run hanya dapat dilakukan ketika parameter
IsRunning bernilai true.
●​ Pada PlayerAnimator, tambahkan parameter bertipe boolean dan beri nama
isGrounded. Lalu parameter velocityX dan velocityY yang bertipe integer.

●​ Untuk melakukan transisi diperlukan Condition untuk mengatur alur Transition.


Untuk setiap Transition ubah konfigurasinya seperti berikut.
●​ Transition dapat berubah karena perubahan Parameter yang mempengaruhi
Condition. Oleh karena itu kita perlu melakukan modifikasi pada code
PlayerController dan menambahkan perubahan paramter. Berikut adalah code
PlayerController yang telah dimodifikasi.

using [Link];
using [Link];
using UnityEngine;

public class PlayerController : MonoBehaviour


{
public static PlayerController Instance { get; private set; }
[Header("Properties")]
[SerializeField] private SpriteRenderer graphic;

[Header("Status")]
public float health = 100;
public float attack = 5;

public bool canBeMoved = true;

public float healthMax { private set; get; }

private bool isGrounded = true;


private bool isShooting = true;
private int velocityX = 0;
private int velocityY = 0;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;
[SerializeField] private float jumpForce = 5.0f;
[SerializeField] private float shootingTimeMax = 1.0f;
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private float bulletSpeed = 10;

[SerializeField] private Vector2 gunOffset;

private float shootingTime = 0;

[SerializeField] private float minGroundDistance = 1.5f;

private Rigidbody2D rb2;


private Animator animator;

void Awake()
{
Instance = this;
}

void Start()
{
rb2 = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();

shootingTime = shootingTimeMax;
healthMax = health;
}

void Update()
{
if (canBeMoved)
{
MovementController();
JumpController();
ShootController();

AnimationController();
}

FallDie();
}

void MovementController()
{
float x = [Link]("Horizontal");

Vector2 direction = [Link];


direction.x = x * moveSpeed;

[Link] = direction;

//sprite dibalik ketika arahnya ke kiri


if (direction.x < 0)
{
[Link] = true;
} else if (direction.x > 0)
{
[Link] = false;
}
}

void JumpController()
{
RaycastHit2D ray = [Link]([Link], [Link],
10, [Link]("Obstacle"));

if (ray && [Link] < minGroundDistance)


{
isGrounded = true;
} else
{
isGrounded = false;
}

if ([Link]([Link]))
{
Jump();
}
}
void Jump()
{
if (isGrounded)
{
[Link]([Link] * jumpForce, [Link]);
}
}

void ShootController()
{
isShooting = [Link](KeyCode.Z);

if (isShooting)
{
shootingTime -= [Link];
} else
{
shootingTime = shootingTimeMax;
}

if (isShooting && shootingTime < 0)


{
shootingTime = shootingTimeMax;
Shoot();
}
}

void Shoot()
{
int direction = ([Link] == false ? 1 : -1);

Vector2 gunPos = new Vector2(gunOffset.x * direction +


[Link].x, gunOffset.y + [Link].y);

GameObject bulletObj = Instantiate(bulletPrefab, gunPos,


[Link]);
Bullet bullet = [Link]<Bullet>();

if (bullet)
{
[Link](new Vector2(direction, 0),"Enemy", bulletSpeed,
attack);
}
}

public void DamagedBy(float damage)


{
health -= damage;
if (health <= 0)
{
health = 0;
Die();
}
}

void FallDie()
{
if ([Link].y < -20)
{
Die();
}
}

void Die()
{
[Link] = false;
canBeMoved = false;
[Link]();
}

void AnimationController()
{
velocityX = (int)[Link]([Link].x, -1, 1);
velocityY = (int)[Link]([Link].y, -1, 1);

[Link]("isGrounded", isGrounded);
[Link]("velocityX", velocityX);
[Link]("velocityY", velocityY);
}

private void OnCollisionEnter2D(Collision2D collision)


{
if ([Link] == "Enemy")
{
float damage =
[Link]<EnemyController>().GetAttackDamage();
DamagedBy(damage);
}
}

private void OnTriggerEnter2D(Collider2D collision)


{
if ([Link] == "Bullet")
{
Bullet bullet = [Link]<Bullet>();
if ([Link] == "Player")
{
float damage = [Link]();
DamagedBy(damage);
Destroy([Link]);
}
}
}
}

●​ Coba Play Game dan amati animasi baru pada Player.

Menambah Animasi pada Enemy


●​ Pada folder Animations buat folder baru dengan nama "Mushroom"

●​ Lalu buat Animator Controller baru dengan nama MushroomAnimator dan


Animation Clip dengan nama MushroomIdle.

●​ Pada MushroomIdle aktifkan Loop Time.

●​ Pada prefab EnemyMushroom tambahkan component Animator. Assign


MushroomAnimator pada component Animator tersebut.
●​ Double click pada MushroomAnimator dan drag and drop MushroomIdle pada
Animator Window.

●​ Double click pada Animation Clip MushroomIdle untuk membuka Animation


Window.
●​ Pada clip MushroomIdle click Add Property lalu tambahkan
Graphic/SpriteRenderer/Sprite.
●​ Pada Project Window masuk ke folder Sprites/Mushroom lalu pilih semua sprites
mushroom_idle. Drag and drop sprites tersebut pada Animation Window bagian
Graphic/SpriteRenderer/Sprite tadi.

●​ Ubah Samples Rate menjadi 10 dan sesuaikan seperti pada gambar diatas.
●​ Pada Prefab Mushroom simpan perubahan agar seluruh Mushroom memiliki
Animator yang sama.
●​ Coba Play Game dan amati animasi baru pada Enemy Mushroom.
N. Menambahkan UI untuk mobile
pertama, download asset untuk UI mobile dan Audio (Assets UI mobile & Audio)

extract file tersebut, kemudian drag ke project tab di unity


buat 4 gameobject baru image sebagai tempat UI mobile

beri nama masing-masing LeftArrow, RightArrow, UpArrow, ShootButton

tambahkan assets image ke dalam gameobject yang sudah dibuat dengan cara drag &
drop ke kolom source image, assets image bisa di akses di dalam folder /Assets UI
mobile & Audio/SpriteUI
agar tombol UI mobile bisa di tekan, ubah script [Link] menjadi seperti
berikut :

using [Link];
using [Link];
using UnityEngine;

public class PlayerController : MonoBehaviour


{
public static PlayerController Instance { get; private set; }

[Header("Properties")]
[SerializeField] private SpriteRenderer graphic;

[Header("Status")]
public float health = 100;
public float attack = 5;
public bool canBeMoved = true;

public float healthMax { private set; get; }

private bool isGrounded = true;


private bool isShooting = true;
private int velocityX = 0;
private int velocityY = 0;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;
[SerializeField] private float jumpForce = 5.0f;
[SerializeField] private float shootingTimeMax = 1.0f;
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private float bulletSpeed = 10;

[SerializeField] private Vector2 gunOffset;

private float shootingTime = 0;

[SerializeField] private float minGroundDistance = 1.5f;

private Rigidbody2D rb2;


private Animator animator;

bool trigMove = false;


bool trigShot = true;

void Awake()
{
Instance = this;
}

void Start()
{
rb2 = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();

healthMax = health;
}

void Update()
{
if (canBeMoved)
{
MovementController();
JumpController();
ShootController();
AnimationController();
}

FallDie();
}

void MovementController()
{
float x = [Link]([Link]("Horizontal"));

if(x != 0){
trigMove = true;
moving(x);
}
else if(trigMove) {
trigMove = false;
moving(0);
}
}

public void moving(float x) {


Vector2 direction = [Link];
direction.x = x * moveSpeed;

[Link] = direction;

//sprite dibalik ketika arahnya ke kiri


if (direction.x < 0)
{
[Link] = true;
} else if (direction.x > 0)
{
[Link] = false;
}
}

void JumpController()
{
RaycastHit2D ray = [Link]([Link], [Link],
10, [Link]("Obstacle"));

if (ray && [Link] < minGroundDistance)


{
isGrounded = true;
} else
{
isGrounded = false;
}
if ([Link]([Link]) || [Link](KeyCode.W))
{
Jump();
}
}

void Jump()
{
if (isGrounded)
{
[Link]([Link] * jumpForce, [Link]);
}
}

void ShootController()
{
isShooting = [Link](KeyCode.Z);

if (isShooting)
{
shootingTime -= [Link];
if(trigShot) {
Shoot();
trigShot = false;
}

} else
{
shootingTime = shootingTimeMax;
trigShot = true;
}

if (isShooting && shootingTime < 0)


{
shootingTime = shootingTimeMax;
Shoot();
}
}

void Shoot()
{
int direction = ([Link] == false ? 1 : -1);

Vector2 gunPos = new Vector2(gunOffset.x * direction +


[Link].x, gunOffset.y + [Link].y);

GameObject bulletObj = Instantiate(bulletPrefab, gunPos,


[Link]);
Bullet bullet = [Link]<Bullet>();

if (bullet)
{
[Link](new Vector2(direction, 0),"Enemy", bulletSpeed,
attack);
}
}

public void DamagedBy(float damage)


{
health -= damage;
if (health <= 0)
{
health = 0;
Die();
}
}

void FallDie()
{
if ([Link].y < -20)
{
Die();
}
}

void Die()
{
[Link] = false;
canBeMoved = false;
[Link]();
}

void AnimationController()
{
velocityX = (int)[Link]([Link].x, -1, 1);
velocityY = (int)[Link]([Link].y, -1, 1);

[Link]("isGrounded", isGrounded);
[Link]("velocityX", velocityX);
[Link]("velocityY", velocityY);
}

private void OnCollisionEnter2D(Collision2D collision)


{
if ([Link] == "Enemy")
{
float damage =
[Link]<EnemyController>().GetAttackDamage();
DamagedBy(damage);
}
}

private void OnTriggerEnter2D(Collider2D collision)


{
if ([Link] == "Bullet")
{
Bullet bullet = [Link]<Bullet>();
if ([Link] == "Player")
{
float damage = [Link]();
DamagedBy(damage);
Destroy([Link]);
}
}
}
}

dan buat script baru juga dengan nama [Link], untuk kodenya sebagai
berikut :

using [Link];
using [Link];
using UnityEngine;
using [Link];

public class ButtonPressed : MonoBehaviour, IPointerDownHandler,


IPointerUpHandler
{

[SerializeField] GameObject Player;


PlayerController _controller;
[Header("False for Left Button, True for Right Button")]
[SerializeField] bool direction = false;
bool pressed;
int x = 0;
// Start is called before the first frame update
void Start()
{
if (Player == null) {
Player = [Link]("Player") as GameObject;
}
_controller = [Link]<PlayerController>();
}

// Update is called once per frame


void Update()
{
if (pressed)
_controller.moving(x);
}

void [Link](PointerEventData eventData){


if (direction)
x = 1;
else
x = -1;

pressed=true;
}

void [Link](PointerEventData eventData) {


x = 0;
_controller.moving(x);
pressed=false;
}
}

tambahkan script button pressed ke GameObject LeftArrow dan RightArrow, tambahkan


event trigger di GameObject UpArrow dan ShootButton, jangan lupa menambahkan
component button pada setiap UI mobile agar tombol bisa di pencet.
O. Menambahkan Sound Effect
Ubah script [Link] untuk menambahkan trigger Audio, scriptnya sebagai
berikut :

using [Link];
using [Link];
using UnityEngine;

public class PlayerController : MonoBehaviour


{
public static PlayerController Instance { get; private set; }

[Header("Properties")]
[SerializeField] private SpriteRenderer graphic;

[Header("Status")]
public float health = 100;
public float attack = 5;

public bool canBeMoved = true;

public float healthMax { private set; get; }


private bool isGrounded = true;
private bool isShooting = true;
private int velocityX = 0;
private int velocityY = 0;

[Header("Configuration")]
[SerializeField] private float moveSpeed = 2.5f;
[SerializeField] private float jumpForce = 5.0f;
[SerializeField] private float shootingTimeMax = 1.0f;
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private float bulletSpeed = 10;

[SerializeField] private Vector2 gunOffset;

private float shootingTime = 0;

[SerializeField] private float minGroundDistance = 1.5f;

[Header("SFV")]​
private AudioSource playerAudio;​
public AudioClip playerJump;​
public AudioClip playerShoot;​
public AudioClip playerMove;​
public AudioClip playerHit;

private Rigidbody2D rb2;


private Animator animator;

bool trigMove = false;


bool trigShot = true;

void Awake()
{
Instance = this;
}

void Start()
{
rb2 = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
playerAudio = GetComponent<AudioSource>();​

shootingTime = shootingTimeMax;
healthMax = health;
}

void Update()
{
if (canBeMoved)
{
MovementController();
JumpController();
ShootController();

AnimationController();
}

FallDie();
}

void MovementController()
{
float x = [Link]([Link]("Horizontal"));

if(x != 0){
trigMove = true;
moving(x);
}
else if(trigMove) {
trigMove = false;
moving(0);
}
}

public void moving(float x) {


Vector2 direction = [Link];
direction.x = x * moveSpeed;

[Link] = direction;

//sprite dibalik ketika arahnya ke kiri


if (direction.x < 0)
{
[Link] = true;
} else if (direction.x > 0)
{
[Link] = false;
}
}

void JumpController()
{
RaycastHit2D ray = [Link]([Link], [Link],
10, [Link]("Obstacle"));

if (ray && [Link] < minGroundDistance)


{
isGrounded = true;
} else
{
isGrounded = false;
}

if ([Link]([Link]) || [Link](KeyCode.W))
{
Jump();
}
}

void Jump()
{
if (isGrounded)
{
[Link]([Link] * jumpForce, [Link]);
[Link](playerJump, 1.0f);
}
}

void ShootController()
{
isShooting = [Link](KeyCode.Z);

if (isShooting)
{
shootingTime -= [Link];
if(trigShot) {
Shoot();
trigShot = false;
}

} else
{
shootingTime = shootingTimeMax;
trigShot = true;
}

if (isShooting && shootingTime < 0)


{
shootingTime = shootingTimeMax;
Shoot();
}
}

void Shoot()
{
[Link](playerShoot, 1.0f);
int direction = ([Link] == false ? 1 : -1);

Vector2 gunPos = new Vector2(gunOffset.x * direction +


[Link].x, gunOffset.y + [Link].y);

GameObject bulletObj = Instantiate(bulletPrefab, gunPos,


[Link]);
Bullet bullet = [Link]<Bullet>();

if (bullet)
{
[Link](new Vector2(direction, 0),"Enemy", bulletSpeed,
attack);
}
}

public void DamagedBy(float damage)


{
[Link](playerHit, 1.0f);

health -= damage;
if (health <= 0)
{
health = 0;
Die();
}
}

void FallDie()
{
if ([Link].y < -20)
{
Die();
}
}

void Die()
{
[Link] = false;
canBeMoved = false;
[Link]();
}

void AnimationController()
{
velocityX = (int)[Link]([Link].x, -1, 1);
velocityY = (int)[Link]([Link].y, -1, 1);

[Link]("isGrounded", isGrounded);
[Link]("velocityX", velocityX);
[Link]("velocityY", velocityY);
}

private void OnCollisionEnter2D(Collision2D collision)


{
if ([Link] == "Enemy")
{
float damage =
[Link]<EnemyController>().GetAttackDamage();
DamagedBy(damage);
}
}

private void OnTriggerEnter2D(Collider2D collision)


{
if ([Link] == "Bullet")
{
Bullet bullet = [Link]<Bullet>();
if ([Link] == "Player")
{
float damage = [Link]();
DamagedBy(damage);
Destroy([Link]);
}
}
}
}

tambahkan AudioClip yang ada di folder /Assets UI mobile & Audio/Audio, tambahkan
gun, hit-wav, dan jump-wav

Anda mungkin juga menyukai