RPG masa oyunu kuralları için genel kural ayrıştırıcı - nasıl yapılır?


19

Kalem ve kağıt tarzı RPG sistemleri için genel bir kural ayrıştırıcısı oluşturmak istiyorum. Bir kural genellikle bir zarın 1 ila N varlıklarını 1 ila N rolünü ve bir varlığın birden fazla özelliğine göre değerlerin hesaplanmasını içerebilir.

Örneğin:

Oyuncu STR 18'e sahip, şu anda donanımlı silahı ona +1 STR bonusu veriyor, ancak DEX -1'in malusu. Bir canavar varlığına saldırıyor ve şimdi oyun mantığının bir dizi kural veya eylem yürütmesi gerekiyor:

Oyuncu zar atar, örneğin 8 veya daha fazla alırsa (geçmesi gereken temel saldırı değeri temel özelliklerinden biridir!) Saldırısı başarılı olur. Canavar daha sonra saldırının zırhından geçip geçmediğini hesaplamak için zarları döndürür. Evet ise, saldırı engellenmezse hasar alınır.

Basit matematik kurallarının yanı sıra, sadece belirli bir kullanıcı sınıfına (örneğin savaşçı vs sihirbaz) veya başka bir özelliğe uygulamak gibi kısıtlamalar da olabilir. Yani bu sadece matematiksel işlemlerle sınırlı değil.

Dungeon ve Dragons gibi RPG sistemlerini biliyorsanız, ne yaptığımı bilirsiniz.

Benim sorunum şimdi mümkün olan en iyi şekilde tam olarak nasıl yapılacağı hakkında hiçbir fikrim yok. İnsanların her türlü kuralı kurabilmelerini ve daha sonra bir oyuncu ve bir canavar seçip bir eylemi (saldırı gibi kurallar kümesi) yürütmek gibi bir eylem yapabilmelerini istiyorum.

Ben şeylerin veritabanı tarafında yardım için daha az istiyorum ama nasıl kurallarımı esnek tutmak için bir yapı ve ayrıştırıcı ile gelip hakkında daha fazla bilgi istiyorum. Bunun için tercih edilen dil php bu arada.

Düzenleme I:

Hedefimi geliştirmeme izin verin: Az ya da çok karmaşık oyun kuralları oluşturmak için kullanıcı dostu bir arayüz (birisinin programlama dilini öğrenmesini gerektirmeyen) oluşturmak istiyorum. Basit neden: Kişisel kullanımın tüm kuralları her zaman hatırlaması gerekmiyor, sadece sık sık oynamıyoruz ve her seferinde onları aramak bir tıpa. Ayrıca: Bir şeyler yapmak ve öğrenmek için eğlenceli bir görev gibi görünüyor. :)

Şimdiye kadar denediklerim: Sadece yanlış bir mimari inşa etmek için zaman kaybetmek yerine bir konsept düşünmek. Şimdiye kadar, bir kullanıcının istediği sayıda özellik oluşturmasına ve ardından herhangi bir varlığa istediği sayıda özellik atamasına izin verme fikrim var. Bir varlık bir oyuncu, bir canavar, bir eşya, herhangi bir şey olabilir. Şimdi bir şey hesaplarken veriler kural ayrıştırıcı tarafından kullanılabilir hale getirilir, böylece kural ayrıştırıcısı Player.base_attack + dice (1x6)> Monster.armor_check sonra Monster.health - 1 gibi şeyler yapabilir. Buradaki soru bu ayrıştırıcının nasıl oluşturulacağı ile ilgilidir.

Düzenleme II:

İşte oldukça basit bir değer örneği ama düzgün bir şekilde hesaplamak için dikkate alınması gereken birçok farklı şey ve değişken var:

Temel Saldırı Bonusu (Terim) Temel saldırı bonusunuz (genellikle d20 topluluğu tarafından BAB olarak adlandırılır), karakter sınıfı ve seviyesinden türetilen bir saldırı atış bonusu. Temel saldırı bonusları farklı karakter sınıfları için farklı oranlarda artar. Bir karakter, taban saldırı bonusu +6'ya ulaştığında her turda ikinci bir saldırı kazanır, üçte biri +11 veya daha yüksek bir taban saldırı bonusu ve dördüncü sırada da +16 veya daha yüksek bir taban saldırı bonusu elde eder. Çok sınıflı bir karakter gibi farklı sınıflardan kazanılan temel saldırı bonusları. Bir karakterin temel saldırı bonusu +16'ya ulaştıktan sonra daha fazla saldırı sağlamaz, +0'dan az olamaz ve karakter seviyesi 20. seviyeye ulaştıktan sonra sınıf seviyeleri nedeniyle artmaz. Belirli yetenekler için minimum taban saldırı bonusu gerekir.

Temel saldırı için gerekli değerleri hesaplamak için yine kendi kuralları olan sınıflara ve yeteneklere bağlantılar da dahil olmak üzere http://www.dandwiki.com/wiki/Base_Attack_Bonus_(Term) burada okuyabilirsiniz .

Mümkün olduğunca genel tutmanın aynı zamanda iyi bir kural ayrıştırıcısının yapılmasını oldukça zorlaştıracağını düşünmeye başladım.



2
Aslında bu sabah tam olarak bu tür bir sorun hakkında düşünüyordum (RPG ile ilgili değil, kural motorları işliyor) ve kuralların işlenmesine devlet dışı makine yaklaşımlarını ve kombinatorik ayrıştırıcıların genellikle devlet makineleri. Monadik birleştiricilerin çoğu devlet makinesi sorununa daha temiz bir şekilde yaklaşmaları için zengin bir olasılık olduğunu düşünüyorum. Bu anlamsız gelebilir ama bence bu fikirde sadece 2 sentim var. RPG sistemleri, kodlamayı sevdiğim klasik bir eğlenceli uygulama problemidir, belki de bu yaklaşımı deneyeceğim.
Jimmy Hoffa

1
@jk. Bu makale Func, sözlüğün anahtarları olarak argümanlara dayalı olarak program durumunu başlatan s sözlüğünü kullanarak komut satırı program argüman ayrıştırma için sevdiğim bir deseni hatırlatıyor . Şaşırdım Yegge'den daha önce hiç bu yazı bulamadım, çok havalı, işaret ettiğin için teşekkürler.
Jimmy Hoffa

4
Bunun neden "gerçek bir soru" olarak kapandığından emin değilim. Belirli bir gereksinim kümesi (RPG kural sistemi) olan bir uygulamanın nasıl mimar edileceği hakkında daha yüksek bir "beyaz tahta" sorusu. Yeniden açmaya oy verdim, ancak yeniden açılması için yine 4 oy daha gerekiyor.
Rachel

1
Dürüst olmak gerekirse bu site tam olarak bu tür kavramsal sorular için düşünürken stackoverflow.com kod / uygulama sorunları için düşünülmüş.
burzum

Yanıtlar:


9

İstediğiniz şey aslında alana özgü bir dildir - dar bir amaç için küçük bir programlama dili, bu durumda P&P RPG kurallarını tanımlar. Bir dil tasarlamak prensip olarak zor değildir, ancak üretken olabilmek için kazanmanız gereken önemli miktarda ön bilgi vardır. Ne yazık ki, bu şeyler için merkezi bir referans yok - deneme, hata ve çok sayıda araştırma yoluyla almanız gerekiyor.

İlk olarak, diğer işlemlerin uygulanabileceği bir dizi ilkel işlem bulun. Örneğin:

  • Oyuncunun, NPC'nin veya canavarın mülkünü alma veya ayarlama

  • Bir kalıp rulosunun sonucunu alın

  • Aritmetik ifadeleri değerlendirme

  • Koşullu ifadeleri değerlendirme

  • Koşullu dallanma gerçekleştirme

İlkellerinizi ifade eden bir sözdizimi tasarlayın. Sayıları nasıl temsil edeceksiniz? Bir ifade neye benziyor? İfadeler noktalı virgülle sonlandırıldı mı? Yeni satır sonlandırılmış? Blok yapı var mı? Bunu nasıl göstereceksiniz: semboller veya girinti yoluyla? Değişken var mı? Yasal değişken adı nedir? Değişkenler değiştirilebilir mi? Nesnelerin özelliklerine nasıl erişeceksiniz? Nesneler birinci sınıf mı? Onları kendiniz yaratabilir misiniz?

Programınızı soyut bir sözdizimi ağacına (AST) dönüştüren bir ayrıştırıcı yazın. Özyinelemeli bir iniş ayrıştırıcısıyla ifadeleri ayrıştırma hakkında bilgi edinin. Aritmetik ifadeleri özyinelemeli iniş ile ayrıştırmanın nasıl can sıkıcı olduğunu ve yukarıdan aşağıya bir operatör öncelik ayrıştırıcısının (Pratt ayrıştırıcı) hayatınızı nasıl kolaylaştırabileceğini ve kodunuzu nasıl kısaltabileceğini öğrenin.

AST'nizi değerlendiren bir tercüman yazın. Bu sadece ağacın her düğümü okumak ve ne diyor yapabilirsiniz: a = bolur new Assignment("a", "b")olur vars["a"] = vars["b"];. Hayatınızı kolaylaştırırsa, değerlendirmeden önce AST'yi daha basit bir forma dönüştürün.

Çalışacak ve okunabilir kalacak en basit şeyi tasarlamanızı öneririm. İşte bir dilin neye benzeyebileceğine bir örnek. Tasarımınız mutlaka özel ihtiyaç ve tercihlerinize göre farklılık gösterecektir.

ATK = D20
if ATK >= player.ATK
    DEF = D20
    if DEF < monster.DEF
        monster.HP -= ATK
        if monster.HP < 0
            monster.ALIVE = 0
        end
    end
end

Alternatif olarak, Python veya Lua gibi mevcut bir komut dosyası dilini uygulamanıza nasıl yerleştireceğinizi öğrenin ve bunu kullanın. Etki alanına özgü bir görev için genel amaçlı bir dil kullanmanın dezavantajı, soyutlamanın sızıntılı olmasıdır: dilin tüm özellikleri ve yakalamaları hala mevcuttur. Tersi, onu kendiniz uygulamak zorunda değilsiniz - ve bu önemli bir ters. Bir düşünün.


2
Kötü bir yaklaşım değil ama sürekli olarak DSL'lerden şüpheliyim, doğru olmak için çok fazla iş var (özellikle insanların sahip olduğu bazı akıcı API'ların aksine, özel sözdizimine sahip gerçek bir DSL'den bahsediyorsanız ve "DSL" leri aramaya başladığınızdan emin olun. Çoğu zaman insanların sadece küçük bir kural motoru için kullanacakları bir DSL denemek istediklerini düşünüyorum. İşte benim kural: DSL uygulaması + kullanımı DSL olmadan daha az kod ise, bunun için gitmek, bu durumda böyle olacağını sanmıyorum.
Jimmy Hoffa

1
@JimmyHoffa: Yeterince adil. Özellikle oyunlar için dil tabanlı çözümlere ulaşmak benim doğamda. Muhtemelen küçük ve işlevsel bir şey yapmanın zorluğunu hafife alıyorum çünkü birçok kez yaptım. Yine de, bu durumda uygun bir öneri gibi görünüyor.
Jon Purdy

Sanırım bu tür bir soruna doğru bir yaklaşım olduğunu söylemeliyim, ama bu uygulamayı yapan kişinin yeterli beceriye sahip biri olduğuna dayanıyor. Öğrenmek için DSL'ler gençler için mükemmeldir, ancak gerçek serbest bırakılabilir ürün için asla üst düzey seviyenin altındaki birini DSL yazarken görmek istemem ve bir çocuk için DSL'de çözülebilen bir sorunun farklı bir şekilde çözülmesi gerekir.
Jimmy Hoffa

Bunu okuduktan sonra bunun için lua betiklerini değerlendirebileceğimi düşünüyorum. Buradaki dezavantaj, bir kullanıcının lua komut dosyaları yazabilmesi gerektiğidir. Benim kişisel amacım magento (e-ticaret uygulaması) kural oluşturucu gibi programlama bilgisi olmadan kullanılabilecek bir arayüz yazmak. Çünkü insanların kendi kurallarını ekleyebilmelerini istiyorum. Ticari bir şey uygulamıyorum, sadece ve arkadaşlarımın düzensiz bir temelde oynadığımız RPG sisteminin kurallarına girmelerine ve kurallara geri dönüp bunları uygulamak bir süre sonra bir acıdır ...
burzum

1
@burzum: Arayüzünüzün lua betikleri oluşturmasına ne dersiniz?
TMN

3

Her bir eylemin farklı "Aşamalarını" belirleyerek başlardım.

Örneğin, bir Savaş Aşaması şunları içerebilir:

GetPlayerCombatStats();
GetEnemyCombatStats();
GetDiceRoll();
CalculateDamage();

Bu yöntemlerin her biri, Playerve gibi oldukça genel nesnelere erişebilir Monsterve diğer varlıkların değerleri değiştirmek için kullanabileceği oldukça genel denetimler gerçekleştirir.

Örneğin, GetPlayerCombatStats()yönteminizde buna benzeyen bir şey olabilir :

GetPlayerCombatStats()
{
    Stats tempStats = player.BaseStats;

    player.GetCombatStats(player, monster, tempStats);

    foreach(var item in Player.EquippedItems)
        item.GetCombatStats(player, monster, tempStats);
}

Bu, Oyuncu Sınıfı, canavar veya Ekipman parçası gibi belirli kurallara sahip herhangi bir varlığı kolayca eklemenizi sağlar.

Başka bir örnek olarak, kalamar hariç her şeyi öldürmek için bir kılıç istediğinizi varsayalım , bu şey dokunaçlara sahip olmadıkça her şeye +4 verir, bu durumda kılıcınızı düşürmeniz ve savaşta bir -10 almanız gerekir.

Bu kılıç için ekipman sınıfınızda GetCombatStatsşöyle bir şey olabilir :

GetCombatStats(Player player, Monster monster, Stats tmpStats)
{
    if (monster.Type == MonsterTypes.Tentacled)
    {
        player.Equipment.Drop(this);
        tmpStats.Attack -= 10;
    }
    else
    {
        tmpStats.Attack += 4;
    }
}

Bu, savaş mantığının geri kalanını bilmenize gerek kalmadan savaş değerlerini kolayca değiştirmenize olanak tanır ve Ekipmanınıza (veya herhangi bir varlık) sadece detaylar ve uygulama mantığı nedeniyle uygulamaya kolayca yeni parçalar eklemenizi sağlar. varlık sınıfının kendisinde var olması gerekir.

Çözülmesi gereken kilit noktalar, değerlerin hangi noktalarda değişebileceği ve hangi değerleri bu değerleri etkileyeceğidir. Bunlara sahip olduğunuzda, bireysel bileşenlerinizi oluşturmak kolay olmalıdır :)


Gidilecek yol bu. Çoğu Kalem ve Kağıt RPG'de, hesaplamalarda genellikle kılavuz kitaplarda yazılı aşamalar vardır. Ayrıca, sahnenin sırasını daha genel hale getirmek için sıralı bir listeye koyabilirsiniz.
Hakan Deryal

Bu benim için oldukça statik geliyor ve bir kullanıcının sadece bir kullanıcı arayüzünde gerekli kuralları girmesine / oluşturmasına izin vermiyor mu? Açıkladığınız şey daha çok kodlanmış kurallara benziyor. Bu, iç içe geçmiş kurallar listesine sahip olarak da yapılabilir. Herhangi bir kuralı sabit kodlamak istemiyorum. Kodda her şeyi yapabilseydim, bu soruyu sormam gerekmiyordu, bu kolay olurdu. :)
burzum

@burzum Evet, bu kuralların kod tarafından tanımlanacağı anlamına gelir, ancak kodu koddan çok genişletilebilir hale getirir. Örneğin, yeni bir Sınıf türü veya yeni bir Donatım parçası veya yeni bir Canavar türü eklemek istiyorsanız, o varlık için sınıf nesnelerini oluşturmanız ve sınıfınızdaki uygun yöntemleri mantığınızla doldurmanız yeterlidir.
Rachel

@burzum Sorunuzun düzenlemesini yeni okudum. Eğer tek arayüz kullanımı için kurallar motoru istiyorsanız, ben birim (bir havuz yaparak ele alacak Player, Monster, Diceparametrelerinde, vb) ve bir "denklem" alanına sürükle / bırak varlık parçalara yapmasını sağlar şey kurma, dolum varlık (doldurma gibi player.base_attack) ve parçaların nasıl bir araya getirildiği konusunda basit operatörler belirtin. Aslında blogumda kullanabileceğiniz bir matematiksel denklemi ayrıştıran bir şey var .
Rachel

@Rachel'de tarif ettiğiniz kolay ölü OOP, vahşi doğada OOP'yi öğretmek için RPG benzeri şeyler kullanan birçok örnek bile var. Bu nesnelere sahip olmak ve onlarla çalışmak kolay kısmı, veritabanındaki verilere dayanarak onları anında oluşturabilirim. Yaklaşımınızdaki sorun, bu yöntemin bir UI aracılığıyla bir yerde tanımlanması ve bir db'de depolanması gereken her şey GetEnemyCombatStats () gibi zor kurallardır. Makaleniz o github.com/bobthecow/Ruler veya o github.com/Trismegiste/PhpRules ile benzer görünüyor .
burzum

0

Maptool'a özellikle Rumble'ın 4. baskı çerçevesine bir göz atacağım . Neden bahsettiğinizi ayarlamak için gördüğüm en iyi sistem. Ne yazık ki en iyisi hala korkunç derecede acımasız. Onların "makro" sistemleri ... diyelim ki ... zamanla gelişti.

Bir "kural ayrıştırıcı" gelince ben sadece PHP bile rahat hangi programlama dili ile sopa olurdu. Sisteminizin tüm kurallarını kodlamanın iyi bir yolu olmayacaktır.

Şimdi, kullanıcılarınızın THEIR OWN kural setini yazmasını istiyorsanız, kendi komut dosyası dilinizi uygulamaya bakıyorsunuz. Kullanıcılar kendi yüksek seviyeli eylemlerini kodlar, php'niz bunu gerçekten veritabanı değerlerini etkileyen bir şeye yorumlar ve daha sonra bir sürü hata atar, çünkü yıllar boyunca ayakkabı boynuzlu olan korkunç bir sistemdir. Gerçekten, Jon Purdy'nin yanıtı hemen topun üzerinde.


0

Sorun alanınızda neler olacağını soyut olarak düşünebilmeniz, bir çeşit model bulmanız ve ardından DSL'inizi buna dayandırmanız gerektiğini düşünüyorum.

Örneğin, varlık, işlem ve etkinliğe en üst düzeyde sahip olabilirsiniz. Kalıp ruloları, eylemlerin bir sonucu olarak meydana gelen olaylar olacaktır. Eylemler, belirli bir durumda kullanılabilir olup olmadıklarını belirleyen koşullara ve eylem gerçekleştirildiğinde meydana gelen şeylerin bir "komut dosyasına" sahip olacaktır. Daha karmaşık şeyler, farklı eylemlerin meydana gelebileceği bir aşamalar dizisi tanımlama yeteneği olacaktır.

Bir çeşit kavramsal modeliniz olduğunda (ve bunu yazmanızı ve / veya temsil etmek için diyagramlar çizmenizi öneririm), onu uygulamanın farklı yollarına bakmaya başlayabilirsiniz.

Bir yol, sözdiziminizi tanımladığınız harici bir DSL olarak adlandırılan şeyi tanımlamak ve ayrıştırmak ve mantığınızı çağırmak için antlr gibi bir araç kullanmaktır. Başka bir yol da DSL'nizi tanımlamak için programlama dilinde mevcut olan tesislerin kullanılmasıdır. Groovy ve Ruby gibi diller bu alanda özellikle iyidir.

Kaçınmanız gereken bir tuzak, ekran mantığınızı uygulanan oyun modelinizle karıştırmaktır. Görüntülü reklam kodunuzu modelinizle karıştırmak yerine ekranın modelinizi okumasını ve uygun bir şekilde görüntülemesini isterim.

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.