Sağlam Bir Öğe Sistemi Oluşturma


12

Amacım modüler / olabildiğince genel bir öğe sistemi oluşturmaktır.

  • Yükseltilebilir Öğeler (+6 Katana)
  • Stat Değiştiricileri (+15 el becerisi)
  • Öğe Değiştiriciler (% X Y hasar verme şansı, donma şansı)
  • Şarj Edilebilir Öğeler (30 kullanımlık sihirli personel)
  • Ögeleri Ayarla (Y özelliğini etkinleştirmek için 4 adet X seti ayarlayın)
  • Nadirlik (ortak, benzersiz, efsanevi)
  • Dezenfekte edilebilir (bazı işçilik malzemelerine ayrılır)
  • Hazırlanabilir (belirli malzemelerle üretilebilir)
  • Sarf malzemesi (5 dakika% X saldırı gücü, iyileşme +15 hp)

* Aşağıdaki kurulumda kalın özellikleri çözebildim.

Şimdi aklımdakileri yansıtmamız için bize birçok seçenek eklemeye çalıştım. Tüm bu özellikleri gerekli şekilde eklemeyi planlamıyorum, ancak uygun gördüğüm şekilde bunları uygulamak istiyorum. Bunlar ayrıca envanter sistemi ve verilerin serileştirilmesi ile de uyumlu olmalıdır.

Kalıtım kullanmayı hiç değil de varlık bileşeni / veri odaklı bir yaklaşım kullanmayı planlıyorum . Başlangıçta aşağıdakileri içeren bir sistem düşündüm:

  • BaseStat: hareket halindeyken istatistikleri tutan genel bir sınıf (öğeler ve karakter istatistikleri için de kullanılabilir)
  • Öğe: listesi, adı, öğe türü ve kullanıcı arabirimi, actionName, açıklama vb. İle ilgili verileri içeren bir sınıf.
  • IWeapon: silah arayüzü. Her silahın IWeapon'ın uygulandığı kendi sınıfı olacak. Bu saldırı ve karakter istatistiklerine bir referans olacaktır. Silah donatıldığında, verileri (Item sınıfı 'stat) karakter statüsüne enjekte edilecektir (BaseStat ne olursa olsun, karakter sınıfına Stat bonusu olarak eklenecektir) Yani, örneğin, bir kılıç ( json ile eşya sınıfları üretir) bu yüzden kılıç karakter istatistiklerine 5 saldırı ekler . Yani ("Saldırı", 5) olarak bir BaseStat'ımız var ( enum'u da kullanabiliriz). Bu istatistik, donatıldıktan sonra karakterin "Saldırı" statüsüne BonusStat (farklı bir sınıf olacaktır) olarak eklenecektir. Böylece adlı bir sınıf Sword uygular IWeapon oluşturulacaktır zaman'Öğe Sınıfı yaratılır. Bu yüzden karakter istatistikleri enjekte edebiliriz ve Saldırı yöntemine hasar verebilir.Bu kılıcın içine ve saldırırken, karakter statüsünden toplam Saldırı statüsünü alabilir
  • BonusStat: BaseStat'a dokunmadan istatistikleri bonus olarak eklemenin bir yoludur.
  • IConsumable: IWeapon ile aynı mantık. Doğrudan stat eklemek oldukça kolaydır (+15 hp) ancak bu kurulumla geçici silahlar eklemekten emin değilim (5 dakika boyunca saldırmak için% x).
  • IUpgradeable: Bu kurulum ile uygulanabilir. UpgradeLevel'i silah yükselttikten sonra artan bir temel stat olarak düşünüyorum . Yükseltildiğinde, yükseltme düzeyine uyacak şekilde weapon'un BaseStat'ını yeniden hesaplayabiliriz .

Bu noktaya kadar sistemin oldukça iyi olduğunu görebiliyorum. Ancak diğer özellikler için başka bir şeye ihtiyacımız olduğunu düşünüyorum, çünkü örneğin CASEtable özelliğini BaseStat'ım olarak uygulayamıyorum . Tüm malzemeleri Stat olarak ekleyebilirim ama bu mantıklı değil.

Buna katkıda bulunmanızı kolaylaştırmak için, size yardımcı olabileceğiniz bazı sorular:

  • Diğer özellikleri uygulamak için bu kuruluma devam etmeli miyim? Kalıtım olmadan mümkün olabilir mi?
  • Tüm bu özellikleri miras olmadan uygulamak için aklınıza gelebilecek herhangi bir yol var mı?
  • Öğe Değiştiriciler hakkında, bunu nasıl başarabiliriz? Çünkü doğasında çok geneldir.
  • Bu tür bir mimariyi inşa etme sürecini kolaylaştırmak için ne yapılabilir, herhangi bir tavsiye?
  • Bu problemle ilgili olarak kazabileceğim herhangi bir kaynak var mı?
  • Gerçekten mirastan kaçınmaya çalışıyorum, ancak bunların oldukça sürdürülebilir olmasını sağlarken mirasla kolaylıkla çözüleceğini / başarılacağını düşünüyor musunuz?

Soruları çok geniş tuttuğumdan, farklı yönlerden / insanlardan bilgi alabilmem için tek bir soruyu cevaplamaktan çekinmeyin.


DÜZENLE


@ Jjimenezg93 yanıtını takiben, test için C # 'da çok temel bir sistem oluşturdum, işe yarıyor! Bir şey ekleyip ekleyemeyeceğinize bakın:

public interface IItem
{
    List<IAttribute> Components { get; set; }

    void ReceiveMessage<T>(T message);
}

public interface IAttribute
{
    IItem source { get; set; }
    void ReceiveMessage<T>(T message);
}

Şimdiye kadar, IItem ve IAttribute temel arayüzlerdir. Mesaj için temel bir arayüz / özniteliğe (düşünebileceğim) gerek yoktu, bu yüzden doğrudan bir test mesajı sınıfı yaratacağız. Şimdi test sınıfları için:


public class TestItem : IItem
{
    private List<IAttribute> _components = new List<IAttribute>();
    public List<IAttribute> Components
    {
        get
        {
            return _components;
        }

        set
        {
            _components = value;
        }
    }

    public void ReceiveMessage<T>(T message)
    {
        foreach (IAttribute attribute in Components)
        {
            attribute.ReceiveMessage(message);
        }
    }
}

public class TestAttribute : IAttribute
{
    string _infoRequiredFromMessage;

    public TestAttribute(IItem source)
    {
        _source = source;
    }

    private IItem _source;
    public IItem source
    {
        get
        {
            return _source;
        }

        set
        {
            _source = value;
        }
    }

    public void ReceiveMessage<T>(T message)
    {
        TestMessage convertedMessage = message as TestMessage;
        if (convertedMessage != null)
        {
            convertedMessage.Execute();
            _infoRequiredFromMessage = convertedMessage._particularInformationThatNeedsToBePassed;
            Debug.Log("Message passed : " + _infoRequiredFromMessage);

        }
    }
} 

public class TestMessage
{
    private string _messageString;
    private int _messageInt;
    public string _particularInformationThatNeedsToBePassed;
    public TestMessage(string messageString, int messageInt, string particularInformationThatNeedsToBePassed)
    {
        _messageString = messageString;
        _messageInt = messageInt;
        _particularInformationThatNeedsToBePassed = particularInformationThatNeedsToBePassed;
    }
    //messages should not have methods, so this is here for fun and testing.
    public void Execute()
    {
        Debug.Log("Desired Execution Method: \nThis is test message : " + _messageString + "\nThis is test int : " + _messageInt);
    }
} 

Bunlar gerekli kurulumlardır. Şimdi sistemi kullanabiliriz (Aşağıdaki Unity içindir).

public class TestManager : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {
        TestItem testItem = new TestItem();
        TestAttribute testAttribute = new TestAttribute(testItem);
        testItem.Components.Add(testAttribute);
        TestMessage testMessage = new TestMessage("my test message", 1, "VERYIMPORTANTINFO");
        testItem.ReceiveMessage(testMessage);
    }

}

Bu TestManager komut dosyasını sahnedeki bir bileşene ekleyin ve hata ayıklamada iletinin başarıyla iletildiğini görebilirsiniz.


Bir şeyleri açıklamak için: Oyundaki her öğe IItem arabirimini uygulayacak ve her Öznitelik (ad sizi karıştırmamalı, öğe özelliği / sistemi anlamına gelir. Yükseltilebilir veya sökülebilir gibi) IAttribute uygulayacaktır. Sonra mesajı işlemek için bir yöntemimiz var (neden mesaja ihtiyacımız var daha fazla örnekte açıklanacaktır). Böylece bağlamda, bir öğeye nitelikler ekleyebilir ve gerisini sizin için yapmanıza izin verebilirsiniz. Bu çok esnektir, çünkü özellikleri kolayca ekleyebilir / kaldırabilirsiniz. Yani sözde bir örnek Disenchantable olur. Disenchantable (IAttribute) adında bir sınıfa sahip olacağız ve Disenchant yönteminde bunu isteyeceğiz:

  • İçerikleri listeleyin (öğe devre dışı bırakıldığında, oyuncuya hangi öğe verilmelidir) not: Öğe, ItemType, ItemID vb.
  • int resultsModifier (hayal kırıklığı özelliğini bir çeşit artırma uygularsanız, devre dışı bırakıldığında alınan bileşenleri artırmak için buraya bir int iletebilirsiniz)
  • int başarısızlık Değişim (eğer fesat sürecinin başarısız olma şansı varsa)

vb.

Bu bilgiler DisenchantManager adlı bir sınıf tarafından sağlanacak, öğeyi alacak ve bu mesajı öğeye (devre dışı bırakıldığında öğenin bileşenleri) ve oyuncu ilerlemesine (sonuçModifier ve failChance) göre oluşturacaktır. Bu iletiyi iletmek için, bu ileti için bir gövde görevi görecek bir DisenchantMessage sınıfı oluşturacağız. Böylece DisenchantManager bir DisenchantMessage dolduracak ve öğeye gönderecektir. Öğe mesajı alır ve ekli tüm Özelliklerine iletir. Disenchantable sınıfının ReceiveMessage yöntemi bir DisenchantMessage arayacağından, bu mesajı yalnızca Disenchantable özniteliği alır ve üzerinde hareket eder. Umarım bu benim için yaptığı şeyleri temizler :).



@DMGregory Hey! Bağlantı için teşekkürler. Çok becerikli görünse de, ne yazık ki konsepti kavramak için gerçek konuşmaya ihtiyacım var. Ve maalesef GDCVault'un sadece üye içeriği olan gerçek konuşmayı bulmaya çalışıyorum (bir yıl için 495 $ deli!). (Eğer GDCVault üyeliğiniz varsa konuşmayı burada bulabilirsiniz -, -
Vandarthul

"BaseStat" konseptiniz tam olarak nasıl üretilebilir silahları engeller?
Attackfarm

Gerçekten engellemiyor ama aklımdaki içeriğe gerçekten uymuyor. "Ahşap", 2 ve "Demir", 5'i bir ustalık reçetesine BaseStat olarak eklemek, bu da kılıcı verecektir. BaseStat adını BaseAttribute olarak değiştirmenin bu bağlamda daha iyi olacağını düşünüyorum. Ama yine de, sistem amacına hizmet edemeyecek. 5dk -% 50 saldırı gücüne sahip sarf malzemesi düşünün. BaseStat olarak nasıl iletirim? "Perc_AttackPower", 50 bunun "Perc ise, tamsayıyı yüzde olarak ele al" olarak çözülmesi ve dakika bilgilerinin eksik olması gerekir. Umarım ne demek istediğimi anlarsın.
Vandarthul

@ İkinci düşünceye göre, bu "BaseStat" konsepti sadece bir int yerine ints listesi ile genişletilebilir. yani, sarf malzemesi tutkunu için, "Saldırı" sağlayabiliyorum, 50, 5, 1 ve IConsumable 3 tamsayı, 1 - değer, 2 - dakika, 3 - arayacaktı. Ancak diğer sistemler içeri girerken ve kendilerini yalnızca int.
Vandarthul

Yanıtlar:


7

Temel kalıtım ve bir mesajlaşma sistemine sahip bir Varlık Bileşen Sistemi kullanarak ölçeklenebilirlik ve sürdürülebilirlik açısından istediğinizi elde edebileceğinizi düşünüyorum. Tabii ki, bu sistemin düşünebildiğim en modüler / özelleştirilebilir / ölçeklenebilir olduğunu unutmayın, ancak muhtemelen mevcut çözümünüzden daha kötü performans gösterecektir.

Daha fazla açıklayacağım:

Her şeyden önce, bir arayüz IItemve bir arayüz oluşturursunuz IComponent. Depolamak istediğiniz herhangi bir öğe devralınmalı IItemve öğelerinizi etkilemek istediğiniz herhangi bir bileşen devralınmalıdır IComponent.

IItembileşenlerin bir dizi ve işleme için bir yöntem olacaktır IMessage. Bu işleme yöntemi, alınan tüm mesajları depolanan tüm bileşenlere gönderir. Daha sonra, bu mesajla ilgilenen bileşenler buna göre hareket edecek ve diğerleri bunu görmezden gelecektir.

Örneğin bir mesaj tip hasardır ve hem saldırganı hem de saldırıya haber verir, bu yüzden ne kadar vurduğunuzu bilirsiniz ve öfke çubuğunuzu bu hasara göre şarj edebilirsiniz. Ya da düşmanın yapay zekası size isabet ederse ve 2HP'den daha az hasar verirse koşmaya karar verebilir. Bunlar aptal örnekler ama bahsettiğim buna benzer bir sistem kullanarak, bu tür mekaniğin çoğunu eklemek için bir mesaj ve uygun işlemlerden başka bir şey yapmanız gerekmeyecek.

Burada mesajlaşma ile bir ECS için bir uygulama var , ama bu öğeler yerine varlıklar için kullanılır ve C ++ kullanır. Neyse, bir göz atın eğer yardımcı olabilir düşünüyorum component.h, entity.hve messages.h. Geliştirilecek çok şey var ama bu basit üniversite çalışmasında benim için çalıştı.

Umarım yardımcı olur.


Hey @ jjimenezg93, cevabınız için teşekkür ederim. Açıkladığınız şeyin basit bir örneğiyle ayrıntılı olarak açıklamak için: Bir kılıç istiyoruz: - Disenchantable [Component] - Stat Modifier [Component] - Upgradeable [Component] Gibi her şeyi içeren eylemler listem var - DISENCHANT - MODIFY_STAT - UPGRADE Öğe bu mesajı aldığında, tüm bileşenlerinden geçer ve bu mesajı gönderirse, her bileşen verilen mesajla ne yapılacağını bilecektir. Teorik olarak, bu harika görünüyor! Örneğini kontrol etmedim ama yapacağım, çok teşekkürler!
Vandarthul

@Vandarthul Evet, temelde fikir bu. Bu şekilde, öğe bileşenleri hakkında hiçbir şey bilmez, böylece hiçbir bağlantı yoktur ve aynı zamanda, istediğiniz farklı işlevler arasında da paylaşılabilen tüm işlevlere sahip olur. Umarım ihtiyaçlarınızı karşılar!
jjimenezg93
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.