Plattformer Oluşturma - Bir oyuncunun atlamasına izin verilip verilmediği nasıl belirlenir?


16

Basit bir Plattformer Jump n 'Run Style oyunu yapıyorum. Fayans kullanmıyorum - bunun yerine seviye varlıkları için geometrik şekillerim var (ve oyuncu da bir tane). Çarpışma algılama kodumu bitirdim ve şimdiye kadar her şey iyi çalışıyor.

Sonra, atlamayı uygulamak istedim. Sadece oynatıcının uygun tuşa çarpıp çarpmadığını kontrol edin ve biraz yukarı doğru hız ekleyin. İyi çalışıyor. Ama oyuncu havada olsa bile çalışıyor, bu benim istediğim şey değil. ;-)

Yani, oyuncunun bir şey üzerinde durup durmadığını kontrol etmeliyim. İlk fikrim, son karede bir çarpışma olup olmadığını kontrol etmek ve oyuncuyu "zıplayabiliyor" olarak işaretlemekti, ancak oyuncu havadaki bir duvara çarptığında bile tetikleyecekti. Matematik becerilerim o kadar iyi olmadığından, yardım istiyorum - ipucu bile bunu nasıl uygulayacağını.

Teşekkürler!

Yanıtlar:


14

Akla gelen iki seçenek:

  • İlk düşünce geometriyi bir ID ile etiketlemek ve ardından çarpışmanın zemin olarak etiketlenmiş geometri ile olup olmadığını kontrol etmektir. Bu, atlanabilir yüzeylerin en iyi kontrolünü sağlar, ancak seviye oluşturma süresinde bir maliyetle.
  • İkincisi, çarpışmanın normalini kontrol etmektir, eğer yukarı dönükse atlamaya izin verin. Ya da bazı kenar boşluklarında, eğimli zeminlerinize bağlı olarak değişir. Bu esnektir ve herhangi bir etiketleme gerektirmez, ancak zemin ve duvarları eğimliyseniz, istemediğiniz yere biraz atlayabilirsiniz.

Normal kontrol benim için harika bir fikir gibi görünüyor. Bunu gönderdiğiniz için teşekkürler.
Christopher Horenstein

Normal kontrol için +1. Bu, bir zeminin herhangi bir soruna neden olmadan sorunsuz bir şekilde duvara geçmesini sağlar.
Soviut

1
+1 Kesinlikle çarpışmayı kontrol edin - normal. Farklı dünya geometrisi türlerine sahip olmak iyidir ve daha esnek bir tasarıma izin verir, ancak birincil sorunu çözmez. Bir "duvar", içine koşturmanıza veya üzerinde durmanıza bağlı olarak "toprak" türünde de olabilir. Çarpışma-normal bu noktada yardımcı olacaktır.
bummzack

Normal çözümü çok güzel buluyorum ve sorunumu çözeceğim. Diğer yüksek puanlı cevap bile güzel ve böyle - ama bu sorumu daha iyi cevaplıyor. Wkerslake'inize teşekkürler!
Malax

8

Kesinlikle bir tür yüzey tipi uygulamalısınız. Bir düşünün, karakterinizin bir duvara mı yoksa bir merdiveni çarpıp çarpmadığını bilmiyorsanız bir merdivene tırmanıp tırmanamayacağınızı nasıl başaracaksınız? Sadece miras kullanarak bir tür hiyerarşisini yönetmek için OOP kullanabilirsiniz, ancak numaralandırılmış bir tür kullanılarak uygulanan "kategoriler" kullanmanızı öneririz:

İşte fikir: Bir "Çarpışma" numaralandırmasının her kategori için bir bayrağı vardır. Örneğin:

namespace Collisions
{
    enum Type
    {
        None   = 0,
        Floor  = 1 << 0,
        Ladder = 1 << 1,
        Enemy  = 1 << 2,
        ... // And whatever else you need.

        // Then, you can construct named groups of flags.
        Player = Floor | Ladder | Enemy
    };
}

Bu yöntemle, oyuncunun juste'ın yönetmeniz gereken herhangi bir şeyi çarpıştırıp çarpmadığını test edebileceksiniz, böylece motorunuz varlığın "Çarpışma" Yöntemi'ni çağırabilir:

void Player::Collided( Collisions::Type group )
{
   if ( group & Collisions::Ladder )
   {
      // Manage Ladder Collision
   }
   if ( group & Collisions::Floor )
   {
      // Manage Floor Collision
   }
   if ( group & Collisions::Enemy )
   {
      // Manage Enemy Collision
   }
}

Yöntem, her bir grubun kategorinin ikili değerine göre farklı bir değere sahip olmasını sağlamak için bitsel bayraklar ve bitsel "Or" operatörünü kullanır. Bu yöntem iyi çalışır ve kolayca ölçeklenebilir, böylece gümrük çarpışma grupları oluşturabilirsiniz. Oyununuzdaki her Varlığın (Oyuncu, Düşman vb.) "Filtre" adı verilen bazı bitleri vardır ve bunlar neyle çarpışabileceğini belirlemek için kullanılır. Çarpışma kodunuz, bitlerin buna uygun olarak eşleşip tepki vermediğini kontrol etmelidir;

void PhysicEngine::OnCollision(...)
{
    mPhysics.AddContact( body1, body1.GetFilter(), body2, body2.GetFilter() );
}

Enum yerine const ints kullanmak için bir neden var mı? Tek bir bayrağın veya adlandırılmış grubun dejenere durumunda numaralandırılmış tür daha okunabilir ve çoğu derleyicide ek tür denetleme yeteneği elde edersiniz.

Evet, enum (sanırım) yeni özel gruplar oluşturmak için ikili işleçleri kullanamaz. Bu const yapmamın nedeni, okunabilirlik nedenleriyle config parametrelerinin güvenliğini koruyarak genel statik üyelerle bir Config sınıfı kullanmamdır.
Frédérick Imbeault

Bu olabilir. Numaralandırma "rvalues" diğer sabit değerler üzerinde bitsel işlemler olabilir (Ben aslında herhangi bir sabit ifade olabilir, ama standart kontrol etmek için çok tembel düşünüyorum). Statik olmayan değerler örneğinizle tam olarak aynı şekilde elde edilir, ancak daha doğru bir şekilde yazılır. "Güvenlik" ile ne demek istediğiniz hakkında hiçbir fikrim yok, ama bir sınıfla ilişkili ek yük olmadan tam olarak aynı sözdizimi bir ad alanı ile elde edilebilir.

Numaralandırılmış bir tür kullanmak için kod örneklerinizi güncelledim.

Belki de düşünmeleri okumayı kolaylaştırır. Yaptığınız değişiklikleri onaylıyorum, kullandığım yöntem doğruydu ama açıklama kodunu ayarlamamıştım, düzeltmeler için teşekkür ederim. Ad alanı için oldukça haklısınız, ancak bu tüm diller için geçerli değil (örnek için komut dilleri). "Güvenlik" benim yapılandırma seçenekleri statik yani değiştirilemez ama bir numaralandırma kullanarak da bunu önlemek.
Frédérick Imbeault

1

Karakterinizin ayağını karakterin altında belirli bir mesafe kadar düşünürseniz ve yüzeyden uzaklaşmazsanız, karakteriniz yerdedir.

Kaba sahte kodda:

bool isOnGround(Character& chr)
{
   // down vector is opposite from your characters current up vector.
   // if you want to support wall jumps, animate the vecToFoot as appropriate.
   vec vecToFoot = -chr.up * chr.footDistanceFromCentre;

// if feet are moving away from any surface, can't be on the ground if (dot(chr.velocity, down) < 0.0f) return false;

// generate line from character centre to the foot position vec linePos0 = chr.position; vec linePos1 = chr.position + vecToFoot;

// test line against world. If it returns a hit surface, we're on the ground if (testLineAgainstWorld(line0, line1, &surface) return true;

return false; }


Bence çift atlama veya duvar atlama gibi özellikler eklemek istiyorsanız işe yaramaz?
Frédérick Imbeault

OP'nin çift sıçramalardan veya duvar sıçramalarından bahsettiğine inanmıyorum, değil mi?
jpaver

Vektörü karakter merkezinden ayağınıza nasıl soyutlayacağınızı göstermek için kodu revize ettim. Bunu canlandırırsanız ve ayaklar yanlara doğru ilerler ve bir duvara çarparsanız, duvar sıçramasını destekleyebilirsiniz.
jpaver

Bu, normalde çarpışmayı kontrol etmenin daha az esnek bir yoludur. (Daha az esnek çünkü bir duvar zıplamasını bir tavan zıplamasından tavan zıplamasından sadece normalin yönünü kontrol ederek ayırt edebilirsiniz.)

2
Asla bir değişkeni çağırmayın char, sahte kodda bile.
sağda
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.