Lua oyunlarda kodlama dili olarak nasıl çalışır?


67

Tam olarak Lua'nın ne olduğu ve C ++ 'da programlanan bir oyunun onu nasıl kullanacağı konusunda biraz endişeliyim. Öncelikle nasıl derlenip çalıştırıldığını soruyorum.

Örneğin, Lua betiklerini kullanan C ++ ile yazılmış bir program kullandığınızda: Lua'daki kod yalnızca C ++ ile yazılmış ana programdaki işlevleri çağırıyor ve derlenip C ++ 'nın bellek yığınına eklenmeyi bekleyen derlenmemiş bir sınıf gibi davranıyor mu? Program?

Yoksa Linux'ta ana programdan tamamen ayrı programlar yürüten bir bash betiği gibi mi davranıyor?

Yanıtlar:


90

Komut dosyası, (kavramsal olarak) başka bir programın (ana bilgisayarın) içinde çalışan bir programın (komut dosyasının) bulunduğu bir programlama özetidir. Çoğu durumda, komut dosyasını yazdığınız dil, sunucunun yazıldığı dilden farklıdır, ancak programın içindeki bir programın soyutlanması komut dosyası olarak kabul edilebilir.

Kavramsal olarak, komut dosyasını etkinleştirmek için ortak adımlar şunlardır (ana bilgisayar için pseudo-c ve komut dosyası için pseudo-lua kullanacağım. Bunlar tam adımlar değil, daha çok komut dosyasını etkinleştirdiğiniz genel akış gibi)

  1. Ana bilgisayar programında sanal bir makine oluşturun:

    VM m_vm = createVM();
  2. Bir işlev oluşturun ve onu VM'ye gösterin:

    void scriptPrintMessage(VM vm)
    {
        const char* message = getParameter(vm, 0); // first parameter
        printf(message);
    }
    
    //...
    
    createSymbol(m_vm, "print", scriptPrintMessage);
    

    Biz fonksiyonu maruz hangi ismi (dikkat edin print() fonksiyonunun kendisinin iç adıyla eşleşmesi gerekmez scriptPrintMessage)

  3. İşlevini kullanan bazı kod kodlarını çalıştırın:

    const char* scriptCode = "print(\"Hello world!\")"; // Could also be loaded from a file though
    doText(m_vm, scriptCode);
    

Hepsi bu kadar. Ardından program aşağıdaki şekilde akar:

  1. Sen ara doText(). Kontrol daha sonra içerdeki metni yürütecek olan sanal makineye aktarılır scriptCode.

  2. Betik kodu daha önce verilen bir sembol bulur print. Daha sonra kontrolü fonksiyona aktaracaktır scriptPrintMessage().

  3. İşlem scriptPrintMessage()tamamlandığında, kontrol sanal makineye geri dönecektir.

  4. Metindeki tüm metinler scriptCodeyürütüldüğünde, doText()bitecek ve kontrol, sonraki satırda programınıza geri aktarılacaktır doText().

Genel olarak yaptığınız tek şey başka bir programın içinde bir program çalıştırmak. Teorik olarak konuşursak, onlarsız yapamayacağınız senaryolarla yapabileceğiniz hiçbir şey yoktur, ancak bu soyutlama bazı ilginç şeyleri gerçekten kolayca yapmanızı sağlar. Onlardan bazıları:

  • Endişelerin ayrılması: C / C ++ ile bir oyun motoru ve daha sonra da asıl oyunun Lua gibi bir betik dilinde yazılması yaygın bir kalıptır. Doğru yapıldığında, oyun kodu tamamen motorun kendisinden bağımsız olarak geliştirilebilir.

  • Esneklik: komut dosyası dilleri genel olarak yorumlanır ve bu nedenle komut dosyasındaki bir değişiklik mutlaka tüm projenin yeniden oluşturulmasını gerektirmez. Doğru, hatta bir program yeniden başlatmadan bile bir betiği değiştirmek ve sonuçları görebilirsiniz!

  • Kararlılık ve güvenlik: komut dosyası sanal bir makinede çalıştığından, doğru yapılırsa, bir hata ayıklama komut dosyası ana bilgisayar programına kilitlenmez. Kullanıcılarınızın oyununuza kendi komut dosyalarını yazmalarına izin verdiğinizde bu özellikle önemlidir. İstediğiniz kadar bağımsız sanal makineler oluşturabileceğinizi unutmayın! (Bir keresinde, her bir eşleşmenin ayrı bir sanal makine üzerinde çalıştığı bir MMO sunucusu yarattım)

  • Dil özellikleri: komut dosyası dillerini kullanırken, ana bilgisayar ve komut dosyası dilleri seçiminize bağlı olarak, her dilin sunduğu en iyi özelliklerden yararlanabilirsiniz. Özellikle, lua'nın coroutinleri, C veya C ++ 'da uygulanması çok zor olan çok ilginç bir özelliktir.

Senaryolar olsa mükemmel değil. Komut dosyası kullanmanın bazı genel dezavantajları vardır:

  • Hata ayıklama çok zorlaşır: genellikle, ortak IDE'lerde bulunan hata ayıklayıcılar, komut dosyalarının içindeki hata ayıklama için tasarlanmamıştır. Bu nedenle, konsol izleme hata ayıklaması istediğimden çok daha yaygın.

    Lua gibi bazı kodlama dilleri, Eclipse gibi bazı IDE'lerde yararlanılabilecek hata ayıklama olanaklarına sahiptir. Bunu yapmak çok zor ve dürüst olmak gerekirse, yerel hata ayıklamanın yanı sıra çalışmakta olan senaryo hata ayıklamasını hiç görmedim.

    Bu arada, Birlik geliştiricilerinin bu konuda sahip oldukları aşırı ilgi eksikliği, oyun motorları hakkındaki temel eleştirim ve artık kullanmamamın ana nedeni, ancak dalıyorum.

  • IDE entegrasyonu: IDE'nizin programınızdan hangi fonksiyonların dışa aktarıldığını bilme olasılığı yoktur ve bu nedenle, IntelliSense ve benzeri gibi özelliklerin komut dosyalarınızla çalışması olası değildir.

  • Performans: Programların yaygın olarak yorumlanması ve mimarisi gerçek donanımdan farklı olabilecek soyut bir sanal makine için kullanılan komut dosyaları genellikle yerel kodlardan daha yavaştır. LuaJIT ve V8 gibi bazı VM'ler gerçekten iyi bir iş çıkarıyor. Çok ağır komut dosyaları kullanıyorsanız, bu fark edilebilir.

    Genellikle, içerik değişiklikleri (ana bilgisayardan komut dosyasına ve ana bilgisayardan komut dosyası için) çok pahalıdır, bu nedenle performans sorunlarınız varsa bunları en aza indirmek isteyebilirsiniz.

Komut dosyalarınızı nasıl kullandığınız size bağlıdır. Çok ince bir oyun motoruyla komut dosyası dilinde tüm oyunları yapmak kadar karmaşık, ayar ayarları kadar basit şeyler için kullanılan komut dosyalarını gördüm. Bir kere bile, Lua ve JavaScript (V8 üzerinden) komut dosyası karışık bir çok egzotik oyun motoru gördüm.

Komut dosyası yalnızca bir araçtır. Harika oyunlar yapmak için nasıl kullandığınız tamamen size kalmış.


Bu konuda gerçekten yeniyim ama Birlik kullanıyorum. Birlik hakkında bir şeyden bahsettiniz, bunun hakkında ayrıntılı bilgi verebilir misiniz? Başka bir şey mi kullanmalıyım?
Tokamocha

1
Ben kullanmak ister printfsizin örnekte (veya en az kullanın printf("%s", message);)
ucube mandalınızı

1
@ratchetfreak: Mesajınızın sonundaki noktalı virgül ve ardından parantez beni takip ediyor ...
Panda Pajama

1
Bu sitede uzun zamandır gördüğüm en iyi cevaplardan biri; aldığı her oyu hak ediyor. Çok iyi yapmışsın.
Steven Stadnicki

1
Oyunlarda Lua'nın posterci çocuğu, kullanıcı arayüzünün çoğunun Lua'da yazıldığı ve çoğu oyuncu tarafından değiştirilebilen World of Warcraft'tır. Bahsetmediğine şaşırdım.
Michael Hampton,

7

Genel olarak, bazı yerel işlevleri Lua'ya bağlar veya gösterirsiniz (genellikle bunu yapmak için bir yardımcı program kütüphanesi kullanarak ). Bu, oyununuz Lua kodunu çalıştırdığında, Lua kodunun yerel C ++ kodunuza arama yapmasına olanak tanır. Bu anlamda, Lua kodunun sadece yerel koda çağırdığı varsayımı doğrudur (Lua'nın kendi standart işlev kütüphanesi olmasına rağmen , her şey için yerel kodunuzu çağırmanıza gerek yoktur ).

Lua kodunun kendisi, kendi programınızdaki (genellikle) bir kütüphane olarak bağladığınız C kodu olan Lua çalışma zamanı tarafından yorumlanır. Lua'nın Lua ana sayfasında nasıl çalıştığı hakkında daha fazla bilgi edinebilirsiniz . Özellikle, Lua tahmin ettiğiniz gibi "derlenmemiş bir sınıf" değildir, özellikle C ++ sınıfını düşünüyorsanız, çünkü C ++ pratikte neredeyse hiçbir zaman dinamik olarak derlenmemiştir. Bununla birlikte, Lua'nın çalışma zamanı ve Lua'nın yarattığı nesneler, oyununuzun çalıştırdığı komut dosyaları oyununuzun sistem belleği havuzunda yer kaplar.


5

Lua gibi betik dilleri çeşitli şekillerde kullanılabilir. Dediğiniz gibi, ana programdaki fonksiyonları çağırmak için Lua'yı kullanabilirsiniz, ancak isterseniz sadece C ++ ile çağrılan Lua fonksiyonlarını kullanabilirsiniz. Genel olarak, seçtiğiniz komut dosyası dili ile biraz esneklik sağlamak için bir arayüz oluşturur, böylece komut dosyası dilini bir dizi senaryoda kullanabilirsiniz. Lua gibi betik dilleri ile ilgili en güzel şey derlenmiş yerine yorumlanmış olmalarıdır, böylece anında Lua betiklerini değiştirebilirsiniz, böylece oyununuzun sadece sizin derlemeniz için derleyebilmesi için derlemesini beklemek zorunda kalmazsınız Yaptığın zevklerine uygun değil.

Lua komutları yalnızca C ++ programı onları çalıştırmak istediğinde çağrılır. Bu nedenle, kod yalnızca çağrıldığında yorumlanacaktır. Sanırım Lua'yı ana programdan ayrı olarak çalışan bir bash betiği olarak düşünebilirsiniz.

Genel olarak, güncelleme veya yinelemeyi yinelemek isteyebileceğiniz şeyler için komut dilleri kullanmak istersiniz. GUI için birçok şirket kullandığını gördüm, böylece arayüze özelleştirilebilirlik sağlıyor. Onların Lua arayüzünü nasıl yaptıklarını bilmenizi sağlayarak GUI'yi kendiniz de değiştirebilirsiniz. Ancak, AI mantığı, silahlarla ilgili bilgiler, karakterlerin diyalogu vb. Gibi Lua'yı kullanmak için kullanabileceğiniz çok sayıda yol var.


3

Lua dahil olmak üzere çoğu kodlama dili, bir komut dosyası komutunu "gerçek" bir CPU komutuna veya işlev çağrısına eşlemek için temelde bir sistem olan Sanal Makine ( VM ) üzerinde çalışır . Lua VM normalde ana uygulama ile aynı süreçte çalışır. Bu özellikle kullanan oyunlar için geçerlidir. Lua API, komut dosyası dosyalarını yüklemek ve derlemek için yerel uygulamada çağırdığınız birçok işlevi sağlar. Örneğin luaL_dofile(), verilen betiği Lua bytecode içinde derler ve sonra çalıştırır. Bu bayt kodu, API içinde çalışan VM tarafından yerel makine talimatlarına ve işlev çağrılarına eşlenecektir.

C ++ gibi bir ana dili bir betik diliyle bağlama işlemine ciltleme denir . Lua durumunda, API'si yerel işlevleri komut dosyası koduna maruz bırakmanıza yardımcı olan işlevler sağlar. Böylece örneğin bir C ++ fonksiyonunu tanımlayabilir say_hello()ve bu fonksiyonu bir Lua betiğinden çağrılabilir hale getirebilirsiniz. Lua API ayrıca, çalıştırıldıklarında betikler için görünür olacak C ++ kodu ile değişken ve tablo oluşturma yöntemleri sağlar. Bu özellikleri birleştirerek tüm C ++ sınıflarını Lua'ya maruz bırakabilirsiniz. Bunun tersi de mümkündür, Lua API, kullanıcının Lua değişkenlerini değiştirmesine ve Lua işlevlerini yerel C ++ kodundan çağırmasına izin verir.

Çoğu tüm komut dosyası dili, komut dosyası kodunun yerel kodla bağlanmasını kolaylaştırmak için API'ler sağlamıyorsa. Çoğu da bytecode içinde derlenir ve bir VM'de çalıştırılır, ancak bazıları satır satır yorumlanabilir.

Umarım bu, bazı sorularınızı netleştirmeye yardımcı olur.


3

Kimse bundan bahsetmediğinden, ilgilenenler için buraya ekleyeceğim. Oyun Komut Dosyası Ustalığı adlı konuda bir kitap var . Bu, bir süre önce yazılmış harika bir metin, ancak bugün tamamen ilgili kalıyor.

Bu kitap size sadece kodlama dillerinin yerel yasalara nasıl uyduğunu göstermez, aynı zamanda kendi kodlama dilinizi nasıl uygulayacağınızı da öğretir. Bu, kullanıcıların% 99’u için aşırı sayılacak olsa da, bir şeyi gerçekten uygulamaktan (çok temel bir biçimde bile) anlamaktan daha iyi bir yol yoktur.

Bir oyun motoru kendiniz yazmak istiyorsanız (veya yalnızca bir oluşturma motoruyla çalışıyorsanız), bu metin bir kodlama dilinin motorunuza / oyununuza en iyi nasıl dahil edilebileceğini anlamak için paha biçilmezdir.

Ve eğer kendi kodlama dilinizi oluşturmak istiyorsanız, başlayacağım en iyi yerlerden biri (bildiğim kadarıyla).


2

Öncelikle, betik dilleri genel olarak derlenmemiştir . Bu, onları genellikle betik dilleri olarak tanımlayan şeyin büyük bir parçasıdır. Bunlar genellikle, "yorumlanır". Ne bu temelde anlamı başka bir dil (bir olmasıdır edilir hat-by-line, gerçek zamanlı olarak, metin okuma ve işlemleri gerçekleştiriyor değil daha sık, derlenmiş).

Bu ve diğer diller arasındaki fark, betik dillerinin daha basit olma eğilimindedir (genellikle "daha yüksek seviye" olarak adlandırılır). Bununla birlikte, derleyiciler kodlamanın "insan öğesi" ile gelen sorunların çoğunu optimize etme eğiliminde olduklarından ve sonuçta ortaya çıkan ikili kod makine için daha küçük ve hızlı olma eğilimindedir. Ek olarak, derlenen programlarla, çalışmakta olan kodu okumak için çalıştırılması gereken başka bir programdan daha az ek yük vardır .

Şimdi, “Pekala, bunun biraz daha kolay olduğunu biliyorum ama neden dünyada neden bu performansı biraz daha fazla kullanım kolaylığı için bırakıyorsun?” Diye düşünüyorsunuz.

Bu varsayımda yalnız kalmayacaksınız, ancak onlarla ne yaptığınıza bağlı olarak betik dilleri kullanma eğilimindesiniz, performanstaki fedakarlığa değer olabilir.

Temel olarak: Geliştirme hızının, programın çalıştırılma hızından daha önemli olduğu durumlarda, bir komut dosyası dili kullanın. Oyun geliştirmede bunun gibi durumlar çok var. Özellikle üst düzey etkinlik yönetimi gibi önemsiz şeylerle uğraşırken.

Düzenleme: Lua'nın oyun geliştirmede oldukça popüler olma eğiliminin nedeni, tartışmalı olarak, dünyadaki en hızlı (en hızlı değilse) herkese açık betik dillerinden biri olmasıdır. Ancak, bu ekstra hız ile bazı kolaylıklarından ödün vermiştir. Olduğu söyleniyor, hala tartışmalı C veya C ++ ile çalışmaktan daha uygun.

Önemli Düzenleme: Daha fazla araştırma yapıldığında, bir betik dili tanımında daha fazla tartışma olduğunu gördüm (bkz. Ousterhout'un ikilemi ). Bir dili "betik dili" olarak tanımlamanın temel eleştirisi, yorumlanması veya derlendiği dilin sözdizimi veya anlambilimi için önemli olmamasıdır.

Genellikle "betik dilleri" olarak kabul edilen diller genellikle derlenmiş olmaktan ziyade geleneksel olarak yorumlanırken, "betik dilleri" olarak tanımlanma sürelerinin kısa ve özü insanların kendilerini nasıl gördüklerinin ve yaratıcılarının onları nasıl tanımladıklarının bir birleşimidir.

Genel olarak konuşursak, bir dil, aşağıdaki kriterleri yerine getirdiği takdirde (yukarıdaki bağlantılı makaleye göre), kolayca bir betik dili olarak kabul edilebilir (Ousterhout'un ikilemini kabul ettiğiniz varsayılarak):

  • Dinamik olarak yazılırlar
  • Karmaşık veri yapıları için çok az veya hiç provizyonları yok
  • İçlerindeki programlar (scriptler) yorumlanır

Ek olarak, bir dilin başka bir programlama diliyle (genellikle bir komut dosyası dili olarak kabul edilmeyen bir dille birlikte) etkileşimde bulunmak ve işlev görmek üzere tasarlanmış olması halinde, bir dilin bir betik dili olduğu kabul edilir.


1
"Scripting dilleri derlenmedi" yazdığınız ilk satırda size katılmıyorum. Lua aslında bir JIT derleyicisi tarafından yürütülmeden önce ara bayt kodunda derlenmiştir. Bazıları elbette satır satır yorumlanıyor, ancak hepsi değil.
glampert

"Script dili" tanımına katılmıyorum. Çift kullanımlı diller (Lua veya C # gibi), betik formundan ziyade derlenmiş formlarında (ya da tam tersi, C # 'da olduğu gibi) sıkça kullanılan dillerdir. Bir dil bir komut dosyası dili olarak kullanıldığında, kesinlikle yorumlanmış ve derlenmemiş bir dil olarak tanımlanır.
Gurgadurgen

Yeterince adil, tanımınız Wikipedia ile daha fazla satır içi: "Bir komut dosyası dili veya komut dili, komut dosyalarını destekleyen bir programlama dilidir, yorumlayabilen özel bir çalışma zamanı ortamı için yazılmış programları (derleme yerine) ..." boşver Benim yorumum o zaman.
glampert

1
Düzenli Lua bile tamamen bytecode ile derlenir, JIT derleyicisi yerel ikili bile üretebilir. Yani hayır, Lua yorumlanmadı.
Oleg V. Volkov

İlk kısım iffy, oy kullanmaya başlıyorum. Sonunda yorumlanması ve @ OlegV.Volkov JIT derleme derlenmiş bir şey yapmaz diye haklı. Derleme, Lua'nın sahip olduğu derleme zamanı ile tanımlanır, Lua byte kodu yok (JIT veya JIT yok). Terimimizi karıştırmayalım.
Alec Teal
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.