Ekran ayarlarını yeniden başlatmadan Seçenekler ekranından nasıl güncelleyebilirim?


9

Şu anda Allegro 5 ve boost ile C ++ 11'de bir 2D RPG oluşturuyorum.

Amacım, Seçenekler Menüsünde bir seçenek değiştirildiğinde oyun ayarlarımı bir şekilde güncellemektir. Kullanıcıyı oyunumu yeniden başlatmaya zorlamak istemiyorum. Diğer oyunlar çözünürlüğü değiştirirken veya tam ekrandan pencereye geçerken yeniden başlatılmasını gerektirmez, bu yüzden oyunum da olmamalıdır. Lütfen aşağıdaki sistemin basitleştirilmiş bir görünümüne bakın.

Lütfen Oyun nesnesimi doğrudan OptionsScreen'den çağırmak istemediğimi unutmayın. Kesik çizgi sadece elde etmeye çalıştığım etkiyi göstermek içindir; bir şekilde sistemin farklı bir bölümünde bir seçenek değiştirildiğinde oyunun güncellenmesine neden olabilir.

Detaylı açıklama

ScreenManager GameScreenmevcut durumda olan tüm nesnelerin bir listesini içerir . Bunlar, pop-up'lar da dahil olmak üzere oyunda çeşitli ekranlar olacak. Bu tasarım , C # / XNA'daki Oyun Durumu Yönetimi örneğine az çok yapışır .

Bu ScreenManager, nesneme bir başvuru içeriyor Game. GameNesne başlangıç durumuna getirilir ve değiştirir oyunun ayarları. Çözünürlüğü değiştirmek, tam ekrana geçmek veya Gamesınıfta yapacağım ses seviyesini kapatmak istersem .

Ancak, OptionsScreen şu anda Game sınıfına erişemiyor. Aşağıdaki şemaya bakın:

Bir GameScreen üç olaya işaret edebilir onFinished, onTransitionStartve onTransitionEnd. Hayır, onOptionsChangedçünkü bunu sadece bir ekran yapar. ScreenManager bunun için olay işlemeyi ayarlayamaz çünkü tüm ekranları GameScreens olarak işler .

Sorum şu: Tasarımımı nasıl değiştirebilirim ki OptionsMenu'daki bir değişiklik yeniden başlatma gerektirmez, ancak hemen değiştirilir? Tercihen Gameuygula düğmesine tıklandığında nesnemin güncellenmesini rica ediyorum .


Bu soru (oyunla ilgili olmasına rağmen) gerçek oyundan ziyade genel OO tasarımı hakkında daha fazla çünkü programcılar için mükemmel bir uyum gibi görünüyor
bughi

Bu kadar güzel görünen grafikleri nereden buldun?
joltmode

@psycketom: Birincisi Visio 2013'ten, ikincisi VS2012 tarafından koddan üretildi. Umarım yardımcı olur!
IAE

Yanıtlar:


1

Gördüğüm kadarıyla, en kolay yaklaşım, mevcut ekran ayarlarını belirlemek için başlangıçta bir seçenekler dosyasını okumaktır; ardından seçenekler ekranınız görüntülendiğinde, geçerli tüm seçenekleri bir dosyadan yükleyin.

Değişiklikler bir applyveya okdüğmesi ile sonlandırıldığında , bir dosyaya geri kaydedilir. Herhangi bir değişiklik görüntüyü etkiliyorsa, etkili olması için kullanıcıyı oyunun yeniden başlatılması gerektiğini bildirin.

Oyun yeniden başlatıldığında, (şimdi yeni) görüntü ayarları dosyadan tekrar okunur.

--DÜZENLE--

Ve ... bu son cümleyi fark etseydim yardımcı olurdu. Yeniden başlatmak zorunda değilsiniz. Uygulamanıza ve arka uç Grafik Kütüphanenize bağlı olarak işleri biraz daha zorlaştırır.

IIRC, Allegro, ekran ayarlarını anında değiştirmenizi sağlayan bir işlev çağrısına sahiptir. Henüz Allegro 5 için hazır değilim, ama 4'te yapabileceğini biliyorum.


Sorunun Allegro ve yetenekleri ile ilgili olduğunu düşünmüyorum. "Sorum şu: Tasarımımı nasıl değiştirebilirim ki OptionsMenu'daki bir değişiklik yeniden başlatma gerektirmez, ancak hemen değiştirilir?" Yeniden başlatma, "OptionsScreen'in şu anda Oyun sınıfına erişememesi" ve doğru anladığımda bunları ayar dosyasından yüklemesi gerektiğidir.
ClassicThunder

@Casey: Merhaba Casey! :) Evet, ilgili görüntüleme verilerini saklamak için bir yapılandırma dosyası kullanıyorum, ancak yeniden başlatmayı önlemek istiyorum. Bu küçük bir oyun ve diğer oyunlar yeniden başlatmaya gerek kalmadan çözünürlüğü değiştirebilir, bu yüzden kullanıcıyı neden benimkini yeniden başlatmaya zorlamam gerektiğini anlamıyorum. Bu bir kullanılabilirlik sorunu. Allegro dispay fonksiyonlarını çağırabilirken, OOP kalmaya çalışıyorum ve grafik çağrılarımı sadece yapabildiğim için karıştırmıyorum; Bu iyi tasarımı düşünmüyorum.
IAE

Diğerleri aynı son cümle üzerinde trip yok böylece "yeniden başlatma olmadan" bit vurguladı. Böyle önemli bir gerçeğin sonunda olmaması gerekirdi, özür dilerim):
IAE

@SoulBeaver Yeniden başlatmamak için bunu yapmanız gerektiğini kim söyledi ? Bunu talep etmek uygun bir şey, aslında gün geçtikçe daha yaygın hale geliyor . Büyük bütçeli oyunların son sürümlerinden bazılarının (XCOM: Enemy Unknown, Skyrim, vb.) Yeniden başlatılması gerekir. (Steam'de olmaları, sunucu tarafı seçeneklerinin senkronizasyonu nedeniyle suçlu olabilir, ancak oraya
Casey

1
@Casey: Doğru ve bazı seçenekler için bunun neden gerekli olduğunu görebiliyorum, ancak tam ekran / pencereli veya ekran çözünürlüğü gibi şeyler için? Bu ayarlar için yeniden başlatma gerektiren bir oyun görmedim. Temel sorum şu: Oyun ayarları otomatik olarak değiştirebildiğinde neden kullanıcılarımı yeniden başlatmaya zorlamalıyım?
IAE

1

Oyunum için yaptığım şey bu. Öğeleri başlatmak için 'init' ve 'reset' olmak üzere 2 ayrı fonksiyonum var. Init başlangıçta yalnızca bir kez çağrılır ve ana varlıkların yüklenmesi gibi ayarlara dayanmayan şeyler yapar. Sıfırlama, kullanıcı arayüzünü ekran çözünürlüğüne göre düzenlemek gibi şeyler yapar, bu nedenle ayarlar her değiştiğinde çağrılır.

init();
bool quit = false;
while( !quit )
{
    createWindow();
    reset();

    bool settings_changed = false;
    while( !quit && !settings_changed )
    {
        ... main loop
        // set quit=true if user clicks 'quit' in main menu
        // set settings_changed=true if user clicks 'apply' in options
    }

    destroyCurrentWindow();
}

Allegro'ya aşina değilim, ama cevabım oldukça genel, bu yüzden umarım size veya benzer bir problemi olan herkese yardımcı olur.


Bu ilginç bir çözüm. Bir sıfırlama çağrıldığında sıkı bir kontrol sahibi olmaya çalışıyordum, ancak bir değişiklikten bağımsız olarak bunu yapıyorsunuz. Bu kesinlikle uygulayabileceğim bir şey ve içine bakacağım, teşekkürler!
IAE

1

Mevcut mimarinizi bozmadan iki yol görüyorum. İlk olarak, sınıftaki Gameörneğe bir işaretçi depolayabilirsiniz OptionsScreen. İkinci olarak, Gamesınıf belirli bir aralıkta geçerli ayarları alabilir, örneğin her saniye.

Yeni ayarlara gerçekten uyum sağlamak için, Gamesınıfın geçerli ayarları getiren ve bunlara göre yeniden başlatan bir tür sıfırlama işlevi uygulaması gerekir.

Temiz bir çözüm için bir tür küresel yöneticiye ihtiyacınız var, bu yüzden uygulamak daha fazla çaba. Örneğin bir olay sistemi veya mesajlaşma sistemi. Sınıfların, toplama veya kompozisyon gibi güçlü bağlar olmadan iletişim kurmasına izin vermek çok yararlıdır.

Küresel bir olay yöneticisi ile, daha önce dinlemek için kayıtlı OptionsScreenolan yeniden çizim etkinliğini küresel olarak tetikleyebilir Game.

Genellikle karma bir haritada dinleyen olayları ve geri çağrıları depolayan bir yönetici sınıfı uygulayabilirsiniz. Daha sonra bu yöneticinin tek bir örneğini oluşturabilir ve işaretçileri bileşenlerinize iletebilirsiniz. std::unordered_mapKarma harita olarak kullanabileceğiniz ve std::functiongeri çağrıları depolayabileceğiniz için daha yeni C ++ kullanmak oldukça kolaydır . Anahtar olarak kullanabileceğiniz farklı yaklaşımlar vardır. Örneğin, bileşenleri daha bağımsız hale getiren olay yöneticisi dizesini temel alabilirsiniz. Bu durumda std::string, karma haritada anahtar olarak kullanabilirsiniz . Şahsen bunu seviyorum ve kesinlikle bir performans sorunu değil, ancak geleneksel etkinlik sistemlerinin çoğu olaylarla sınıf olarak çalışır.


Merhaba danijar. Ben zaten ilkel olay işleme şeması ayarlamak için boost :: sinyalleri kullanıyorum. GameScreen'den ScreenManager'a giden güçlü çizgi aslında o olay işlemedir. Küresel bir etkinlik yöneticisinin mimarisini detaylandıran kaynaklarınız var mı? Daha fazla iş olsun veya olmasın, bu temiz bir uygulamaya yol açabileceği gibi görünüyor.
IAE

Bununla ilgili herhangi bir araştırma okumamış olmama rağmen, kendi küçük motorum için küresel bir etkinlik etkinlik yöneticisi uyguladım. Eğer uygulama ile ilgileniyorsanız, size bir link göndereceğim. Cevabımı daha fazla ayrıntı içerecek şekilde güncelledim.
danijar

1

Bu, Gözlemci modelinin belirli bir örneğidir.

Geri çağrıları içeren bir çözüm var. Gevşek bir bağlantı istiyorsanız bunu yapmanın en iyi yolu budur ve bence bu da en temiz olanıdır. Bu herhangi bir küresel yönetici veya singleton içermez.

Temel olarak, bir çeşit olması gerekir SettingsStore. Orada ayarları kaydedersiniz. Yeni bir ekran oluşturduğunuzda, mağazaya bir işaretçi gerekir. Bu durumda OptionsScreen, ayar değerinin bazılarını kendisi değiştirecektir. Bu durumda GameScreensadece onları okuyacak. Yani, oyununuzda, bir tane gerektiren tüm ekranlardan geçirilecek tek bir örnek oluşturacaksınız.

Şimdi, bu SettingsStoresınıfın bir listesi olacaktır notifiables. Belirli bir ISettingChangedarabirimi uygulayan sınıflardır . Arayüz, aşağıdaki yöntemi içeren basit bir arayüz olacaktır:

void settingChanged(std::string setting);

Ardından ekranınızda, önem verdiğiniz her ayar için mantığı uygulayacaksınız. Ardından, mağazaya eklenin bildirilmesini: store->notifyOnChange(this);. Bir ayar değiştirildiğinde, ayar adıyla geri arama çağrılır. Daha sonra yeni ayar değeri SettingsStore.

Şimdi, bu aşağıdaki fikirlerle daha da artırılabilir:

  • Ayar dizelerini saklayan bir sınıf kullanın - SettingsStoreetrafına kopya yapıştırma dizelerini önlemek için (const dizeleri bile olabilir ).
  • Daha da iyisi, bir dize yerine, hangi ayarlara sahip olduğunuzu belirtmek için bir numaralandırma kullanın
  • Eski ve yeni değerleri geri çağrıda argüman olarak bile belirtebilirsiniz, ancak dize veya int değerleriniz olabilir ya da olmasın, bu daha karmaşık olur. Sana kalmış.

0

Ayarlarınızı bir dosyadan değişkenlere okuyun. Ekran Yöneticinizin henüz geldiği ekranın Seçenekler ekranı olup olmadığını takip etmesini sağlayın ve öyleyse ayarlarınızı değişkenlerden yeniden yükleyin. Kullanıcı oyununuzdan çıkarken, değişkenlerdeki ayarları dosyaya geri yazın.

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.