XNA GameComponents (veya oyundaki herhangi bir türün bileşenleri) arasındaki iletişimi kolaylaştırmak için hangi tekniği kullanmalıyım?


9

İlk 'uygun' oyun projeme başlıyorum ve kaçınılmaz olarak XNA'daki oyun bileşenlerinin nasıl iletişim kurması gerektiğine karar vermeye çalışan bir bloğa çarptım.

Önceki (Java) GUI programlama olaylarından, işleyiciler ve dinleyiciler ilerlemenin yolu gibi görünüyordu. Bu yüzden olaylara abone olan olay kayıtlarını ve sınıfları kabul eden ve onlarla başa çıkmak için işleyicileri olan bir tür olay otobüsüm olurdu. Örneğin (sözde kod):

class SpriteManager
    Update(){
        if(player.collidesWith(enemy)
             // create new 'PlayerCollisionEvent'
    }

class HUDManager
    onPlayerCollisionEvent(){
        // Update the HUD (reduce lives etc)
    }

Ancak, tam olarak bunu gerçekleştirmek için gerekli olacak kod kurulum (C #) emin değilim. Olayları takip eden nedir (bir tür otobüs?) Ve nasıl yapılandırılmıştır?

Oyun Hizmetlerinde de ana Game.cs sınıfınıza bir GameComponent kaydedebilir, ardından kodunuzda ana 'Oyun' nesnesine referans olan herhangi bir yerden getirebileceğiniz çok şey var gibi görünüyor. Bu benim SpriteBatch nesnesi ile denedim ve çok kolay görünüyor .. Ancak, bu bir olay modeli kadar esnek olduğunu göremiyorum.

Örneğin bir düşman öldüğünde bunu ele alalım. Oyun skorunu güncellemek istiyoruz. Hizmetleri kullanarak Game1'de oluşturulan ve bir hizmet olarak eklenen StateManager nesnesime bir başvuru alabilir, ardından yeni değere 'skor' ayarlayabilirim. Çok sayıda sınıf tarafından farklı şekilde ele alınabilen, ancak ilgili 'düşman ölüm tespiti' bölümünde 1 kod satırı ile başlatılan bir 'onEnemyDeath' olayını düşünürdüm, her bir GameComponent'i tek tek dökmekten ve daha sonra yöntemleri gereklidir.

Yoksa bu stratejiler başka bir şeye mi daha düşük?

Bunun kısmen oyun iletişimi paradigmaları kadar benim zayıf C # bilgim olduğunu fark ettim, ama bu temel şeyi doğru yapmak istiyorum.

Güncelleme

Hizmetlere bakmak daha az ikna oldum - temelde küresel bir değişkeni (anladığım kadarıyla) geçiyor.

Güncelleme 2

Olay işleme ve örnek kod test bu temel öğretici bir göz vardı olayları tartışmak ne için mantıklı bir seçim gibi görünüyor. Ama gördüğüm örneklerde çok fazla kullanamıyorum. Birinin olmamasının açık bir nedeni var mı?


Önce FlatRedBall'ı denemenizi tavsiye ederim. XNA'nın tepesinde oturuyor ve hayatı gerçekten kolaylaştırıyor.
ashes999

3
Bir motora atlamadan önce neler olup bittiğini gerçekten anlamak istiyorum.
codinghands

Sanırım burada başarısızlık gerçekten C # hakkında bilgi eksikliği. C # genellikle sınıflar arasındaki iletişimi kolaylaştırmak için olayları kullanır. Bunu nasıl yapacağınız tamamen size bağlı - XNA bir SpriteBatch sınıfı sağlar ve işin çoğu size kalmıştır. Bir motor, ayrıntılara dalmadan önce işlerin daha yüksek bir seviyede nasıl çalıştığı hakkında sağlam bir fikir verecektir.
ashes999

1
Bir dereceye kadar katılıyorum, ancak GameComponents arasındaki sınıflar arası iletişimin çoğunu Hizmetler kullanarak yapabilirim. Olayları kullanmaya alışkınım. Hangisinin en iyisi olduğundan emin değilim veya geçerli alternatifler (
tektonlar,

Yanıtlar:


4

Önceki (Java) GUI programlama olaylarından, işleyiciler ve dinleyiciler ilerlemenin yolu gibi görünüyordu. Bu yüzden, olaylara abone olan olay kayıtlarını ve sınıfları kabul eden ve onlarla başa çıkmak için işleyicileri olan bir tür olay otobüsüm olurdu.

C # 'daki olay otobüsleri hakkında fazla bir şey bulamamanın nedeni, Java dışında hiç kimsenin benim deneyimime göre böyle bir şey' otobüs 'dediğini sanmıyorum. Daha yaygın terimler mesaj kuyruğu, etkinlik yöneticisi, sinyaller / yuvalar, yayınlama / abone olma vb. Olabilir.

Çalışan bir oyun yapmak için bunlara ihtiyacınız yoktur, ancak bu rahat olduğunuz bir sistemse, burada da size iyi hizmet edecektir. Ne yazık ki kimse size tam olarak nasıl yapılacağını söyleyemez, çünkü herkes onları kullanıyorsa, onları biraz farklı yuvarlar. (Örneğin, yapmıyorum.) System.Collections.Generic.List<Event>Çeşitli etkinlikleriniz Etkinlik'in alt sınıfları ve her etkinlik türü için bir aboneler listesi olacak şekilde sıra için bir basitle başlayabilirsiniz . Kuyruktaki her olay için abone listesini alın ve her abone için çağırın handle(this_event). Sonra kuyruktan kaldırın. Tekrar et.

Oyun Hizmetlerinde de ana Game.cs sınıfınıza bir GameComponent kaydedebilir, ardından kodunuzda ana 'Oyun' nesnesine referans olan herhangi bir yerden getirebileceğiniz çok şey var gibi görünüyor. Bu benim SpriteBatch nesnesi ile denedim ve çok kolay görünüyor .. Ancak, bu bir olay modeli kadar esnek olduğunu göremiyorum.

Muhtemelen esnek değildir, ancak hata ayıklamak daha kolaydır. Olaylar ve mesajlar zordur, çünkü çağrı fonksiyonunu çağrılan fonksiyondan ayırırlar, bu da çağrı yığınlarınızın hata ayıklamada çok yararlı olmadığı anlamına gelir, ara işlemler normalde çalışan bir şeyin kırılmasına neden olabilir, düzgün bağlanmadığında işler sessizce başarısız olabilir , ve bunun gibi. "Bir bileşeni yakala ve üzerinde ihtiyacınız olanı çağır" ın açık yöntemi, hataları erkenden yakalama ve açık ve açık kodlara sahip olma konusunda iyi çalışır. Sadece sıkı bir şekilde kodlanmış kod ve birçok karmaşık bağımlılığa yol açar.

Bunun kısmen oyun iletişimi paradigmaları kadar benim zayıf C # bilgim olduğunu fark ettim, ama bu temel şeyi doğru yapmak istiyorum.

C #, Java ile hemen hemen aynı bir dildir. Java'da ne yaparsanız yapın, sadece farklı sözdizimi ile C # 'da yapılabilir. Bir kavramı çevirmekte sorun yaşıyorsanız, bunun nedeni büyük olasılıkla yalnızca Java'ya özgü bir ad bildiğinizdir.


Teşekkürler @Kylotan. Meraktan, sınıflar arası iletişim için hangi sistemi kullanıyorsunuz - Hizmetler yaklaşımı veya başka bir şey?
codinghands

AFAIK, olay otobüsleri mesajlaşma sırası öğelerine benzer, ancak etkinlikler için.
ashes999

2
@codinghands, normalde herhangi bir resmi sınıflar arası iletişim yöntemi kullanmıyorum. Ben sadece işleri basit tutuyorum - eğer bir sınıf diğerini çağırmak gerekiyorsa, genellikle ya ikinci sınıfa üye olarak başvuruyor ya da ikinci sınıfa argüman olarak geçiyordu. Ancak bazen Unity motoruyla çalışırken, 'hizmetler' olarak adlandırdığınız şeye benzer bir yaklaşıma sahip olduğumda, ihtiyacım olan bileşeni içeren bir nesneye bakacağım, bileşene bakın daha sonra bu bileşendeki yöntemleri çağırın.
Kylotan

@ ashes999 - Mesajlar ve olaylar bu bağlamda hemen hemen aynı şey. Bir olayı bir kuyruğa, bir otobüse ya da her neyse koyarsanız, gerçekten depoladığınız şey bir olayın gerçekleştiğini gösteren bir mesajdır. Benzer şekilde bir iletiyi kuyruğa koymak, o iletiyi oluşturmak için bir olayın meydana geldiğini gösterir. Eşzamansız bir işlev çağrısına bakmak için sadece farklı yollar.
Kylotan

Üzgünüm, bunu henüz 'cevaplanmış' olarak işaretlemedim, ancak dilden bağımsız olarak her oyunun bileşenler arasında bir şekilde iletişim kurması gerektiğinden daha fazla bakış açısı olacağını düşündüm ... Ana olasılıkları ele aldık mı?
codinghands

1

Sadece basit statik olayları kullanmayı denediniz mi? Örneğin, puan sınıfınızın bir düşmanın ne zaman öldüğünü bilmesini istiyorsanız, şöyle bir şey yaparsınız:

Score.cs

class Score
{
    public int PlayerScore { get; set; }

    public Score()
    {
        EnemySpaceship.Death += new EventHandler<SpaceshipDeathEventArgs>(Spaceship_Death);
    }

    private void Spaceship_Death(object sender, SpaceshipDeathEventArgs e)
    {
        PlayerScore += e.Points;
    }
}

EnemySpaceship.cs

class EnemySpaceship
{
    public static event EventHandler<SpaceshipDeathEventArgs> Death;

    public void Kill()
    {
        OnDeath();
    }

    protected virtual void OnDeath()
    {
        if (Death != null)
        {
            Death(this, new SpaceshipDeathEventArgs(50));
        }
    }
}

SpaceshipDeathEventArgs.cs

class SpaceshipDeathEventArgs : EventArgs
{
    public int Points { get; private set; }

    internal SpaceshipDeathEventArgs(int points)
    {
        Points = points;
    }
}


0

bunun gibi olay toplayıcıyı kullanmaya çalışın


4
Bu bağlantı, yalnızca bağlantıyı sağlamak yerine öneriniz hakkında daha ayrıntılı bilgi vermeniz halinde daha iyi olur.
MichaelHouse
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.