Bir varlık sisteminde özellikleri nasıl uygularım?


31

Varlık sistemleri hakkında iki soru sorduktan ( 1 , 2 ) ve bunlarla ilgili bazı makaleleri okuduktan sonra, onları öncekinden daha iyi anladığımı düşünüyorum. Hala bir parçacık yayıcı, bir giriş sistemi ve bir kamera oluşturmak konusunda hala bazı belirsizliklerim var. Açıkçası, varlık sistemlerini anlamada hala bazı problemlerim var ve bunlar diğer tüm nesneler için geçerli olabilir, ancak bu üçünü seçtim çünkü bunlar çok farklı kavramlar, oldukça geniş bir temeli kapsamalı ve varlık sistemlerini ve nasıl anlamayı anlamama yardım etmeli Bu gibi problemleri kendim hallederken halledebiliriz.

JavaScript'te bir motor yapıyorum ve aşağıdakileri içeren temel özelliklerin çoğunu uyguladım: giriş işleme, esnek animasyon sistemi, parçacık yayıcı, matematik sınıfları ve işlevleri, sahne kullanımı, kamera ve görüntü oluşturma ve bir sürü ürün motorların genellikle desteklediği şeylerden. Byte56'nin cevabını okudum, bu da motoru bir varlık sistemine dönüştürmekle ilgilendi. Temel sahne felsefesiyle hala bir HTML5 oyun motoru olarak kalacaktı, ancak bileşenlerden dinamik varlık yaratmayı desteklemesi gerekiyor.


Şu andaki sorun, eski motor konseptimi bu yeni programlama paradigmasına sığdırmak. Bunlar önceki soruların tanımlarından bazıları, güncellenmiş:

  • Bir varlık bir tanımlayıcıdır. Herhangi bir veriye sahip değil, bir nesne değil, tüm varlıkların sahneler listesindeki bir dizini temsil eden basit bir kimlik (aslında bir bileşen matrisi olarak uygulamayı planlıyorum).

  • Bir Bileşen bir veri taşıyıcısıdır, ancak bu veriler üzerinde çalışabilen yöntemlerle. En iyi örnek bir Vector2Dveya "Konum" bileşenidir. Bu veriler içeriyor: xve y, ama biraz daha kolay veri üzerinde işlem yapmak da bazı yöntemleri: add(), normalize(), vb.

  • Bir Sistem belirli gereksinimleri karşılaması varlıklar kümesi üzerinde işlem bir şeydir; genellikle işletmelerin çalıştırılmak üzere belirli bir bileşen setine sahip olmaları gerekir. Sistem "mantık" kısmı, "algoritma" kısmıdır, bileşenlerin sağladığı tüm işlevler tamamen kolay veri yönetimi içindir.


Kamera

Kamera bir Vector2Dkonum özelliğine, bir dönüş özelliğine ve onu bir nokta etrafında ortalamak için bazı yöntemlere sahiptir. Her kare, bir sahneyle birlikte bir işleyiciye beslenir ve tüm nesneler konumuna göre çevrilir. Sahne daha sonra oluşturulur.

Bir varlık sisteminde bu tür bir nesneyi nasıl temsil edebilirim? Kamera bir varlık mı, bir bileşen mi, yoksa kombinasyon olur mu ( cevabım gereğince )?

Parçacık Verici

Parçacık vericimde yaşadığım sorun, yine ne olması gerektiğidir. 10.000'den fazla kişiyi desteklemek istediğim için parçacıkların kendilerinin varlık olmaması gerektiğinden oldukça eminim ve bu kadar fazla varlık yaratmanın performansım üzerinde büyük bir darbe olacağına inanıyorum.

Bir varlık sisteminde bu tür bir nesneyi nasıl temsil edebilirim?

Giriş Yöneticisi

En son konuşmak istediğim, girdilerin nasıl kullanılması gerektiği. Motorun şu anki versiyonunda, denilen bir sınıf var Input. Tuşlara basma ve fare konumu değişikliği gibi tarayıcı olaylarına abone olan ve aynı zamanda bir iç durumu koruyan bir işleyicidir. Ardından, oyuncu sınıfı react()bir giriş nesnesini argüman olarak kabul eden bir yönteme sahiptir . Bunun avantajı, giriş nesnesinin .JSON'a serileştirilebilmesi ve daha sonra ağ üzerinden paylaşılarak düzgün çok oyunculu simülasyonlara izin vermesidir.

Bu nasıl bir varlık sistemine dönüşüyor?

Yanıtlar:


26
  • Kamera: Bunu bir bileşen yapmak oldukça zarif olurdu. Sadece bir olurduisRenderingSean'ın dediği gibi bayrak ve derinlik aralığı. "Görüş alanı" ek olarak (2 boyutlu? Ölçek? Diyebilirim sanırım) ve bir çıkış bölgesi. Çıkış bölgesi, oyun penceresinin bu kameranın oluşturulduğu kısmını tanımlayabilir. Bahsettiğiniz gibi ayrı bir pozisyon / rotasyon olmazdı. Bir kamera bileşenine sahip yarattığınız varlık, o varlığın konum ve döndürme bileşenlerini kullanır. Ardından, kamera, konum ve döndürme bileşenleri olan varlıkları arayan bir kamera sisteminiz olur. Sistem, bu varlığı alır ve "görebileceği" tüm varlıkları konumundan, rotasyonundan, görüş derinliğinden ve görüş alanından ekranın belirtilen kısmına çeker. Bu size çoklu görünüm portları, "karakter görünümü" pencereleri, yerel çoklu oyuncu,

  • Parçacık Verici: Bu da sadece bir bileşen olmalıdır. Parçacık sistemi, konumu, dönüşü ve parçacık yayıcı olan varlıkları arar. Verici, geçerli vericinizi çoğaltmak için gereken tüm özelliklere sahiptir, tüm bunların ne olduğundan emin değilim: oran, başlangıç ​​hızı, bozulma süresi vb. Birden çok geçiş yapmak zorunda kalmazsınız. Parçacık sistemi, hangi varlıkların bu bileşene sahip olduğunu bilir. Mevcut kodunuzun çok daha fazlasını tekrar kullanabileceğinizi hayal ediyorum.

  • Girdiler: Bunu bir bileşenin içine sokmak gerektiğini söylemek zorundayım, yukarıda verdiğim öneriler doğrultusunda en mantıklı olanı. Sizininput systemGeçerli giriş olaylarıyla her kareyi güncelleyecektim. Sonra girdi bileşenine sahip olan bütün varlıklardan geçerken, bu olayları uygular. Giriş bileşeni, tüm ilişkili yöntem geri aramaları bir klavye ve fare olayları listesine sahip olacaktır. Geri çağırma yönteminin nerede yaşayacağından emin değilim. Belki bazı giriş denetleyici sınıfı? Motor kullanıcıları tarafından daha sonra değiştirilmek için en anlamlı olan şey ne? Ancak bu, giriş kontrolünü kamera varlıklarına, oyuncu varlıklarına veya ihtiyacınız olan her şeye kolayca uygulama gücü verir. Bir grup varlığın hareketini klavye ile senkronize etmek mi istiyorsunuz? Onlara sadece aynı girişlere cevap veren tüm giriş bileşenlerini verin ve giriş sistemi bu taşıma olaylarını isteyen tüm bileşenlere uygular.

Bu yüzden çoğu sadece kafamın üstünde, bu yüzden daha fazla açıklama yapmadan bir anlam ifade etmiyor. Sadece bana neyin açık olmadığını bilmeme izin ver. Temel olarak, üzerinde çalışacağınız çok şey verdim :)


Başka bir harika cevap! Teşekkürler! Şimdi tek sorunum varlıkları hızlı bir şekilde depolamak ve geri almak, böylece kullanıcı aslında bir oyun döngüsü / mantığı uygulayabiliyor ... Bunu kendi başıma çözmeye çalışacağım ama öncelikle Javascript'in diziler, nesneler ve nesnelerle nasıl ilgilendiğini öğrenmeliyim. iyi bir tahminde bulunmak için bellekteki tanımsız değerler ... Bu bir sorun olacaktır çünkü farklı tarayıcılar farklı uygulayabilir.
jcora

Bu mimari olarak saf hissediyor ancak görüntü oluşturma sistemi aktif kamerayı tüm varlıklar arasında yineleme yapmaktan nasıl kaçındı?
Pace

@Pace Aktif kameranın çok hızlı bir şekilde bulunmasını istediğimden, kamera sisteminin aktif bir kameraya sahip olan varlıklara referans vermesine izin vereceğim.
MichaelHouse

Birden fazla kamerayı kontrol etmek için mantığı nereye koyarsınız (bak, döndür, taşı vb.)? Birden fazla kamerayı nasıl kontrol ediyorsunuz?
plasmacel

@plasmacel Denetimleri paylaşan birden fazla nesneniz varsa, hangi nesnenin girdileri alacağını belirlemek sizin kontrol sisteminizin sorumluluğunda olacaktır.
MichaelHouse

13

İşte buna nasıl yaklaştığım:

Kamera

Kameram, diğerlerine benzeyen, eklenmiş bileşenleri olan bir varlıktır:

  1. Transformyer alır Translation, Rotationve Scalehız, vs., diğerleri yanında, özellikleri

  2. Pov(Bakış açısı) olmuştur FieldOfView, AspectRatio, Near, Far, ve başka bir şey bir ek olarak, bir çıkıntı matrisi üretmek için gerekli olan IsOrthoperspektif ve ortografik çıkıntılar arasında geçiş yapmak için kullanılan bir bayrak. Povayrıca, ProjectionMatrixokuma sırasında dahili olarak hesaplanan ve diğer özelliklerin herhangi biri değiştirilinceye kadar önbelleklenen oluşturma sistemi tarafından kullanılan tembel bir yükleme özelliği sağlar.

Özel bir kamera sistemi yok. Render Sistemi bir listesini tutar Povve oluştururken hangisinin kullanılacağını belirlemek için bir mantık içerir.

Giriş

Bir InputReceiverbileşen herhangi bir işletmeye eklenebilir. Bu, mevcut ve önceki anahtar durumu, geçerli ve önceki fare konumu ve düğme durumu vb. İçin parametreleri alan, varlığa özgü giriş işlemlerini tutmak için kullanılan, eklenmiş bir olay işleyicisine (ya da diliniz destekliyorsa lambda) sahiptir (Aslında, fare ve klavye için ayrı işleyiciler var).

Örneğin, Varlık / Bileşene alışırken yarattığım Asteroid benzeri bir test oyununda, iki giriş lambda yöntemim var. Biri ok tuşlarını ve boşluk çubuğunu (ateşleme için) işleyerek gemi navigasyonunu yönetir. Diğerleri genel klavye girişini idare eder - çıkış, duraklat, vb., Yeniden başlatma seviyesi, vb. İçin tuşlar. İki bileşen oluşturur, her lambda'yı kendi bileşenine ekler, sonra navigasyon alıcısı bileşenini gemi varlığına, diğerini bir diğerine atar. görünmeyen komut işlemcisi varlığı.

İşte geminin InputReceiverbileşenine (C #) takılan çerçeveler arasında tutulan anahtarları işlemek için olay işleyicisi :

  void ship_input_Hold(object sender, InputEventArgs args)
    {
        var k = args.Keys;
        var e = args.Entity;

        var dt = (float)args.GameTime.ElapsedGameTime.TotalSeconds;

        var verlet = e.As<VerletMotion>();
        var transform = e.As<Transform>();

        if (verlet != null)
        {

        /// calculate applied force 
            var force = Vector3.Zero;
            var forward = transform.RotationMatrix.Up * Settings.ShipSpeedMax;

            if (k.Contains(Keys.W))
                force += forward;

            if (k.Contains(Keys.S))
                force -= forward;

            verlet.Force += force * dt;
        }

        if (transform != null)
        {
            var theta = Vector3.Zero;

            if (k.Contains(Keys.A))
                theta.Z += Settings.TurnRate;

            if (k.Contains(Keys.D))
                theta.Z -= Settings.TurnRate;

            transform.Rotation += theta * dt;
        }

        if (k.Contains(Keys.Space))
        {
            var time = (float)args.GameTime.TotalGameTime.TotalSeconds - _rapidFireLast;

            if (time >= _rapidFireDelay)
            {
                Fire();
                _rapidFireLast = (float)args.GameTime.TotalGameTime.TotalSeconds;
            }
        }
    }

Kameranız mobil ise, ona kendi bileşenini InputReceiverve Transformbileşenini verin, istediğiniz kontrolü uygulayan bir lambda veya taşıyıcı kullanın ve işlemi bitirin.

InputReceiverBileşeni gemiden bir asteroide veya navigasyon işleyicisine takılıyken taşıyabileceğiniz ve bunun için başka herhangi bir şeyi taşıyabileceğiniz için bu oldukça zarif . Veya Povsahnenizdeki herhangi bir şeye bir bileşen atayarak (bir asteroit, sokak lambası vb.) Sahnenizi o varlığın perspektifinden görüntüleyebilirsiniz.

Bir InputSystemklavye, fare için bir iç durumunu korur sınıf, vb InputSystembir olan birimler için iç varlık koleksiyonunu filtreler InputReceiverbileşeni. Bu Update()yöntemde, bu koleksiyon boyunca yinelenir ve bu bileşenlerin her birine eklenmiş giriş işleyicilerini, oluşturma sisteminin her öğeyi bir Renderablebileşenle çizdiği şekilde çağırır .

Parçacıklar

Bu gerçekten parçacıklarla nasıl etkileşime geçmeyi planladığınıza bağlıdır. Sadece tek bir nesne gibi davranan bir parçacık sistemine ihtiyacınız varsa - örneğin, bir havai fişek oyuncunun dokunamayacağını ya da vuramayacağını gösteriyor - o zaman tek bir varlık ve ParticleRenderGroupparçacıklar için gereken bilgileri içeren bir bileşen yaratacağım. çürüme, vb. - Renderablebileşeniniz tarafından karşılanmayan . Oluşturma sırasında, oluşturma sistemi bir işletmenin RenderParticleGroupekli olup olmadığını görecek ve buna göre işlem yapacak .

Çarpışma algılamaya katılmak, girdilere cevap vermek, vb. İçin ayrı parçacıklara ihtiyacınız varsa, ancak bunları bir toplu iş olarak oluşturmak istiyorsanız Particle, bu bilgileri parçacık başına bazda içeren bir bileşen oluşturur ve ayrı varlıklar Render sistemi hala onları topluyor, fakat diğer sistemler tarafından ayrı nesneler olarak ele alınacaklar. (Bu örnekleme ile çok iyi çalışır.)

Ardından, sizin MotionSystem(veya güncelleme varlık pozisyonunu idare eden işleri ne şekilde kullanırsanız yapın) veya özel olarak ParticleSystem, her bir partikül için her bir partikül için gereken işlemleri yapın. Bu RenderSystem, parçacık koleksiyonlarını oluşturulduklarında ve yok edildiklerinde oluşturma / harmanlama ve önbelleklemekten ve gerektiğinde bunları sağlamaktan sorumlu olacaktır.

Bu yaklaşımla ilgili güzel bir şey, çarpışma, çarpma vb. İçin parçacıklar için özel durumlara sahip olmanız gerekmemesidir; Her türlü varlık için yazdığınız kodlar hala kullanılabilir.

Sonuç

Eğer platformlar arası geçmeyi düşünüyorsanız - JavaScript'e süper uygun değil - platformunuza özel kodunuzun tamamı (yani, oluşturma ve giriş) iki sistemde izole edilmiştir. Oyun mantığınız platform-agnositik sınıflarda kalır (hareket, çarpışma vb.) Bu yüzden taşıma sırasında bunlara dokunmamanız gerekir.

Uygulamanızın ihtiyaçlarını doldurmak için kalıbı ayarlamaktan ziyade kalıba sıkı sıkıya bağlı kalmak için kalıba bürünen şeylerin bir kalıba girdiğini kabul ediyorum. Giriş, Kamera veya Parçacıklarda bu tür bir tedavi gerektiren herhangi bir şey görmüyorum.


Birden fazla kamerayı kontrol etmek için mantığı nereye koyarsınız (bak, döndür, taşı vb.)?
plasmacel

7

Giriş ve oyun mantığı büyük olasılıkla varlık bileşen sistemi dışındaki özel bir kod ögesinde ele alınacaktır. Tasarıma sokmak teknik olarak mümkün, ancak çok az yararı var - oyun mantığı ve kullanıcı arayüzü ne yapıyor olursanız olun sahte ve sızdıran soyutlamalarla dolu ve kare pimi yuvarlak bir deliğe zorlamak sadece mimari saflık için Zamanın

Aynı şekilde, partikül vericiler, özellikle de performansı önemsiyorsanız, özel canavarlardır. Bir verici bileşeni anlamlıdır, ancak grafikler, bu bileşenlerle özel bir sihir yapacak, renderin geri kalanı için sihirle karıştırılacak.

Kameranıza gelince, kameralara yalnızca aktif bir bayrak ve belki de "derinlik" endeksi verin ve grafik sisteminin etkinleştirilen hepsini oluşturmasına izin verin. Bu aslında GUI'ler dahil birçok püf noktası için kullanışlıdır (GUI'nizin oyun dünyasının üzerinde ortografik modda yapılmasını ister misiniz? Sorun değil, onlar sadece farklı nesne maskeleri ve GUI'nin daha yüksek bir katmana ayarlanmış iki kamerası). Özel efekt katmanları vb. İçin de yararlıdır.


4

Kamera bir varlık mı yoksa sadece bir bileşen mi?

Bu sorunun ne sorduğundan emin değilim. Oyunda sahip olduğun tek şey varlıklar olduğu için, kameraların varlık olması gerekiyor. Kamera işlevi, bir çeşit kamera bileşeni aracılığıyla gerçekleştirilir. Ayrı "Konum" ve "Döndürme" bileşenlerine sahip değilsiniz - bu çok düşük seviyedir. Dünyadaki herhangi bir işletmeye uygulanacak bir tür WorldPosition bileşeni ile birleştirilmelidirler. Hangisini kullanacağınıza gelince ... bir şekilde sisteme mantık kazandırmalısınız. Ya kamera kullanım sisteminize kodlarsınız ya da scriptler ya da başka bir şey eklersiniz. Yardım ederse, bir kamera bileşeninde etkin / devre dışı bayrak olabilir.

Parçacıkların kendilerinin varlık olmaması gerektiğine oldukça eminim

Ben de. Bir parçacık yayıcı bir varlık olacaktır ve parçacık sistemi verilen bir varlık ile ilişkili parçacıkları izleyecektir. Bunun gibi şeyler “her şey bir varlıktır” anlamsız pratiktir. Uygulamada, varlıklar olan tek şey, bileşenlerin kombinasyonlarından faydalanan nispeten karmaşık nesnelerdir.

Giriş gelince: giriş, oyun dünyasında böyle olmaz, bu nedenle bir sistem tarafından yönetilir. Mutlaka bir 'bileşen sistemi' değil, çünkü oyununuzdaki her şey bileşenlerin etrafında dönmeyecek. Ancak bir giriş sistemi olacak. Bir tür Player bileşeniyle girişe yanıt veren varlığı işaretlemek isteyebilirsiniz, ancak giriş karmaşık ve tamamen oyuna özgü olacak, bu yüzden bunun için bileşen yapmaya çalışan çok az nokta var.


1

İşte bu sorunları çözme konusundaki fikirlerimden bazıları. Muhtemelen onlarla ilgili yanlış bir şeyleri olacak ve muhtemelen daha iyi bir yaklaşım olacaktır, bu yüzden lütfen beni cevabınıza yönlendirin!

Kamera :

Herhangi bir varlığa eklenebilecek bir "Kamera" bileşeni vardır. Ne var ki, bu bileşene hangi verileri koyacağımı gerçekten bilemiyorum, ancak: "Konum" ve "Döndürme" bileşenlerini ayrı tutabilirim! followZaten bağlı olduğu varlık takip ediyor, çünkü yöntem, uygulanması gereken değil! Ve dolaşmak için özgürüm. Bu sistemle ilgili sorun birçok farklı kamera nesnesi olacaktır: RendererSystemHangisinin kullanılacağını nasıl bilebilirim? Ve ayrıca, sadece kamera nesnesini dolaştırırdım, ama şimdi RendererSystemtüm varlıkların iki kez tekrarlanması gerekecek gibi görünüyor : ilk önce kameralar gibi hareket edenleri bulmak ve ikincisi de her şeyi yapmak.

ParticleEmitter :

ParticleSystemBir "Verici" bileşeni olan tüm varlıkları güncelleyen bir tane olacaktı. Parçacıklar, o bileşenin içinde, göreceli bir koordinat alanındaki aptal nesnelerdir. Burada görüntü oluşturma sorunu var: Bir ParticleRenderersistem yapmam veya mevcut sistemin işlevselliğini genişletmem gerekiyor .

Giriş sistemi :

Buradaki benim için asıl kaygı, mantık ya da react()yöntemdi. Karşılaştığım tek çözüm bunun için ayrı bir sistem ve hangisinin kullanılacağını belirten her bir sistem için bir bileşen. Bu gerçekten çok tehlikeli görünüyor ve bununla nasıl başa çıkacağımı bilmiyorum. Bir şey, endişelendiğim sürece, Inputsınıf olarak uygulanmaya devam edebildiğim, ancak bunu oyunun geri kalanına nasıl entegre edebileceğimi göremiyorum.


RendererSystem'in tüm varlıklar üzerinde yinelenmesi için bir neden yoktur - çekmeceler listesi (ve kameralar ve ışıklar (ışıklar çekilebilir olmadığı sürece)) veya bu listelerin nerede olduğunu bilmelidir. Ayrıca, oluşturmak istediğiniz kameralar için culling yapmak isteyeceksinizdir, bu yüzden belki de kameranızda görülebilen çekilebilir varlık kimlikleri listesi bulunabilir. Her ikisi de senaryolar ve tetikleyiciler ve girişler gibi herhangi bir şey tarafından kontrol edilebilecek, farklı POV'lere bağlanmış birçok kamera ve bir tane aktif kamera veya bir tane kameranız olabilir

@ melak47, bu doğru, ben de düşündüm ama Aremis'in yaptığı gibi uygulamak istedim. Ancak bu "sistemlerin ilgili kurumlara referanslar göndermesi" giderek daha kusurlu görünüyor ...
jcora

Artemis her bir Bileşen tipini kendi listesinde saklamıyor mu? bu yüzden tam olarak çizilebilir bileşenlerin, kamera bileşenlerinin, ışıkların listesine sahip değil miydiniz?
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.