Unity'de 2D Kameralarda Uzmanlaşma: Oyun Geliştiricileri İçin Bir Eğitim

Yayınlanan: 2022-03-11

Bir geliştirici için kamera, oyun geliştirme sürecinin temel taşlarından biridir. Bir satranç uygulamasında oyun görünümünüzü göstermekten, sinematik efektler elde etmek için bir 3D AAA oyununda kamera hareketini ustaca yönlendirmeye kadar, kameralar temel olarak şimdiye kadar yapılmış herhangi bir video oyununda, aslında “kamera” olarak adlandırılmadan önce bile kullanılır.

Bu yazıda, 2D oyunlar için bir kamera sisteminin nasıl tasarlanacağını açıklayacağım ve ayrıca bunu piyasadaki en popüler oyun motorlarından biri olan Unity'de nasıl uygulayacağınıza dair bazı noktaları açıklayacağım.

2D'den 2.5D'ye: Genişletilebilir Bir Kamera Sistemi

Birlikte tasarlayacağımız kamera sistemi modüler ve genişletilebilir. Temel işlevselliği sağlayacak birkaç bileşenden oluşan temel bir çekirdeğe ve ardından eldeki duruma bağlı olarak isteğe bağlı olarak kullanılabilen çeşitli bileşenlere/etkilere sahiptir.

Burada inşa ettiğimiz kamera sistemi 2D platform oyunlarını hedefliyor, ancak diğer 2D oyun türlerine, 2.5D oyunlara ve hatta 3D oyunlara kolayca genişletilebilir.

Unity'de 2D Kamerada Uzmanlaşma: Oyun Geliştiricileri İçin Bir Eğitim

Unity'de 2D Kamerada Uzmanlaşma: Oyun Geliştiricileri İçin Bir Eğitim
Cıvıldamak

Kamera işlevselliğini iki ana gruba ayıracağım: kamera takibi ve kamera efektleri.

izleme

Burada yapacağımız kamera hareketinin çoğu izlemeye dayalı olacaktır. Bu, bir nesnenin, bu durumda kameranın, oyun sahnesinde hareket ederken diğer nesneleri izleme yeteneğidir. Uygulayacağımız izleme türleri, 2d platform oyunlarında karşılaşılan bazı yaygın senaryoları çözecek, ancak sahip olabileceğiniz diğer belirli senaryolar için yeni izleme türleri ile genişletilebilirler.

Etkileri

Kamera titremesi, kamera yakınlaştırması, kamera solması ve renk katmanı gibi bazı harika efektler uygulayacağız.

Başlarken

Unity'de yeni bir 2B proje oluşturun ve standart varlıkları, özellikle RobotBoy karakterini içe aktarın. Ardından, bir zemin kutusu oluşturun ve bir karakter örneği ekleyin. Bulunduğunuz sahnede karakterinizle birlikte yürüyebilmeli ve zıplayabilmelisiniz. Kameranın Ortografik moda ayarlandığından emin olun (varsayılan olarak Perspektif olarak ayarlanmıştır).

Bir Hedefi İzlemek

Aşağıdaki komut dosyası, ana kameramıza temel izleme davranışı ekleyecektir. Komut dosyası, sahnenizdeki ana kameraya bir bileşen olarak eklenmelidir ve izlenecek bir hedef nesne atamak için bir alan sunar. Ardından komut dosyası, kameranın x ve y koordinatlarının izlediği nesneyle aynı olmasını sağlar. Tüm bu işlemler Güncelleme adımı sırasında yapılır.

 [SerializeField] protected Transform trackingTarget; // ... void Update() { transform.position = new Vector3(trackingTarget.position.x, trackingTarget.position.y, transform.position.z); }

Ana karakterin izlenmesini sağlamak için RobotBoy karakterini sahne hiyerarşinizden aşağıdaki davranışımızla açığa çıkan “İzleme Hedefi” alanı üzerine sürükleyin.

Ofset Ekleme

Her şey yolunda, ancak hemen bir sınırlama görebiliriz: karakter her zaman sahnemizin merkezindedir. Genellikle ilgilenmediğimiz şeyler olan karakterin arkasında çok şey görebiliriz ve karakterimizin önünde ne olduğunu çok az görüyoruz, bu da oyun için zararlı olabilir.

Bunu çözmek için, komut dosyasına kameranın hedefinden bir uzaklıkta konumlandırılmasını sağlayacak bazı yeni alanlar ekliyoruz.

 [SerializeField] float xOffset; [SerializeField] float yOffset; // ... void Update() { transform.position = new Vector3(trackingTarget.position.x + xOffset, trackingTarget.position.y + yOffset, transform.position.z); }

Aşağıda iki yeni alan için olası bir yapılandırma görebilirsiniz:

İşleri Pürüzsüzleştirmek

Kamera hareketi oldukça sert ve bazı oyuncularda ortamın sürekli algılanan hareketinden dolayı baş dönmesine neden olacak. Bunu düzeltmek için, doğrusal enterpolasyon kullanarak kamera izlemede biraz gecikme ve karakter konumunu değiştirmeye başladıktan sonra kameranın ne kadar hızlı yerine oturduğunu kontrol etmek için yeni bir alan ekleyeceğiz.

 [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); } 

Baş Dönmesini Durdurun: Eksen Kilitleme

Karakterle birlikte kameranın sürekli aşağı yukarı hareketini izlemek beyniniz için hoş olmadığı için eksen kilitlemeyi tanıtıyoruz. Bu, izlemeyi yalnızca bir eksenle sınırlayabileceğimiz anlamına gelir. Ardından, izleme kodumuzu eksenden bağımsız izlemeye ayıracağız ve yeni kilitleme bayraklarını dikkate alacağız.

 [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); } 

Şerit Sistemi

Artık kamera oynatıcıyı yalnızca yatay olarak izlediğine göre, bir ekranın yüksekliğiyle sınırlıyız. Karakter bir merdivene tırmanırsa veya bundan daha yükseğe atlarsa, takip etmeliyiz. Bunu yapmanın yolu bir şerit sistemi kullanmaktır.

Aşağıdaki senaryoyu hayal edin:

Karakter başlangıçta alt şerittedir. Karakter bu kulvarın sınırları içinde kalırken, kamera bizim ayarlayabileceğimiz kulvara özgü yükseklik ofseti üzerinde sadece yatay olarak hareket edecektir.

Karakter başka bir şeride girer girmez kamera o şeride geçecek ve bir sonraki şerit değişikliği gerçekleşene kadar oradan yatay olarak hareket etmeye devam edecektir.

Oyuncu için kafa karışıklığı yaratabilecek atlama gibi eylemler sırasında hızlı şerit değiştirmeyi önlemek için şerit tasarımına özen gösterilmelidir. Bir şerit, ancak oyuncunun karakteri bir süre üzerinde kalacaksa değiştirilmelidir.

Lanes'in seviyeleri, tasarımcının özel ihtiyaçlarına göre oyun seviyesi boyunca değişebilir veya tamamen kesintiye uğrayabilir ve başka bir kamera takip sistemi onların yerini alabilir. Bu nedenle, şerit bölgelerini belirlemek için bazı sınırlayıcılara ihtiyacımız var.

uygulama

Olası bir uygulama, sahnede şeritleri basit nesneler olarak eklemektir. Sistemi uygulamak için yukarıdaki izleme komut dosyasında Y ofseti ile eşleştirilen Y konum koordinatlarını kullanacağız. Bu nedenle X ve Z koordinatlarında konumlanmaları önemli değildir.

İzleme sınıfıyla birlikte LaneSystem sınıfını kameraya ekleyin ve şerit nesnelerini sağlanan diziye atayın. Ayrıca oyuncu karakterini Referans alanına atayın. Referans bir şerit ile başka bir şerit arasında konumlandığından, kamerayı konumlandırmak için ikisinden alttaki kullanılacaktır.

Ve LaneSystem sınıfı, referans konumuna bağlı olarak kamerayı şeritler arasında hareket ettirmeye özen gösterir. FollowSpeed, şerit değiştirmenin çok ani olmasını önlemek için konum enterpolasyonu için burada tekrar kullanılır:

 [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); }

Bu uygulama bir WYSIWYG değildir ve okuyucu için bir alıştırma olarak bırakılmıştır.

Kilit Düğümü Sistemi

Kameranın şeritlerde hareket etmesi harika, ancak bazen kameranın bir şeye, oyun sahnesindeki bir ilgi noktasına (POI) kilitlenmesine ihtiyacımız var.

Bu, sahnede bu tür İÇN'leri yapılandırarak ve bunlara bir tetikleyici çarpıştırıcı ekleyerek başarılabilir. Karakter o tetik çarpıştırıcıya girdiğinde, kamerayı hareket ettirir ve POI'de kalırız. Karakter hareket edip ardından POI'nin tetik çarpıştırıcısını terk ederken, genellikle standart takip davranışı olan başka bir izleme türüne geri döneriz.

Kamera takibinin bir kilit düğümüne ve geriye çevrilmesi, ya basit bir anahtarla ya da izleme modlarının itilip açıldığı bir yığın sistemi ile yapılabilir.

uygulama

Bir kilit düğümü yapılandırmak için, sadece bir nesne oluşturun (boş olabilir veya aşağıdaki ekran görüntüsünde olduğu gibi bir hareketli grafik olabilir) ve ona büyük bir Circle Collider 2D bileşeni ekleyin, böylece kamera açıldığında oynatıcının içinde olacağı alanı işaretler. düğüme odaklanın. Herhangi bir çarpıştırıcı türü seçebilirsiniz, burada örnek olarak Circle'ı seçiyorum. Ayrıca “CameraNode” gibi kolayca kontrol edebileceğiniz bir etiket oluşturun ve bu nesneye atayın.

Aşağıdaki özelliği kameranızdaki izleme komut dosyasına ekleyin:

 public Transform TrackingTarget { get { return trackingTarget; } set { trackingTarget = value; } }

Ardından, kameranın hedefini belirlediğiniz kilit düğümüne geçici olarak değiştirmesine izin verecek olan aşağıdaki komut dosyasını oynatıcıya ekleyin. Komut dosyası ayrıca önceki hedefini hatırlayacak ve böylece oyuncu tetikleme alanının dışına çıktığında ona geri dönebilecektir. Buna ihtiyacınız varsa, devam edip bunu tam bir yığın halinde dönüştürebilirsiniz, ancak amacımız için birden fazla kilit düğümü ile örtüşmediğimiz için bu yeterli olacaktır. Ayrıca lütfen Circle Collider 2D'nin konumunu değiştirebileceğinizi veya kamera kilidini tetiklemek için başka herhangi bir çarpıştırıcı ekleyebileceğinizi unutmayın, bu sadece bir örnek.

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

Kamera Yakınlaştırma

Kamera yakınlaştırması, kullanıcı girişinde veya bir İÇN gibi bir şeye veya bir seviye içinde daha dar bir alana odaklanmak istediğimizde bir animasyon olarak yürütülebilir.

Unity 3D'de 2B kamera yakınlaştırması, kameranın ortografik Boyutu değiştirilerek elde edilebilir. Sonraki komut dosyasını bir kameraya bileşen olarak eklemek ve yakınlaştırma faktörünü değiştirmek için SetZoom yöntemini kullanmak istenen efekti üretecektir. 1.0 yakınlaştırma yok, 0,5 iki kez yakınlaştırma, 2 iki kez uzaklaştırma vb. anlamına gelir.

 [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; }

Ekran Sarsıntısı

Oyunumuzda bir deprem, bir patlama veya başka bir efekt göstermemiz gerektiğinde, kamera sallama efekti işe yarar.

Bunun nasıl yapılacağına ilişkin örnek bir uygulama GitHub'da mevcuttur: gist.github.com/ftvs/5822103. Uygulama oldukça basittir. Şimdiye kadar ele aldığımız diğer etkilerin aksine, biraz rastgeleliğe dayanır.

Soldurma ve Kaplama

Seviyemiz başladığında veya bittiğinde, bir yavaşlama veya azalma efekti güzeldir. Bunu, ekranımızın her yerine uzanan bir panele etkileşimsiz bir UI dokusu ekleyerek uygulayabiliriz. Başlangıçta şeffaf, bunu herhangi bir renk ve opaklıkla doldurabilir veya istediğimiz efekti elde etmek için canlandırabiliriz.

İşte bu yapılandırmanın bir örneği, lütfen UI Panel nesnesinin Ana Kamera Nesnesinin "Kamera Yerleşimi" alt öğesine atandığına dikkat edin. Kamera Yerleşimi, Yer Paylaşımı adlı ve aşağıdakileri içeren bir komut dosyası sunar:

 [SerializeField] Image overlay; // ... public void SetOverlayColor(Color color) { overlay.color = color; } 

Fade-in efekti elde etmek için bir sonraki scriptte olduğu gibi SetOverlayColor ile belirlediğiniz bir hedef renge enterpolasyon ekleyerek Overlay scriptinizi değiştirin ve Panelimizin başlangıç ​​rengini Siyah (veya Beyaz) ve hedef rengi ayarlayın. kaplamanızın son rengine. FadeSpeed'i ihtiyaçlarınıza göre değiştirebilirsiniz, bence 0.8 yeni başlayanlar için iyi bir değer. fadeSpeed ​​değeri bir zaman değiştirici olarak çalışır. 1.0, birden fazla karede, ancak 1 saniyelik bir zaman diliminde gerçekleşeceği anlamına gelir. 0,8, tamamlanmasının 1/0.8 = 1.25 saniye alacağı anlamına gelir.

 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 }

Sarmak

Bu yazıda, oyununuz için modüler bir 2D kamera sistemine sahip olmak için gereken temel bileşenleri ve ayrıca onu tasarlamak için gerekli zihniyetin ne olduğunu göstermeye çalıştım. Doğal olarak, tüm oyunların kendine özgü ihtiyaçları vardır, ancak burada açıklanan temel izleme ve basit efektlerle uzun bir yol alabilir ve ayrıca kendi efektlerinizi uygulamak için bir planınız olabilir. O zaman daha da ileri gidebilir ve her şeyi başka projelere de aktarabileceğiniz yeniden kullanılabilir bir Unity 3D paketinde toplayabilirsiniz.

Oyuncularınıza doğru atmosferi aktarmada kamera sistemleri çok önemlidir. Klasik tiyatro ve filmler arasındaki farkı düşündüğünüzde kullanmayı sevdiğim iyi bir karşılaştırma. Kameralar ve film, sahneye o kadar çok olasılık getirdi ki, sonunda kendi başına bir sanata dönüştü, bu nedenle başka bir “Pong” oyunu uygulamayı planlamıyorsanız, herhangi bir oyun projesinde gelişmiş kameralar tercih ettiğiniz araç olmalıdır. bundan böyle üstleneceğim.

İlgili: MVC ile Unity: Oyun Geliştirmenizin Seviyesini Nasıl Yükseltebilirsiniz?