Odak modu
Bu öğreticide, OOP'nin birbiriyle yakından ilişkili iki sütunu olan inheritance ve polimorfizm hakkında bilgi edineceksiniz.
Nesne yönelimli programlamanın sonraki iki sütunu olan inheritance ve polimorfizm derinden iç içe geçmiş durumda. Inheritance, adından da anlaşılacağı gibi, farklı nesneler arasındaki ebeveyn-çocuk ilişkilerine odaklanır. Polimorfizm inheritanceın bir sonucudur ve bir alt sınıfın bir üst sınıftan miras aldığı şeyi değiştirme sürecini ifade eder. Birlikte kullanıldığında, inheritance ve polimorfizm, bir uygulamada yazmanız gereken kod miktarını azaltabilir.
Alternatif metin: Soyutlama, Kapsülleme, Inheritance ve Polimorfizm ile soldan sağa etiketlenmiş, arka arkaya dört sütunun görüntüsü. Inheritance etiketli ikinci sütun vurgulanır.
Miras diğer sınıfların (alt sınıflar olarak adlandırılır) oluşturulabileceği bir birincil sınıf (üst sınıf olarak da bilinir) oluşturma sürecidir. Bir alt sınıf, üst sınıfın tüm özelliklerini otomatik olarak devralır veya devralır. Bir uygulamada farklı sınıfların benzer özellikleri paylaşması yaygındır. Örneğin, bir video oyunu birçok farklı türde düşman sınıfı içerebilir, ancak kendi sağlıklarını yönetme ve oyuncuya zarar verme yeteneği gibi aynı temel özellikleri paylaşmaları muhtemeldir. Inheritance ile, her bir düşman sınıfı için bu sağlık ve hasar işlevselliğini yazma ihtiyacı ortadan kalkar, böylece her sınıfa özgü yazma işlevselliğine odaklanabilirsiniz.
Alternatif metin: Üst sınıflar ve alt sınıflar arasındaki ilişkiyi gösteren akış şeması. Düşman sınıfı diyagramın en üstündedir ve oklar aşağı doğru üç alt sınıfa işaret eder: Hırsız sınıfı, Aldatma sınıfı ve Kendini tanımlayan 'kötü adam' sınıfı. Hem ebeveyn hem de alt sınıflar, "hasar verme" ve "sağlığı azaltma" gibi paylaşılan davranışlara sahiptir, ancak her alt sınıf, ebeveyn veya diğer alt sınıflar tarafından paylaşılmayan benzersiz bir davranışa da sahiptir.
Şimdiye kadar Unity'de yazdığınız her komut dosyasında zaten inheritancedan yararlanıyorsunuz. Varsayılan olarak, yeni bir sınıf oluşturduğunuzda, MonoBehaviour'dan miras alır:
public class SomeClass : MonoBehaviour { }
MonoBehaviour, tüm temel Unity komut dosyası oluşturma işlevlerinin devraldığı temel sınıftır. MonoBehaviour olmadan OnTriggerEnter, GetComponent'i çağıramaz, hatta Başlat veya Güncelle'yi bile kullanamazsınız!
Yukarıdaki şemada, devralan sınıflarını MonoBehaviour'dan Enemy'ye değiştirdikleri için, tüm alt düşman sınıflarının Unity işlevselliğine erişme yeteneklerini kaybedecekleri görünebilir. Neyse ki, Enemy sınıfı Monobehaviour'dan miras aldığı için, Enemy sınıfının çocukları da MonoBehaviour'un çocukları olarak kabul edilir!
Alternatif metin: Soyutlama, Kapsülleme, Inheritance ve Polimorfizm ile soldan sağa etiketlenmiş, arka arkaya dört sütunun görüntüsü. Polimorfizm etiketli üçüncü sütun vurgulanmıştır.
Bir üst sınıftan temel işlevleri devralmak yararlı olsa da, alt sınıfın üst sınıfla tam olarak aynı eylemi gerçekleştirmesini istemediğiniz birçok durum vardır. Polimorfizm, bir nesnenin üst sınıfından miras aldığı şeyin işlevselliğini değiştirmenize olanak tanır.
public class Enemy : MonoBehaviour
{
public void DealDamage ()
{
Player.Health -= 10;
}
}
Yukarıdaki örnekte, Enemy sınıfı, çağrıldığında Oyuncunun sağlığından 10 puan kaldıran bir DealDamage yöntemine sahiptir. Enemy'nin çocuğu olan Thief sınıfı, bu yöntemi sınıfta bildirmeden çağırabilir.
public class Thief : Enemy
{
private void Update()
{
if (Player.isSeen)
{
DealDamage(); // method from parent class can be called
}
}
}
Hırsızın Düşman sınıfıyla tam olarak aynı miktarda hasar vermesini istiyorsanız bu iyidir, ancak ya farklı bir değerde olmasını istiyorsanız? Bu değişiklikler, yöntemi geçersiz kılma olarak bilinen süreç aracılığıyla gerçekleştirilir.
Üst sınıfta geçersiz kılmak istediğiniz yöntemin önce geçersiz kılma için işaretlenmesi gerekir. Bu, onu sanal bir yöntem haline getirerek yapılır:
public class Enemy : MonoBehaviour {
public virtual void DealDamage () { // virtual keyword allows overriding
Player.Health -= 10;
}
}
Bir yöntemi sanal olarak belirlemek, geçersiz kılınabileceğini, ancak zorunlu olmadığını gösterir. Bu, mevcut örnek için idealdir, çünkü Thief alt sınıfının DealDamage yöntemini değiştirmesi gerekebilirken, Scoundrel sınıfı gibi başka bir alt sınıf gerekmeyebilir.
DealDamage sanal olarak ayarlandığında, Thief sınıfı DealDamage için kendi yöntemini oluşturarak onu geçersiz kılabilir. Burada sanal yerine geçersiz kılma notasyonunu kullanacağız. Artık özellikle Thief sınıfı için yönteme yeni işlevler ekleyebilirsiniz:
public class Thief : Enemy
{
public override void DealDamage() // can override virtual methods from parent class
{
Player.Health -= 2;
CommitPettyTheft();
}
private void Update()
{
if (Player.isSeen)
{
DealDamage();
}
}
}
Thief sınıfı artık ana Enemy sınıfından daha az miktarda hasar veriyor ve ayrıca Thief'e özgü yöntemlerden birini çağırıyor. Artık Update'te bir Hırsız nesnesi tarafından DealDamage çağrıldığında, ana yöntem yerine özelleştirilmiş DealDamage yöntemi çağrılacak.
Proje özetinde, inşa edilecek öğelerden birinin bir üretkenlik birimi olduğunu göreceksiniz. Bu birim, kullanıcının sahnede seçtiği herhangi bir kaynak türünün üretkenliğini artırmalıdır. Kullanıcı kaynağı forkliftle aynı şekilde seçecektir: üniteyi seçmek için sol tıklayın ve taşınacak kaynağı seçmek için sağ tıklayın. Bir kaynağın verimliliği ancak verimlilik birimi aktif olarak üzerinde çalışırken artırılmalı ve birim kaynaktan ayrılırsa normal üretim hızına dönmelidir.
Projenizde şöyle görünebilir:
Forklift, kendisi Unit sınıfının bir alt öğesi olan TransporterUnit betiği tarafından yönetilir. Unit sınıfına bakarsanız, hareket için ihtiyaç duyduğumuz tüm işlevlerin orada olduğunu görürsünüz, bu nedenle üretkenlik birimimizin Unit'in başka bir alt sınıfı olması mantıklıdır.
Alternatif metin: Kollarını tutan bir işçi olan “ProductivityUnit Prefabrik” in Sahne görünümünde yakın çekim
public class ProductivityUnit : Unit // replace MonoBehaviour with Unit
{
}
Komut dosyanızda şunu söyleyen bir hata görünecektir: 'ProductivityUnit', devralınan soyut üye 'Unit.BuildingInRange()' uygulamıyor. Endişelenme - bunu hemen düzelteceğiz.
protected abstract void BuildingInRange();
Geçersiz kılmanın isteğe bağlı olduğu sanal yöntemlerin aksine, bu yöntem geçersiz kılınması gerektiğini belirten soyut gösterimi kullanır. Soyut yöntemler, tüm alt sınıfların belirli bir işlevsellik türüne ihtiyaç duyacağını, ancak bu işlevselliğin her alt sınıfta ayrı olarak kodlanması gerektiğini fark ettiğinizde yararlıdır. Bu durumda, BuildingInRange, bir birim bir kaynak yığınıyla (bina sınıfının bir çocuğu olan) etkileşim kurduğunda olan her şeyi yönetmeyi amaçlar, ancak meydana gelen şey, hangi alt sınıfın yöntemi çağırdığına bağlı olarak değişecektir.
Bu nedenle, ProductivityUnit.cs'de yapmanız gereken tek şey bu yöntemi geçersiz kılmaktır:
protected override void BuildingInRange()
{
}
Alternatif metin: Hız özelliğinin 3 olarak ayarlandığını gösteren Üretkenlik Birimi bileşeni.
Verimlilik biriminin temel özelliği, halihazırda atanmış olduğu kaynak yığınının üretim hızını artırmaktır. Bu işlevselliği geliştirelim.
public class ProductivityUnit : Unit
{
// new variables
private ResourcePile m_CurrentPile = null;
public float ProductivityMultiplier = 2;
protected override void BuildingInRange()
{
// start of new code
if (m_CurrentPile == null)
{
ResourcePile pile = m_Target as ResourcePile;
if (pile != null)
{
m_CurrentPile = pile;
m_CurrentPile.ProductionSpeed *= ProductivityMultiplier;
}
}
// end of new code
}
"As ResourcePile" gösterimi, yığın değişkenini yalnızca m_Target bir ResourcePile türüyse m_Target olarak ayarlar. m_Target bir Temel ise, bu türler eşleşmeyecek ve yığın boş olarak ayarlanacaktır. Bu, m_Target'ın bir kaynak yığını olup olmadığını kontrol etmenin etkili bir yoludur. (yığın != null) ise, m_CurrentPile bu kaynak yığınına ayarlanır ve ProductionSpeed ikiye katlanır.
Bir sonraki çerçevede, yöntemin en üstündeki if ifadesi bu kodun tekrar çalışmasını engelleyecektir, çünkü m_CurrentPile bir değere (kaynak yığını) ayarlanacaktır.
Bu kodda dikkat edilmesi gereken bir diğer ilginç şey de, ebeveyn Unit sınıfında "korumalı" bir değişken olan m_Target değişkenine erişebilmenizdir. Korumalı değişkenler özel değişkenler gibidir, ancak bunlara herhangi bir alt sınıf tarafından da erişilebilir - buna yalnızca ProductivityUnit.cs Unit.cs'den türetildiği için erişebildiniz.
Verimlilik birimini sonlandırmak için, özette açıklandığı gibi, kaynak yığınının üretim hızının birim ayrılır ayrılmaz önceki değerine dönmesini sağlamanız gerekir. Unit sınıfında bu, GoTo yöntemiyle yönetilir - ancak sınıfa bakarsanız, bu ada sahip bir değil iki yöntem olduğunu fark edeceksiniz:
public virtual void GoTo(Building target)
{
m_Target = target;
if (m_Target != null)
{
m_Agent.SetDestination(m_Target.transform.position);
m_Agent.isStopped = false;
}
}
public virtual void GoTo(Vector3 position)
{
m_Target = null;
m_Agent.SetDestination(position);
m_Agent.isStopped = false;
}
Yöntemler adları paylaşamaz - değil mi? Yöntem over loadingsi olarak adlandırılan bu özel durum dışında çoğu durumda bu doğrudur. Her iki GoTo yönteminin de farklı parametre türlerine ve farklı işlevlere sahip olduğuna dikkat edin. Yöntem over loading’i, tek bir yöntemi çok amaçlı hale getirir. Kullanıcı bir hedef seçtiğinde, bu over loading çifti, seçtikleri nesnenin türüne bağlı olarak navigasyonu gerçekleştirecektir.
İlk GoTo yöntemi, parametre olarak kullanıcı bir kaynak yığınına veya tabana sağ tıkladığında toplanan bir Yapı sınıfını alır. Bu parametre daha sonra Unit komut dosyasındaki SetTarget yöntemine iletilir.
İkinci GoTo yöntemi, kullanıcının bir kaynak yığını yerine depoda rastgele bir nokta seçtiği durumlar için bir Vector3 parametresi alır.
Bunları ayrı yöntemler olarak yazabilirsiniz, ancak birden çok aramayı hatırlamanız gerekir! Yöntem over loadinginde, yalnızca bir çağrıyı hatırlamanız gerekir ve iletilen veri türü/türleri hangi kodun çalıştırılacağını belirleyecektir.
Bu, Unity'nin yerleşik yöntemlerinde gördüğünüz başka bir özelliktir. Unity API'sinden bir yöntem çağırdığınızda ve kullanmak için birçok parametre seçeneğiniz olduğunda, yöntem over loadinginden yararlanırsınız. Örneğin, transform.Translate'de dört ayrı aşırı yük vardır; bunlardan birkaçını, Kodla Oluştur'un ilk ünitesinde bir arabayı yolda hareket ettirmek için kullandınız:
Alternatif metin: Create with Code Unit 1'de yapılan “Sürüş Simülasyonu” prototipinden oynanış görüntüsü. Bu, yolun ortasından geçen kırmızı bir aracı gösterir.
public void Translate(Vector3 translation);
// implemented as transform.Translate(Vector3.forward);
public void Translate(float x, float y, float z);
// implemented as transform.Translate(0, 0, 1);
public void Translate(Vector3 translation, Transform relativeTo);
// implemented as transform.Translate(Vector3.forward, Space.Self);
public void Translate(float x, float y, float z, Transform relativeTo);
// implemented as transform.Translate(0, 0, 1, Space.Self);
Üretkenlik biriminin, şu anda bir kaynak yığını üzerinde çalışıp çalışmadığını kontrol etmesi ve görmesi ve ardından, çalışıyorsa, temel GoTo yönteminde meydana gelenleri gerçekleştirmesi ve uzaklaşmadan önce bu kaynak yığınının üretim çıktısını orijinal değerine geri döndürmesi gerekir. Bunu yapmak için GoTo yöntemlerini geçersiz kılalım.
void ResetProductivity()
{
if (m_CurrentPile != null)
{
m_CurrentPile.ProductionSpeed /= ProductivityMultiplier;
m_CurrentPile = null;
}
}
public override void GoTo(Building target)
{
}
Oluşturduğunuz ResetProductivity yöntemini ve base.GoTo yöntemini çağırın.
public override void GoTo(Building target)
{
ResetProductivity(); // call your new method
base.GoTo(target); // run method from base class
}
Temel etiket, komut dosyasına bu geçersiz kılma yöntemindeki yeni koda ek olarak orijinal yöntemi çalıştırmasını söyler.
public override void GoTo(Vector3 position)
{
ResetProductivity();
base.GoTo(position);
}
Bu yöntemler, kullanıcı üretkenlik birimi için yeni bir konum seçer seçmez çalışacaktır. Hareket etmeden önce, halihazırda bir verimlilik yığını seçilmişse, mevcut yığının üretim hızını orijinal hızına geri döndürür.
Inheritance ve polimorfizm, sınıflarınız arasında, yazmanız gereken toplam kod miktarını azaltmaya yardımcı olan karşılıklı ilişkiler oluşturmanıza yardımcı olur. Bu öğreticide, ebeveyn Unit sınıfının işlevselliğini genişleten kendinize ait yeni bir sınıf oluşturdunuz.
Yazılım Kariyerinde İlerlemeni Hızlandıracak Programlar
Patika+ programlarımız ile 4-8 aylık yoğun yazılım kamplarına katıl, temel bilgilerden başlayarak kapsamlı bilgiler edin, yazılım kariyerine başla!
Yorum yapabilmek için derse kayıt olmalısın!