Oyun durumu yönetimi (Oyun, Menü, Başlık ekranı vb.)


11

Temel olarak, şimdiye kadar yaptığım her oyunda, "current_state" gibi her zaman "game", "titlescreen", "gameoverscreen" vb. Olabilen bir değişkenim var.

Ve sonra Güncelleme fonksiyonumda çok büyük bir var:

if current_state == "game" 
  game stuf
  ...
else if current_state == "titlescreen"
  ...

Ancak, bu durumları ele almanın profesyonel / temiz bir yolu olduğunu düşünmüyorum. Bunun nasıl daha iyi bir şekilde yapılacağı hakkında bir fikriniz var mı? Yoksa bu standart bir yol mu?


Hangi dili, çerçeveyi vb. Kullanıyorsunuz?
Petr Abdulin

Genellikle Lua + LOVE. Ayrıca farklı çerçevelerin bunu ele almak için farklı yolları olduğunu keşfettim. SFML'nin çok güzel bir Screen sınıfı var gibi görünüyor.
David Gomes

1
Devlet makinelerine baktın mı?
Darcara

1
Oyun sitelerini ayrıca sağ üstteki arama çubuğunda da arayabilirsiniz. Bazı sonuçlar vermeli.
TravisG

İkinci Darcara olmalı - bu Devlet Makinelerinin tam olarak ne için kullanıldığı gibi görünüyor.
balajeerc

Yanıtlar:


14

Ekranlardan bahsettiğiniz için, tüm bu mantığı farklı Ekranlara ayırmanın en iyisi olduğunu düşünüyorum. Normalde ne yaparım:

Ekran adı verilen bir arabirim tanımlayın ve birden çok ekranın onu uygulamasını sağlayın. LoadingScreen, MainMenuScreen, GameScreen, GameOverScreen, HighScoreScreen vb. Oyunda mevcut ekranı tutan bir değişken koyarsınız. Her döngüde, screen.update () öğesini çağırır ve geçerli ekranı oluşturursunuz. Durumunuz geçerli ekran tarafından tanımlandığı için bu size çok fazla "bu durum bunu yaparsa" kazandırır.

Bu, mantığınızı çok güzel bir şekilde ayıracaktır.

Örnek kod:

### Screen interface ###
public interface Screen {

    public void show();

    public void update(float delta);

    public void render(float delta);

    public void hide ();
}

### An implementation of screen ###
public class MainMenuScreen implements Screen {

    private Game game;

    public MainMenuScreen(Game game) {
        this.game = game;
    }

    public void show() {
        // init stuff
    }

    public void update(float delta) {
        // react to clicks, update animations etc.
        if (buttonwasclicked) {
            game.setScreen(new GameScreen(game)); // change the screen
        }
    }

    public void render(float delta) {
        // draw everything
    }

    public void hide() {
        // release all resources, as the screen is being hidden
    }
}

### Game, drawing the appropriate screen ###
public class Game {

    public Screen screen;

    public void update() {
        screen.update(getDeltaTime);
        screen.render();
    }

    public void setScreen(Screen screen) {
        this.screen.hide();

        this.screen = screen;
        this.screen.show();
    }
}

Veya oyun kurulumunuza bağlı olarak, oyununuz olarak sonsuz bir döngüye sahip olabilirsiniz.

while(true) {
    calculatetimesincelastframe()
    screen.update(time);
    screen.render(time);
}

5

Zaten Middleclass kullanıyorsanız, onunla birlikte Statefull adı verilen mükemmel bir devlet-makine kütüphanesi var . Kullanımı kolaydır ve Matsemann'ın önerdiği fikirlerin aynısını sunar.


2

Senin Eğer current_statedeğişken bir dize, o zaman bu Lua gerçekten kolaydır:

game_states = {}
function game_states.game()
    -- game stuff
end
function game_states.titlescreen()
    -- title screen stuff
end

-- then, inside the Update function:
game_states[current_state]()

1

Yaptığım şey kabaca şöyle:

Bir sahip yönlendirilmiş asiklik grafik esasen birbirine nokta düğümleri sadece bir grup olan bir veri yapısı. Her düğüm bir oyun sistemini temsil eder. UI, dünya, girdi, oluşturma gibi. Ve her bir düğüm kendisinden önce veya sonra gelen diğer düğümleri gösterir. Tüm düğümler yerleştirildikten sonra, basit bir listeye düzleştirmek kolaydır. Bu DAG'ı kurmak oyunun başlangıcında yaptığım ilk şey. Yeni bir sistem eklemek istediğimde, AI diyorum, sadece bu kodu yaz diyebilirim ve oyunuma neye bağlı olduğunu ve neye bağlı olması gerektiğini söyleyebilirim.

Ana oyun döngüm bundan sonra geliyor ve her sistemi sırayla çalıştırıyor. İlk girdi işlenir, sonra dünya güncellenir, sonra diğer şeyler ... Kullanıcı arabirimi sona yaklaşıyor ve oluşturma son. Oyun ilk başladığında, dünya veya fizik ya da yapay zeka yoktur, bu nedenle bu adımlar esasen atlanır ve sadece başlık ekranı görüntülenir. Oyuna uygun şekilde başladığınızda, UI dünya sistemine açılmak için bir mesaj gönderir ve sadece kendi kendine ilgilenir. Oyun durumunu yönetmek sadece çeşitli sistemleri açmak ve kapatmak anlamına gelir. Her sistemin, diğerlerinden daha fazla veya daha az bağımsız olarak ele alınan kendi durum bilgisi kümesi vardır (Bu tamamen değiltrue aslında, birçok sistem aynı veri kümesi üzerinde hareket eder - örneğin UI sistemi, örneğin bilgileri görüntülemek için dünyadan veri alır. AI sisteminin ayrıca dünyadaki varlıklara bakması ve mesaj göndermesi gerekir).


Bu cevap farklı bir soruya iyi bir cevaptır .
Matsemann

Nasıl yani? Çeşitli oyun durumlarını nasıl kuracağını sordu ve benim çözümüm şu anda olduğu gibi bir durum makinesi kullanmak değil, bunun yerine bitleri bir durum makinesi değil, bir DAG olan çeşitli sistemlere ayırmak.
Alex Ames

1

Lua + Love2d'de eyaletlerimi şu şekilde organize ederim. Uzun if / then deyimlerini önler.

İlk olarak, bir update (dt) ve render () yöntemleri içeren temel bir sınıf oluşturuyorum. Ayrıca onKeyDown (anahtar) gibi olay işleme yöntemleri de verebilirsiniz. Bu sınıfa Stage diyorum, ancak yöntemleri uygulayan herhangi bir nesne çalışacaktır. Daha sonra, her oyun durumu için gerekli sınıfları uygulayarak o sınıfın bir örneğini yapıyorum. Sonra devletin adı ve devlet örneği ile bir anahtar / değer tablosu oluşturun. Ardından, geçerli bir durumu karşıladığında durumların değiştirebilmesi için currentState'i global kapsamda takip edin.

states = {}
states["title"] = title   -- Where title implements Stage class.
states["game"] = game     -- You could create the instance of 'game' lazily too.
currentState = "title"

function love.update(dt)
    if states[currentState] ~= nil then
       states[currentState]:update(dt) 
    end
end

-1

Pekala, durumları bu şekilde işlemek sorun değil, IMO. Her durum için işlevleri kullanarak çok daha temiz hale getirebilirsiniz, örneğin:

if current_state == "game" 
  game()
else if current_state == "titlescreen"
  titlescreen()

ya da başka bir şey bu yaklaşım sizi rahatsız (yani güncelleme yöntemi çok uzun hariç)?

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.