Diş Açmadan Komut Dosyası Oluşturma ve Sinema


12

Oyun motorumda komut dizilerini nasıl uygulayacağımı düşünüyorum. Sadece birkaç gereksinimim var: Sezgisel olmalı, özel bir dil, ayrıştırıcı ve yorumlayıcı yazmak istemiyorum ve iş parçacığı kullanmak istemiyorum. (Daha basit bir çözüm olduğundan eminim; Birden fazla oyun mantığı iş parçacığının sıkıntısına ihtiyacım yok.) Python'da (aka pseudocode) örnek bir komut dosyası var:

def dramatic_scene(actors):
    alice = actors["alice"]
    bob = actors["bob"]

    alice.walk_to(bob)
    if bob.can_see(alice):
        bob.say("Hello again!")
    else:
        alice.say("Excuse me, Bob?")

Bu destansı hikaye anlatımı, uygulama sorunları yaratıyor. Tüm yöntemi bir kerede değerlendiremiyorum, çünkü walk_tooyun zamanını alıyor. Hemen geri dönerse Alice, Bob'a doğru yürümeye başlar ve (aynı çerçevede) merhaba der (ya da selamlanır). Ama walk_toBob'a ulaştığında geri dönen bir engelleme çağrısı varsa , o zaman oyunum sıkışır, çünkü Alice'i yürütebilecek aynı iş parçacığını engeller.

Her bir işlevi bir eylemi enqueue yapmayı düşündüm - alice.walk_to(bob)bir nesneyi kuyruğa iterdi, ki bu nerede olursa olsun Alice Bob'a ulaştıktan sonra patlardı. Bu daha incelikle kırıldı: ifşube hemen değerlendirildi, bu yüzden Bob sırtını ona dönse bile Alice'i selamlayabilir.

Diğer motorlar / insanlar, iş parçacığı oluşturmadan komut dosyalarını nasıl işler? Fikirler için jQuery animasyon zincirleri gibi oyun dışı alanlara bakmaya başlıyorum. Bu tür bir sorun için iyi kalıplar olması gerektiği anlaşılıyor.


1
Soru için +1, ancak özellikle "Python (aka pseudocode)" :)
Ricket

Python bir süper güce sahip olmak gibidir.
ojrac

Yanıtlar:


3

Panda gibi bir şeyin bunu yapmasının yolu geri aramalardır. Engellemek yerine böyle bir şey olurdu

def dramatic_scene(actors):
    alice = actors["alice"]
    bob = actors["bob"]

    def cb():
        if bob.can_see(alice):
            bob.say("Hello again!")
        else:
            alice.say("Excuse me, Bob?")
    alice.walk_to(bob, cb)

Tamamen geri arama yapmak, bu tür olayları istediğiniz kadar derinlemesine zincirlemenizi sağlar.

EDIT: JavaScript örneği, çünkü bu stil için daha iyi sözdizimi vardır:

function dramatic_scene(actors) {
    var alice = actors.alice;
    var bob = actors.bob;
    alice.walk_to(bob, function() {
        if(bob.can_see(alice)) {
            bob.say('Hello again!');
        } else {
            alice.say('Excuse me, Bob?');
        }
     });
}

+1 için yeterince işe yarıyor, sadece içerik tasarlamak için yanlış olduğunu düşünüyorum. Komut dosyalarının basit ve net görünmesi için sonumda biraz daha fazla iş yapmaya hazırım.
ojrac

1
@ojrac: Aslında bu şekilde daha iyi, çünkü burada aynı senaryoda birden fazla aktöre aynı anda yürümeye başlamasını söyleyebilirsiniz.
Bart van Heukelom

Ugh, iyi bir nokta.
ojrac

Ancak okunabilirliği artırmak için, geri arama tanımı walk_to () çağrısının içine yerleştirilebilir veya daha sonra çağrılacak kodun daha sonra kaynakta görünmesi için arkasından (her ikisi için de geçerlidir: dil destekleniyorsa) yerleştirilebilir.
Bart van Heukelom

Evet, Python ne yazık ki bu tür bir sözdizimi için gerçekten harika değil. JavaScript'te çok daha güzel görünüyor (yukarıya bakın, burada kod biçimlendirmesini kullanamazsınız).
coderanger

13

Burada aramak istediğiniz terim " coroutines " dir (ve genellikle dil anahtar kelimesi veya işlev adıdır yield).

Ortak programlar, belirli konumlarda yürütmeyi askıya almak ve devam ettirmek için birden fazla giriş noktasına izin vermek üzere alt yordamları genelleştiren program bileşenleridir.

Uygulama her şeyden önce sizin dilinize bağlı olacaktır. Bir oyun için uygulamanın mümkün olduğunca hafif olmasını istersiniz (iplikler ve hatta liflerden daha hafif). Wikipedia sayfasında (bağlantılı) dile özgü çeşitli uygulamalara bazı bağlantılar bulunur.

Lua'nın couteinler için yerleşik desteği olduğunu duydum. GameMonkey de öyle.

UnrealScript bunu "durumlar" ve "gizli işlevler" olarak adlandırdığı şeyle uygular.

C # kullanıyorsanız , Nick Gravelyn'in bu blog gönderisine bakabilirsiniz .

Ayrıca "animasyon zincirleri" fikri, aynı şey olmasa da, aynı soruna uygulanabilir bir çözümdür. Nick Gravelyn de bunun bir C # uygulaması var .


Nice catch, Tetrad;)
Andrew Russell

Bu gerçekten iyi, ama bana bu yolun% 100'ünü getirdiğinden emin değilim. Coroutines arama yöntemine verelim sağlar gibi görünüyor, ama bir Lua komut dosyası, (yol_to ()! = Tamamlandı) {verim} yazmadan yığın kadar C # koduna kadar yığın kadar vermesini istiyorum.
ojrac

@ojrac: Lua hakkında bilmiyorum, ancak Nick Gravelyn'in C # yöntemini kullanıyorsanız, komut dosyası yöneticinizin kontrol etmesi için koşulu tutan bir temsilci (veya bir nesne) döndürebilirsiniz (Nick'in kodu sadece bir zaman döndürür bu da bir koşullu şarttır). Hatta gizli işlevlerin kendilerinin delege döndürmesini sağlayabilirsiniz, böylece yield return walk_to();senaryonuza şunu yazabilirsiniz:
Andrew Russell

C # 'da verim harika, ama basit, karmaşıklığı zor komut dosyaları için çözümümü optimize ediyorum. Geri aramaları açıklamaktan daha kolay bir zaman ayıracağım, bu yüzden diğer cevabı kabul edeceğim. Yapabilirsem +2 olurdu.
ojrac

1
Normalde verim çağrısını açıklamak zorunda değilsiniz - örneğin "walk_to" işlevinde bunu sarabilirsiniz.
Kylotan

3

dişli geçmemek akıllıdır.

Çoğu oyun motoru, bir dizi modüler aşama olarak çalışır ve her aşamada hafızada bulunan şeyler vardır. 'Örneğe yürüyün' için genellikle yürüdüğünüz karakterlerin öldürülecek düşmanları aramamaları gereken bir AI aşamasına, X animasyonunu çalıştırmaları gereken bir animasyon aşamasına, bir fizik aşamasına (veya simülasyon aşaması) gerçek konumlarının güncellendiği vb.

Yukarıdaki örneğinizde, 'alice' bu aşamaların çoğunda yaşayan parçalardan oluşan bir aktördür, bu nedenle, engelleme aktörü.walk_to (veya çerçeve başına bir kez () (sonra) aradığınız bir cohoutine) muhtemelen uygun içeriğe sahip olmaz kararlar vermek.

Bunun yerine, bir 'start_walk_to' işlevi muhtemelen şöyle bir şey yapar:

def start_cutscene_walk_to(actor,target):
    actor.ai.setbrain(cutscene_brain)
    actor.physics.nocoll = 1
    actor.anims.force_anim('walk')
    # etc.

Ardından, ana döngünüz AI işaretini, fizik işaretini, animasyon işaretini ve cutscene işaretini çalıştırır ve cutscene, motorunuzdaki alt sistemlerin her birinin durumunu günceller. Cutscene sistemi, cutscenlerinin her birinin ne yaptığını kesinlikle izlemelidir ve custscene gibi doğrusal ve deterministik bir şey için koroutin tahrikli bir sistem mantıklı olabilir.

Bu modülerliğin nedeni, şeyleri güzel ve basit tutması ve bazı sistemler için (fizik ve AI gibi), işleri düzgün bir şekilde çözmek ve oyunu tutarlı bir durumda tutmak için her şeyin durumunu aynı anda bilmeniz gerekir. .

Bu yardımcı olur umarım!


Ben ne için gibi, ama aslında actor.walk_to ([başka bir aktör, sabit bir pozisyon, hatta bir pozisyon döndüren bir işlev] değeri hakkında güçlü hissediyorum. Amacım basit, anlaşılır araçlar sağlamak ve oyunun içerik oluşturma bölümünden tüm karmaşıklığı ortadan kaldırmak. Ayrıca, gerçekten tüm istediğim her komut dosyasına sonlu durum makinesi olarak davranmanın bir yolu olduğunu anlamama yardımcı oldunuz.
ojrac

yardımcı olduğuma sevindim! Cevabımın biraz konu dışı olduğunu hissettim :) Kesinlikle hedeflerinize ulaşmak için bir actor.walk_to işlevinin değeri ile katılıyorum, uygulamanızı duymayı dört gözle bekliyorum.
Aaron Brady

Görünüşe göre jQuery tarzı geri aramalar ve zincirleme fonksiyonlar karışımı ile gideceğim. Kabul edilen cevaba bakınız;)
ojrac
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.