Menguasai Kamera 2D dalam Unity: Tutorial untuk Pengembang Game
Diterbitkan: 2022-03-11Bagi seorang developer, kamera merupakan salah satu pilar dalam proses pengembangan game. Dari sekadar menampilkan tampilan gim Anda di aplikasi catur hingga dengan mahir mengarahkan gerakan kamera dalam gim 3D AAA untuk mendapatkan efek sinematik, kamera pada dasarnya digunakan dalam gim video apa pun yang pernah dibuat, bahkan sebelum benar-benar disebut "kamera".
Dalam artikel ini saya akan menjelaskan cara mendesain sistem kamera untuk game 2D, dan saya juga akan menjelaskan beberapa poin tentang cara menerapkannya di salah satu mesin game paling populer di luar sana, Unity.
Dari 2D ke 2.5D: Sistem Kamera yang Dapat Diperluas
Sistem kamera yang akan kita rancang bersama bersifat modular dan dapat diperluas. Ini memiliki inti dasar yang terdiri dari beberapa komponen yang akan memastikan fungsionalitas dasar, dan kemudian berbagai komponen/efek yang dapat digunakan secara opsional, tergantung pada situasi yang dihadapi.
Sistem kamera yang kami bangun di sini ditargetkan untuk game platform 2D, tetapi dapat dengan mudah diperluas ke jenis game 2D lainnya, game 2.5D, atau bahkan game 3D.
Saya akan membagi fungsi kamera menjadi dua kelompok utama: pelacakan kamera dan efek kamera.
Pelacakan
Sebagian besar pergerakan kamera yang akan kita lakukan di sini akan didasarkan pada pelacakan. Yaitu kemampuan suatu objek, dalam hal ini kamera, untuk melacak objek lain saat mereka bergerak dalam adegan permainan. Jenis pelacakan yang akan kami terapkan akan menyelesaikan beberapa skenario umum yang dihadapi dalam game platform 2d, tetapi mereka dapat diperluas dengan jenis pelacakan baru untuk skenario khusus lainnya yang mungkin Anda miliki.
Efek
Kami akan menerapkan beberapa efek keren seperti goyangan kamera, zoom kamera, fade kamera, dan overlay warna.
Mulai
Buat proyek 2D baru di Unity dan impor aset standar, terutama karakter RobotBoy. Selanjutnya, buat kotak ground dan tambahkan instance karakter. Anda harus bisa berjalan dan melompat dengan karakter Anda dalam adegan Anda saat ini. Pastikan kamera diatur ke mode Ortografis (diatur ke Perspektif secara default).
Melacak Target
Skrip berikut akan menambahkan perilaku pelacakan dasar ke kamera utama kita. Script harus dilampirkan sebagai komponen ke kamera utama dalam adegan Anda dan itu memperlihatkan bidang untuk menetapkan objek target untuk dilacak. Kemudian skrip memastikan koordinat x dan y kamera sama dengan objek yang dilacaknya. Semua pemrosesan ini dilakukan selama langkah Pembaruan.
[SerializeField] protected Transform trackingTarget; // ... void Update() { transform.position = new Vector3(trackingTarget.position.x, trackingTarget.position.y, transform.position.z); }
Seret karakter RobotBoy dari hierarki adegan Anda ke bidang "Target Pelacakan" yang diekspos oleh perilaku kami berikut untuk mengaktifkan pelacakan karakter utama.
Menambahkan Offset
Semuanya bagus, tapi kita bisa langsung melihat batasannya: karakter selalu berada di tengah adegan kita. Kita bisa melihat banyak hal di belakang karakter, yang biasanya hal-hal yang tidak kita minati, dan kita melihat terlalu sedikit dari apa yang ada di depan karakter kita, yang mungkin merusak gameplay.
Untuk mengatasi ini, kami menambahkan beberapa bidang baru ke skrip yang memungkinkan pemosisian kamera pada offset dari targetnya.
[SerializeField] float xOffset; [SerializeField] float yOffset; // ... void Update() { transform.position = new Vector3(trackingTarget.position.x + xOffset, trackingTarget.position.y + yOffset, transform.position.z); }
Di bawah ini Anda dapat melihat kemungkinan konfigurasi untuk dua bidang baru:
Menghaluskan Hal-hal
Pergerakan kamera cukup kaku dan juga akan membuat beberapa pemain pusing karena pergerakan lingkungan yang dirasakan terus-menerus. Untuk memperbaikinya, kami akan menambahkan beberapa penundaan dalam pelacakan kamera menggunakan interpolasi linier, dan bidang baru untuk mengontrol seberapa cepat kamera masuk ke tempatnya setelah karakter mulai mengubah posisinya.
[SerializeField] protected float followSpeed; // ... protected override void Update() { float xTarget = trackingTarget.position.x + xOffset; float yTarget = trackingTarget.position.y + yOffset; float xNew = Mathf.Lerp(transform.position.x, xTarget, Time.deltaTime * followSpeed); float yNew = Mathf.Lerp(transform.position.y, yTarget, Time.deltaTime * followSpeed); transform.position = new Vector3(xNew, yNew, transform.position.z); }
Hentikan Pusing: Penguncian Sumbu
Karena tidak menyenangkan bagi otak Anda untuk melihat kamera naik dan turun sepanjang waktu bersama dengan karakter, kami memperkenalkan penguncian sumbu. Ini berarti kita dapat membatasi pelacakan hanya pada satu sumbu. Kemudian kami akan memisahkan kode pelacakan kami menjadi pelacakan independen sumbu, dan kami akan mempertimbangkan tanda penguncian baru.
[SerializeField] protected bool isXLocked = false; [SerializeField] protected bool isYLocked = false; // ... float xNew = transform.position.x; if (!isXLocked) { xNew = Mathf.Lerp(transform.position.x, xTarget, Time.deltaTime * followSpeed); } float yNew = transform.position.y; if (!isYLocked) { yNew = Mathf.Lerp(transform.position.y, yTarget, Time.deltaTime * followSpeed); }
Sistem Jalur
Sekarang kamera hanya melacak pemutar secara horizontal, kami terbatas pada ketinggian satu layar. Jika karakter menaiki tangga atau melompat lebih tinggi dari ini, kita harus mengikuti. Cara yang kami lakukan adalah dengan menggunakan sistem lajur.
Bayangkan skenario berikut:
Karakter awalnya berada di jalur bawah. Sementara karakter tetap dalam batas-batas jalur ini, kamera akan bergerak hanya secara horizontal pada offset ketinggian tertentu yang dapat kita atur.
Segera setelah karakter memasuki jalur lain, kamera akan beralih ke jalur tersebut dan terus bergerak secara horizontal dari sana hingga perubahan jalur berikutnya terjadi.
Perhatian harus diberikan pada desain jalur untuk mencegah peralihan jalur cepat selama tindakan seperti melompat, yang dapat membuat kebingungan bagi pemain. Sebuah jalur harus diubah hanya jika karakter pemain akan tetap berada di sana untuk sementara waktu.
Level Lanes dapat berubah sepanjang level game berdasarkan kebutuhan spesifik desainer, atau dapat diinterupsi sama sekali dan sistem pelacakan kamera lain dapat menggantikannya. Oleh karena itu, diperlukan beberapa pembatas untuk menentukan zona jalur.
Penerapan
Implementasi yang mungkin adalah menambahkan jalur sebagai objek sederhana di tempat kejadian. Kami akan menggunakan koordinat posisi Y yang dipasangkan dengan offset Y dalam skrip pelacakan di atas untuk menerapkan sistem. Oleh karena itu, posisi mereka pada koordinat X dan Z tidak menjadi masalah.
Tambahkan kelas LaneSystem ke kamera, bersama dengan kelas pelacakan, dan tetapkan objek jalur ke larik yang disediakan. Tetapkan juga karakter pemain ke bidang Referensi. Karena referensi diposisikan antara jalur dan jalur lainnya, jalur yang lebih rendah dari keduanya akan digunakan untuk memposisikan kamera.
Dan kelas LaneSystem menangani pemindahan kamera di antara jalur, berdasarkan posisi referensi. FollowSpeed digunakan di sini lagi untuk interpolasi posisi, untuk mencegah peralihan jalur menjadi terlalu mendadak:
[SerializeField] Transform reference; [SerializeField] List<Transform> lanes; [SerializeField] float followSpeed = 5f; // ... void Update() { float targetYCoord = transform.position.y; if (lanes.Count > 1) { int i = 0; for (i = 0; i < lanes.Count - 1; ++i) { if ((reference.position.y > lanes[i].position.y) && (reference.position.y <= lanes[i + 1].position.y)) { targetYCoord = lanes[i].position.y; break; } } if (i == lanes.Count - 1) targetYCoord = lanes[lanes.Count - 1].position.y; } else { targetYCoord = lanes[0].position.y; } float yCoord = Mathf.Lerp(transform.position.y, targetYCoord, Time.deltaTime * followSpeed); transform.position = new Vector3(transform.position.x, yCoord, transform.position.z); }
Implementasi ini bukan WYSIWYG, dan dibiarkan seperti latihan untuk pembaca.

Sistem Simpul Kunci
Memiliki kamera yang bergerak di jalur itu bagus, tetapi terkadang kita membutuhkan kamera untuk mengunci sesuatu, sebuah tempat menarik (POI) dalam adegan permainan.
Hal ini dapat dicapai dengan mengonfigurasi POI seperti itu di tempat kejadian dan memasang Collider pemicu padanya. Setiap kali karakter masuk ke trigger clasher itu, kita gerakkan kamera dan tetap di POI. Saat karakter bergerak dan kemudian meninggalkan trigger Collider POI, kita kembali ke jenis pelacakan lain, biasanya perilaku mengikuti standar.
Peralihan pelacakan kamera ke simpul kunci dan kembali dapat dilakukan dengan sakelar sederhana atau dengan sistem tumpukan, di mana mode pelacakan didorong dan muncul.
Penerapan
Untuk mengonfigurasi simpul kunci, cukup buat objek (bisa kosong atau seperti pada gambar di bawah, sprite) dan tempelkan komponen Circle Collider 2D besar ke objek tersebut sehingga menandai area tempat pemain akan berada saat kamera akan memfokuskan simpul. Anda dapat memilih semua jenis clasher, saya memilih Circle sebagai contoh di sini. Buat juga tag yang dapat Anda periksa dengan mudah, seperti “CameraNode” dan tetapkan ke objek ini.
Tambahkan properti berikut ke skrip pelacakan di kamera Anda:
public Transform TrackingTarget { get { return trackingTarget; } set { trackingTarget = value; } }
Kemudian lampirkan skrip berikut ke pemutar, yang memungkinkannya untuk sementara mengalihkan target kamera ke simpul kunci yang telah Anda tetapkan. Script juga akan mengingat target sebelumnya sehingga bisa kembali ke sana saat pemain keluar dari area pemicu. Anda dapat melanjutkan dan mengubah ini dalam tumpukan penuh jika Anda membutuhkannya, tetapi untuk tujuan kami karena kami tidak tumpang tindih beberapa node kunci, ini akan dilakukan. Perlu diketahui juga bahwa Anda dapat mengubah posisi Circle Collider 2D, atau menambahkan lagi jenis collider lain untuk memicu kunci kamera, ini hanyalah contoh belaka.
public class LockBehavior : MonoBehaviour { #region Public Fields [SerializeField] Camera camera; [SerializeField] string tag; #endregion #region Private private Transform previousTarget; private TrackingBehavior trackingBehavior; private bool isLocked = false; #endregion // Use this for initialization void Start() { trackingBehavior = camera.GetComponent<TrackingBehavior>(); } void OnTriggerEnter2D(Collider2D other) { if (other.tag == tag && !isLocked) { isLocked = true; PushTarget(other.transform); } } void OnTriggerExit2D(Collider2D other) { if (other.tag == tag && isLocked) { isLocked = false; PopTarget(); } } private void PushTarget(Transform newTarget) { previousTarget = trackingBehavior.TrackingTarget; trackingBehavior.TrackingTarget = newTarget; } private void PopTarget() { trackingBehavior.TrackingTarget = previousTarget; } }
Zoom Kamera
Zoom kamera dapat dijalankan baik pada input pengguna atau sebagai animasi ketika kita ingin fokus pada sesuatu seperti POI atau area yang lebih sempit dalam suatu level.
Zoom kamera 2D dalam Unity 3D dapat dicapai dengan memanipulasi ukuran ortografis kamera. Melampirkan skrip berikutnya sebagai komponen ke kamera dan menggunakan metode SetZoom untuk mengubah faktor zoom akan menghasilkan efek yang diinginkan. 1,0 berarti tidak ada zoom, 0,5 berarti memperbesar dua kali, 2 berarti memperkecil dua kali, dan seterusnya.
[SerializeField] float zoomFactor = 1.0f; [SerializeField] float zoomSpeed = 5.0f; private float originalSize = 0f; private Camera thisCamera; // Use this for initialization void Start() { thisCamera = GetComponent<Camera>(); originalSize = thisCamera.orthographicSize; } // Update is called once per frame void Update() { float targetSize = originalSize * zoomFactor; if (targetSize != thisCamera.orthographicSize) { thisCamera.orthographicSize = Mathf.Lerp(thisCamera.orthographicSize, targetSize, Time.deltaTime * zoomSpeed); } } void SetZoom(float zoomFactor) { this.zoomFactor = zoomFactor; }
Layar Goyang
Kapan pun kami perlu menunjukkan gempa bumi, ledakan, atau efek lain apa pun dalam permainan kami, efek goyangan kamera sangat berguna.
Contoh implementasi cara melakukannya tersedia di GitHub: gist.github.com/ftvs/5822103. Implementasinya cukup mudah. Berbeda dengan efek lain yang telah kita bahas sejauh ini, itu bergantung pada sedikit keacakan.
Pudar & Hamparan
Ketika level kita mulai atau berakhir, efek fade-in atau out-nya bagus. Kami dapat menerapkan ini dengan menambahkan tekstur UI yang tidak dapat berinteraksi di panel yang membentang di seluruh layar kami. Awalnya transparan, kita bisa mengisinya dengan warna dan opacity apa saja, atau menganimasikannya untuk mencapai efek yang kita inginkan.
Berikut adalah contoh konfigurasi tersebut, harap perhatikan bahwa objek Panel UI ditetapkan ke anak “Camera Overlay” dari Objek Kamera Utama. Camera Overlay menampilkan skrip bernama Overlay yang menampilkan fitur berikut:
[SerializeField] Image overlay; // ... public void SetOverlayColor(Color color) { overlay.color = color; }
Agar memiliki efek fade-in, ubah skrip Overlay Anda dengan menambahkan interpolasi ke warna target yang Anda atur dengan SetOverlayColor seperti pada skrip berikutnya, dan atur warna awal Panel kami menjadi Hitam (atau Putih) dan warna target ke warna akhir overlay Anda. Anda dapat mengubah fadeSpeed menjadi apa pun yang sesuai dengan kebutuhan Anda, menurut saya 0.8 adalah pilihan yang baik untuk permulaan. Nilai fadeSpeed berfungsi sebagai pengubah waktu. 1.0 berarti itu akan terjadi pada beberapa frame, tetapi dalam jangka waktu 1 detik. 0,8 berarti akan membutuhkan 1/0,8 = 1,25 detik untuk menyelesaikannya.
public class Overlay : MonoBehaviour { #region Fields [SerializeField] Image overlay; [SerializeField] float fadeSpeed = 5f; [SerializeField] Color targetColor; #endregion void Update() { if (overlay.color != targetColor) { overlay.color = Color.Lerp(overlay.color, targetColor, Time.deltaTime * fadeSpeed); } } #region Public public void SetOverlayColor(Color color) { targetColor = color; } #endregion }
Bungkus
Dalam artikel ini saya telah mencoba mendemonstrasikan komponen dasar yang diperlukan untuk memiliki sistem kamera 2D modular untuk gim Anda, dan juga pola pikir yang diperlukan untuk mendesainnya. Secara alami, semua game memiliki kebutuhan khusus mereka, tetapi dengan pelacakan dasar dan efek sederhana yang dijelaskan di sini, Anda bisa mendapatkan banyak hal dan juga memiliki cetak biru untuk menerapkan efek Anda sendiri. Kemudian Anda dapat melangkah lebih jauh dan mengemas semuanya ke dalam paket Unity 3D yang dapat digunakan kembali yang dapat Anda transfer ke proyek lain juga.
Sistem kamera sangat penting dalam menyampaikan suasana yang tepat untuk pemain Anda. Perbandingan bagus yang saya suka gunakan adalah ketika Anda memikirkan perbedaan antara teater klasik dan film. Kamera dan film itu sendiri membawa begitu banyak kemungkinan ke adegan yang akhirnya berkembang menjadi seni tersendiri, jadi jika Anda tidak berencana untuk mengimplementasikan game "Pong" lainnya, kamera canggih harus menjadi alat pilihan Anda dalam proyek game apa pun yang Anda buat. 'll melakukan dari sekarang.