Macera Oyunlarında farklı durumları kodlama


12

Bir macera oyunu planlıyorum ve hikaye ilerlemesine bağlı olarak bir seviyenin davranışını uygulamanın doğru yolunun ne olduğunu anlayamıyorum.

Tek oyunculu oyunum, oyuncunun bir kasabadaki insanlarla oyunun çeşitli noktalarında etkileşim kurması gereken dev bir dünyaya sahip. Bununla birlikte, hikaye ilerlemesine bağlı olarak, oyuncuya farklı şeyler sunulacaktır, çünkü Lonca Lideri kasaba meydanından şehirdeki çeşitli konumlara yer değiştirecektir; Kapılar sadece belirli bir rutini bitirdikten sonra günün belirli saatlerinde açılır; Farklı kesme-ekran / tetikleme olayları ancak belirli bir aşamaya ulaşıldıktan sonra gerçekleşir.

NPC'nin ne söylemesi veya hangisinde bulunabileceğine karar vermek için başlangıçta bir switch {} ifadesi kullanmayı ve görev hedeflerini ancak küresel bir game_state değişkeninin durumunu kontrol ettikten sonra etkileşimli hale getirmeyi düşündüm. Ancak bir nesnenin davranışını değiştirmek için çok sayıda farklı oyun durumuna ve geçiş senaryosuna gireceğimi fark ettim. Bu anahtar ifadesinin hata ayıklaması da büyük ölçüde zor olacak ve sanırım bir seviye düzenleyicide kullanmak zor olabilir.

Bu yüzden, birden çok durumlu tek bir nesneye sahip olmak yerine, belki de tek bir durumla aynı nesnenin birden çok örneğine sahip olmam gerektiğini düşündüm. Bu şekilde, bir seviye editörü gibi bir şey kullanırsam, NPC'nin bir örneğini, görülebileceği tüm farklı konumlara ve ayrıca sahip olduğu her konuşma durumu için bir örnek koyabilirim. Ancak bu, seviye etrafında yüzen, bellek için sorun yaratabilecek veya bir seviye düzenleyicide görmek zor olan bir çok inaktif, görünmez oyun nesnesi olacağı anlamına geliyor, bilmiyorum.

Veya her oyun durumu için aynı, ancak ayrı bir seviye yapın. Bu, işleri yapmanın en temiz ve hatasız yolunu hisseder, ancak seviyenin her versiyonunun birbiriyle gerçekten aynı olduğundan emin olmak için büyük bir manuel çalışma gibi hisseder.

Tüm yöntemlerim o kadar verimsiz hissediyor, öyleyse sorumu yeniden özetlemek için, hikaye ilerlemesine bağlı olarak bir seviyenin davranışını uygulamanın daha iyi veya standart bir yolu var mı?

Not: Henüz bir seviye editörüm yok - JME SDK gibi bir şey kullanmayı ya da kendimi yapmayı düşünüyorum.

Yanıtlar:


9

Bu durumda ihtiyacınız olanın Devlet Tasarım Örneği olduğunu düşünüyorum . Her oyun nesnesinin birden çok örneğine sahip olmak yerine, tek bir örnek oluşturun, ancak davranışını ayrı bir sınıfta kapsülleyin . Her olası davranış için bir tane olmak üzere birden çok sınıf oluşturun ve tüm sınıflara aynı arabirimi verin. Birini oyun nesnenizle (başlangıç ​​durumu) ilişkilendirin ve koşullar değiştiğinde (dönüm noktasına ulaşıldığında, günün saati geçtiğinde vb.) O nesnenin durumunu değiştirirsiniz (yani oyun mantığınıza bağlı olarak farklı bir nesneyle ilişkilendirirsiniz) ve varsa özelliklerini güncelleyin.

Bir durum arayüzünün nasıl görüneceğine bir örnek (tamamen uydurulmuş - sadece bu şemanın size verdiği kontrol seviyesini göstermek için):

interface NPCState {
    Scene whereAmI(NPC o);
    String saySomething(NPC o);
}

Ve iki uygulama sınıfı:

class Busy implements NPCState {
    Scene whereAmI(NPC o) {
        return o.getWorkScene();
    }
    String saySomething(NPC o) {
        return "Can't talk now, I'm busy!";
    }
}

class Available implements NPCState {
    Scene whereAmI(NPC o) {
        return TAVERN;
    }
    String saySomething(NPC o) {
        String[] choices = o.getRandomChat();
        return choices[RANDOM.getInt(choices.length)];
    }
}

Ve anahtarlama durumları:

// The time of day passed from "afternoon" to "evening"
NPCState available = new Available();
for ( NPC o : list ) {
    Scene oldScene = o.state.whereAmI(o);
    o.state = available;
    Scene newScene = o.state.whereAmI(o);
    moveGameObject(o, oldScene, newScene);
    ...

Önemli NPC'lerin özel durumları olabilir, eyalet seçme mantığı daha özelleştirilebilir olabilir ve oyunun farklı yönleri için farklı durumlara sahip olabilirsiniz (bu örnekte, hem konumu hem de sohbeti anlatmak için tek bir sınıf kullandım, ancak ayrılabilirsiniz) ve birçok kombinasyon yapın).

Bu, seviye editörleriyle de iyi çalışır: bir seviyenin "global" durumunu değiştirmek için basit bir birleşik giriş kutunuz olabilir, ardından oyun nesnelerini bu durumda görünmelerini istediğiniz şekilde ekleyebilir ve yeniden konumlandırabilirsiniz. Oyun motoru, yalnızca doğru nesneye sahip olduğunda sahneye o nesneyi "eklemekten" sorumlu olacaktır - ancak parametreleri yine de kullanıcı dostu bir şekilde düzenlenebilir.

(Feragatname: Oyun editörleri ile çok az gerçek dünya deneyimim var, bu yüzden profesyonel editörlerin nasıl çalıştığı konusunda güvenle söyleyebilirim; ancak Devlet Deseni hakkındaki düşüncem hala geçerli, kodunuzu bu şekilde organize etmek temiz, bakım yapılabilir ve atık sistemi olmamalıdır kaynaklar.)


Biliyorsunuz, bu Durum tasarım desenini tanımladığım ilişkilendirilebilir dizi ile birleştirebilirsiniz. Durum nesnelerini burada açıklandığı gibi kodlayabilir ve sonra önerdiğim gibi ilişkilendirilebilir bir dizi kullanarak farklı durum nesneleri arasında seçim yapabilirsiniz.
jhocking

Katılıyorum, oyunu motorundan ayırmak da iyi ve hardcoding oyun mantığı aralarındaki bağlantıyı güçlendiriyor (yeniden kullanma olasılığını azaltıyor). Yine de bir ödünleşim var, çünkü amaçlanan davranışınızın "yumuşak kodlamaya" çalışmasına bağlı olarak, her şey gereksiz karmaşaya neden olabilir . Bu durumda, karışık bir yaklaşım istenebilir (yani "jenerik" durum geçiş mantığına sahip olmakla birlikte, özel kodun da eklenmesine izin verir)
mgibsonbr

Anladığım kadarıyla, NPCState ve GameState gibi bire bir eşleme var. Sonra bir dizi NPC'leri koymak ve bir oyun durumu değişikliği gözlendiğinde yeni NPCState atayarak, onu yinelemek wld. NPCState, kendisine gönderilen her diff NPC'nin nasıl işleneceğini bilmesi gerekir, bu nedenle temelde NPCState, belirli bir durum için tüm NPC'lerin davranışını içerir? Tüm davranışların temiz bir şekilde oyun editörü uygulamasına eşlenen tek bir NPCState'te saklanmasını seviyorum, ancak NPCState'i oldukça büyük hale getiriyor.
Cardin

Oh, sanırım senin yanlış anladım. Gözlemcileri dahil etmek için biraz değiştirdim. Bu, durumu paylaşabilen Crowd NPC gibi süper jenerik olanlar hariç, her fark NPC'si için bir fark NPCState. Her oyun durumu için, NPC kendisini ve NPCState'ini bir Gözlemci ile kaydedecektir. Bu nedenle Gözlemci, hangi NPC'nin hangi durumdaki davranışını değiştirmek için kayıtlı olduğunu tam olarak bilecek ve bunlar üzerinden tekrarlayacaktır. Ve oyun editörü tarafında, oyun editörü tüm seviyenin durumunu değiştirmek için Gözlemciye bir sinyal iletmek zorundadır.
Cardin

1
Evet, fikir bu! Önemli NPC'lerin birçok durumu olacaktır ve devlet geçişi çoğunlukla tamamlanan kilometre taşlarına bağlı olacaktır. Genel NPC'ler bazen kilometre taşlarına tepki verebilir ve hatta seçtikleri durum dahili bir özelliğe bağlı olabilir (diyelim ki tüm NPC'ler varsayılan bir başlangıç ​​durumuna sahiptir ve bunlardan biriyle ilk kez konuştuğunuzda, normal durum değiştirme çevrimi).
mgibsonbr

2

Dikkate alacağım seçimler ya tek tek nesneleri farklı oyun sitelerine cevap veriyor ya da farklı oyun sitelerinde farklı seviyelere hizmet ediyor. Bu ikisi arasındaki seçim, oyunda tam olarak ne yapmaya çalıştığımıza bağlı olacaktır (farklı durumlar nelerdir? Oyun eyaletler arasında nasıl geçiş yapacak? Vb.)

Her iki durumda da, devletleri oyun koduna zor kodlayarak yapmazdım. NPC nesnelerinde büyük bir anahtar deyimi yerine, bir veri dosyasından ilişkilendirilebilir bir diziye yüklenen NPC davranışları yerine ve bu ilişkilendirilmiş diziyi, ilişkili durumlar için farklı davranışlar çalıştırmak için aşağıdaki gibi kullanırsınız:

if (state in behaviors) {
  behaviors[state]();
}

Bu veri dosyası bir tür komut dosyası dili mi olurdu? Bence bir düz metin veri dosyası davranışı tanımlamak için yeterli olmayabilir. Her halükarda, dinamik olarak yüklenmesi gerektiği konusunda haklısınız. Geçerli Java kodu oluşturmak için bir oyun editörü kullanmayı tam olarak düşünemiyorum, kesinlikle biraz ayrıştırılması gerekiyor.
Cardin

1
Bu benim ilk düşüncemdi, ancak mgibsonbr'un cevabını gördükten sonra çeşitli bevaviorları ayrı sınıflar olarak kodlayabileceğinizi fark ettim ve daha sonra veri dosyasında hangi davranış sınıflarının hangi durumla gittiğini söyleyebilirsiniz. Bu verileri çalışma zamanında ilişkilendirilebilir bir diziye yükleyin.
jhocking

Oh .. Evet, bu kesinlikle daha basit! : D Lua haha ​​gibi bir şey gömme senaryosu ile karşılaştırıldığında ..
Cardin

2

Kilometre taşı değişikliklerini aramak için bir gözlemci deseni kullanmaya ne dersiniz? Bir değişiklik olursa, bazı sınıflar bunu tanır ve örneğin bir npc'de yapılması gereken bir değişikliği işler.

Bahsedilen devlet tasarım modeli yerine bir strateji modeli kullanırdım.

Bir npc'in karakter ve m konumları ile etkileşime girmenin n yolu varsa, tasarlamanız gereken maksimum (m * n) +1 sınıfı vardır. Strateji modelini kullanarak n + m + 1 sınıfları elde edersiniz, ancak bu stratejiler diğer npcs'ler tarafından da kullanılabilir.

Bu nedenle, kilometre taşlarını idare eden bir sınıf ve bu sınıfı gözlemleyen ve npc veya düşmanları veya neyin değiştirilmesi gerektiğini ele alan sınıflar olabilir. Gözlemciler güncellenirse, bir şeyi yönettikleri örneklere değiştirmeleri gerekip gerekmediğine karar verirler. Örneğin NPC sınıfı, kurucuda NPC-Manager'a ne zaman güncellenmesi ve ne güncellenmesi gerektiğini bildirecektir ...


Gözlemci modeli ilginç görünüyor. Devlet gözlemcisine kayıt olmak NPC'ye tüm sorumlulukları temiz bırakabileceğini düşünüyorum. Strateji modeli, Unity Engine'in Tetikleyici ve AI davranışlarına çok benziyor, bu da farklı oyun nesneleri arasındaki davranışları paylaşmak için kullanılıyor (sanırım). Kulağa mantıklı geliyor. Artıları / eksileri şu anda nt emin değilim, ama Unity de aynı yöntemi kullanıyor biraz güven verici haha ​​..
Cardin

Sadece bu iki deseni birkaç kez kullandım, bu yüzden size eksilerini anlatamıyorum: - / Ama tek bir sorumluluk ve her stratejiyi test etmek için kullanılabilirlik güzel olduğunu düşünüyorum :) birçok farklı sınıfta bir strateji kullanarak onu kullanan her sınıfı bulmak istersiniz.
TOAOGG

0

Verilen tüm yaklaşımlar geçerlidir. Herhangi bir anda bulunduğunuz duruma bağlıdır. Birçok macera ya da MMO bunların bir kombinasyonunu kullanır.

Örneğin, önemli bir olay seviyenin büyük bir bölümünü değiştirirse (örneğin, bir borç tahsildarı dairenizi temizler ve içindeki herkes tutuklanır), tüm odayı benzer görünen ikinci bir oda ile değiştirmek genellikle daha kolaydır.

OTOH, karakterler haritada dolaşıyor ve farklı yerlerde farklı şeyler yapıyorsa, genellikle farklı davranış nesnelerini döndüren tek bir aktörünüz vardır (ör. Düz yürüyün / konuşma yok vs burada durun / Mitch'in ölümü hakkında konuşma). amaçları yerine getirilmişse "gizli".

Bununla birlikte, genellikle el ile oluşturduğunuz bir nesnenin kopyalarına sahip olmak, herhangi bir soruna neden olmamalıdır. Kaç nesne oluşturabilirsiniz? Oyununuz üzerinden dönebileceğinden daha fazla nesne oluşturabilirseniz, "gizli" özelliklerine bakın ve atlayın, motorunuz çok yavaş. Bu yüzden çok fazla endişelenmem. Birçok çevrimiçi oyun aslında bunu yapar. Belirli karakterler veya öğeler her zaman oradadır, ancak karşılık gelen görevi olmayan karakterlere gösterilmez.

Yaklaşımları bile birleştirebilirsiniz: Apartmanınızda iki kapı var. Biri "önce borç tahsildarı" daireye, sonra da daireye götürür. Koridora girdiğinizde, sadece hikayedeki ilerlemeniz için geçerli olan gösterilir. Bu şekilde, "öğe öykünün şu andaki noktasında görünür" ve tek bir hedefe sahip bir kapı için genel bir mekanizmaya sahip olabilirsiniz. Alternatif olarak, değiştirilebilecek davranışlara sahip olabilecek daha karmaşık kapılar yapabilirsiniz ve bunlardan biri "tam daireye git", diğeri "boş daireye git" dir. Gerçekten sadece kapının hedefi değiştiğinde bu saçma görünebilir, ancak görünüşü de değişiyorsa (örneğin, ilk önce kırmanız gereken kapının önünde büyük bir kilit),

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.