Birleştirilebilecek birçok farklı saldırı türünü nasıl tasarlayabilirim?


17

Yukarıdan aşağıya 2D bir oyun yapıyorum ve birçok farklı saldırı türüne sahip olmak istiyorum. Saldırıları çok esnek hale getirmek ve Isaac'ın Bağlanması'nın çalışma şeklini birleştirmek istiyorum. İşte oyundaki tüm koleksiyonların bir listesi . İyi bir örnek bulmak için Spoon Bender maddesine bakalım .

Kaşık Bender, Isaac'e posta gözyaşları çekme yeteneği verir.

"Sinerjiler" bölümüne bakarsanız, ilginç ancak sezgisel efektler için diğer koleksiyonlarla birleştirilebileceğini göreceksiniz. Örneğin, İç Göz ile birleşirse , "İshak'ın aynı anda birden fazla hedef arama yapmasını sağlar". Bu mantıklı, çünkü İç Göz

Isaac ile üçlü vuruş yaptı.

Böyle şeyler tasarlamak için iyi bir mimari nedir? İşte kaba kuvvet çözümü:

if not spoon bender and not the inner eye then ...
if spoon bender and not the inner eye then ...
if not spoon bender and the inner eye then ...
if spoon bender and the inner eye then ...

Ama bu çok hızlı bir şekilde kontrolden çıkacak. Böyle bir sistem tasarlamanın daha iyi bir yolu nedir?


Şahsen ben sadece tüm donanımlı öğeleri bir listede tutmak ve onları mutasyon geçirdiğiniz bir nesneyi nesneden nesneye götüren bir tür ortak arayüz uygulamak istiyorum. "Her madde için planlanan saldırıyı değiştirin", böylece bir öğe mermi miktarını çoğaltabilir, biri renk tonunu ekleyebilir ve hasarı değiştirebilir (böylece bir öğe kırmızı cıvata yaptıysa ve diğeri sarıysa, her ikisi de saldırıyı değiştirdikten sonra turuncu bir saldırı olur) . Ayrıca, planlanan saldırıyı nasıl değiştireceğine karar vermek için parametreleri olan tek bir genel öğe sınıfınız da olabilir.
Benjamin Danger Johnson

2
Kirby 64'ün tüm olası yetenek kombinasyonları için kaba kuvvet yaklaşımı ve zor programlanmış farklı efektler aldığını belirtmek isterim , bu yüzden yapılabilir.
Kevin

Yanıtlar:


16

Kombinasyonları tamamen elle kodlamanız gerekmez. Bunun yerine her bir öğenin size sağladığı özelliklere odaklanabilirsiniz. Örneğin, Öğe A ayarlanır Projectile=Fireball,Targetting=Homing. B öğesi kümeler FireMode=ArcShot,Count=3. ArcShotMantık dışarı göndermekten sorumludur Countsayısını Projectilebir yay öğelerin.

Bu iki öğe, bu (veya diğer) özellikleri serbestçe değiştiren diğer öğelerle birleştirilebilir. Yeni bir mermi türü eklerseniz, otomatik olarak birlikte çalışır ArcShotve yeni bir ateşleme modu eklerseniz otomatik olarak Fireballmermilerle çalışır. Benzer şekilde, Targettingmermileri FireModeoluştururken mermiler için denetleyiciyi ayarlayan bir özelliktir , böylece mantıklı olarak herhangi bir kombinasyonda kolayca ve önemsiz bir şekilde birleştirilebilirler.

Ayrıca, mülk bağımlılıkları ve benzerlerini de ayarlayabilirsiniz. Örneğin, ArcShotbir sağlayıcınız olmasını gerektirir Projectile(bu sadece varsayılan olabilir). Her ikisi Projectilede kodu sağlayan iki etkin öğeniz varsa hangisini kullanacağınızı bilmesi için öncelikler ayarlayabilirsiniz . Ya da kullanıcının hangi mermi türünü kullanacağını seçmesine izin vermek için kullanıcı arayüzü sağlayabilir veya oynatıcının istemediği yüksek öncelikli öğeleri çözmesini isteyebilir veya en son öğeyi vb. Kullanabilirsiniz. Bir uyumsuzluk sistemine daha fazla izin verebilirsiniz. örneğin, her ikisinde de değişiklik yapan iki öğe Projectileaynı anda donatılamaz.

Genel olarak, mümkün olduğunda, nesneler ve oyununuzdaki nesneler söz konusu olduğunda, prosedürel yaklaşımlara (başka büyük karışıklık varsa ) her türlü veri güdümlü yaklaşımı (veya beyan edici ) tercih edin. Basit verilerle yapılandırılabilen daha üst düzey jenerik mantık, özel kodlanmış kuralların sabit kodlu listelerine kıyasla çok daha fazla tercih edilir.


Küçük nit, ancak kullandığınız örnekler için doğru özelliklere sahip görünmüyorsunuz. "Kaşık Bender" hedef arama ekler ve "İç Göz" üçlü atış ekler. İkisi de ark eklemez ve her ikisi de gözyaşıdır. Örneğinizde tasarımı soyutlaştırmak için rastgele özellikler kullanıyorsanız, yanıltıcı yollarla adlandırılmamışlarsa okumak daha kolay olurdu. Ben buna "Öğe A" ve "Öğe B" yi tercih ederim.
Daniel Kaplan

1
@tieTYT: İsimleri genelleştirdim ve örneği mermi türlerine ve atış modlarına ek olarak hedefleme modlarını içerecek şekilde genişlettim. Asla birkaç dakikadan fazla BoI oynamadım, bu yüzden isimlerin diğerleri gibi içselleştirilemedi. :)
Sean Middleditch

Bana öyle geliyor ki, zor kısım özellik kategorilerini tanımlamaktadır. Örneğin: Hedefleme bir, FireMode başka bir, Sayım 3 olabilir ... ya da olmayabilir. Belki 3 mermi ateş topu olabilir ve 5 silah olsa da el bombası olabilir.
Daniel Kaplan

@tieTYT: kesinlikle. Özel kombinasyonlara veya mantığa izin vermek için sistemi daha da genişletebilirsiniz, ancak bu kuraldan ziyade istisna olmalıdır. Köşe kılıfı için değil, genel durum için optimize edin.
Sean Middleditch

Yordamsal programlama youtu.be/QM1iUe6IofM ile ilgili neden yanıldığınıza dair harika bir video , ayrıca herhangi bir if / else tek tek veri kümelerine bloke olursa haritaları tanımladığınız veri temelli yol, esas olarak kaç özel vaka senaryosunu azaltmak için hiçbir şey yapmaz program, hepsini programlamak zorunda olduğunuz gibi ...
RenaissanceProgrammer

8

Bir OOP dili kullanıyorsanız, bu Dekoratör Desenini kullanmak için iyi bir yer gibi görünür . Bir saldırının nasıl gerçekleştiğini değiştirmek istediğinizde, onu uygun artırmayla süsleyin.

Ham c ++ Örneği:

class AttackBehaviour
{
    /* other code */
    virtual void Attack(double angle);
};

class TearAttack: public AttackBehaviour
{
    /* other code */
    void Attack(double angle);
};

class TripleAttack: public AttackBehaviour
{
    /* other code */
    AttackBehaviour* baseAttackBehaviour;
    void Attack(double angle);
};

void TripleAttack::Attack(angle)
{
    baseAttackBehaviour->Attack(angle-30);
    baseAttackBehaviour->Attack(angle);
    baseAttackBehaviour->Attack(angle+30);
}

Bu yöntem çok sayıda saldırınız varsa ve hepsinin aşağı yukarı aynı şekilde davranması gerektiğinde en iyi yöntem olacaktır. Saldırının değiştiriciyle (örneğin değiştiriciyle yeni animasyon) gerçekleşme şeklini önemli ölçüde değiştirmek istiyorsanız, bu yöntem sizin için değildir.


Animasyonu değiştirmek istersem, bu neden benim için değil? Ayrıca, daha işlevsel bir dilde çalışıyorsam ne olur? Onlar için uygun bir tasarım deseni biliyor musunuz?
Daniel Kaplan

Daha katı çünkü değiştirici her zaman Attacktopladığı nesnenin yöntemini çağırır . TripleAttackSınıf hakkında bilmek gerekir TearAttacksınıfında. Eğer bu doğru olsaydı, else-ifblok kadar baş ağrısına yol açardı . Bu, gözyaşı animasyonlarının TearAttackBehaviournesnenin içinde bulunması gerektiği anlamına gelir . Bu nesne bir TripleAttacknesne tarafından süslendiğini bilmiyor (bilmemeli) . Sonuç, 3 gözyaşı animasyonlar, bağımsız bir şekilde, devam olmasıdır olan bağımsız olarak gerçekleştirilir.
NauticalMile

Bunu kelimelerle açıklamakta zorlanıyorum, eğer başka biri bıçaklamak istiyorsa, misafirim ol.
NauticalMile

Bunu daha işlevsel bir dilde uygulamaya gelince, bir süre düşüneceğim ve hazır olduğumda cevabımı değiştireceğim.
NauticalMile

1

Isaac'in Binding hayranı olarak ben de böyle bir şeyi nasıl yapacağımı merak ettim. Oyundaki sistem, ortaya çıkan davranışların efektlerin birleşiminden kaynaklandığı yerde yeterince sağlamdır (aklıma gelen ayna, kaşık bükücü ve bazı menzil arttırıcılar, Isaac, Magneto stili etrafında dönen, gözyaşı duvarı ile sonuçlanır. ). Çok sayıdaki "if" bloğu pratik olmaz.

Benim sonucum, İshak ve gözyaşlarının büyük bir kitlenin merkezinde iki varlık olduğu Bileşen-Varlık Çerçevesinin varlık olduğudur . Varlıkların bazı temel istatistikleri vardır (hamle hızı, ömür, menzil, hasar, hareketli grafik, vb.) Ve her bileşen bir stat değiştirici ve bir fiil getirecektir.

Kod olarak, Isaac ve gözyaşlarının her birinin bir arayüzün şeylerini içeren bir listesi olurdu. Isaac, IsaacMutator arabirimine abone olan şeylerin bir listesine ve gözyaşı gözyaşıMutator'a sahip olacaktı. IsaacMutator, Isaacs'ın sağlığını, hızını, menzilini, görünümünü ve bazı özel fiilleri değiştirme işlevlerine sahip olacaktı. TearMutator benzer olurdu. Her oyun döngüsü için, Isaac sahip olduğu tüm IsaacMutators arasında döngü yapar ve tüm canlı gözyaşları da olur. İngilizce örneğinize göre, şu şekilde olacaktır:

Isaac has IsaacMutators:
--spoonbender which gives no stat change and: Tears are made homing
--MeatEater which give +1 health, +1 damage and: nothing
--MagicMirror which gives no stat change and: Tears are made reflecting

Tears have tearMutators:
--(depends on MeatEater) +1 damage and: nothing
--(depends on MagicMirror) no stat change and: +1 vector towards isaac
--(depnds on spoonbender) no stat change and: +1 vector towards enemytype

ve bunun gibi. Türler toplanır olduğundan, kalplerinizin içeriğini yığınlayabilir ve kaldırabilirsiniz.


-5

Bence yolunuz en iyi şekilde çalışıyor. Bu tür öğelerin her biri bir koşul verir, birlikte kullanıldıklarında farklı bir koşul oluştururlarsa, tanımlanan 3 olası koşulun tümüne etkili bir şekilde ihtiyacınız olacaktır.

Her iki öğe de mevcut olduğunda yeni bir tanım türü oluşturarak da devam edebilirsiniz, ancak bu aslında evrime katkıda bulunur:

if spoon bender and the inner eye then new spoon bender inner eye

if spoon bender inner eye then ...
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.