Manajemen status permainan (Game, Menu, Layar Layar, dll)

11

Pada dasarnya, dalam setiap gim yang saya buat sejauh ini, saya selalu memiliki variabel seperti "current_state", yang dapat berupa "gim", "layar judul", "layar permainan", dll.

Dan kemudian pada fungsi Pembaruan saya, saya memiliki besar:

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

Namun, saya tidak merasa ini adalah cara yang profesional / bersih dalam menangani negara. Adakah ide tentang cara melakukan ini dengan cara yang lebih baik? Atau apakah ini cara standar?

David Gomes
sumber
Bahasa, kerangka kerja, dll. Apa yang Anda gunakan?
Petr Abdulin
Biasanya Lua + CINTA. Saya juga baru menemukan bahwa kerangka kerja yang berbeda memiliki cara penanganan yang berbeda. SFML tampaknya memiliki kelas Layar yang sangat bagus.
David Gomes
1
Apakah Anda sudah melihat ke mesin negara?
Darcara
1
Anda juga dapat mencari gamestate di bilah pencarian di kanan atas. Harus memberikan beberapa hasil.
TravisG
Harus kedua Darcara - ini persis seperti apa Mesin Negara digunakan untuk.
balajeerc

Jawaban:

14

Karena Anda berbicara tentang layar, saya merasa yang terbaik untuk memisahkan semua logika itu menjadi Layar yang berbeda. Apa yang biasanya saya lakukan:

Tentukan antarmuka yang disebut layar, dan minta beberapa layar menerapkannya. Seperti LoadingScreen, MainMenuScreen, GameScreen, GameOverScreen, HighScoreScreen dll. Dalam game Anda, Anda meletakkan variabel yang memegang layar saat ini. Setiap loop, Anda memanggil screen.update () dan membuat layar saat ini. Ini akan menghemat banyak "jika kondisi ini melakukan itu" karena status Anda ditentukan oleh layar saat ini.

Ini akan memisahkan logika Anda dengan sangat baik.

Kode contoh:

### 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();
    }
}

Atau tergantung pada pengaturan gim Anda, Anda mungkin memiliki perulangan tak terbatas sebagai gim Anda.

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

Jika Anda sudah menggunakan Middleclass, ada perpustakaan mesin-negara yang sangat baik untuk digunakan bersamaan dengan itu disebut Statefull . Mudah digunakan dan mengemukakan gagasan yang sama yang diusulkan Matsemann.

WuTangTan
sumber
2

Jika current_statevariabel Anda adalah string, maka ini sangat mudah di Lua:

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]()
John Calsbeek
sumber
1

Apa yang saya lakukan kira-kira sebagai berikut:

Saya memiliki struktur data grafik asiklik diarahkan , yang pada dasarnya hanya sekelompok node yang saling menunjuk. Setiap node mewakili sistem permainan. misalnya UI, dunia, input, render. Dan setiap node menunjuk pada node lain yang datang sebelum atau sesudahnya. Setelah semua node berada di tempatnya, mudah untuk meratakannya menjadi daftar sederhana. Menyiapkan DAG ini adalah hal pertama yang saya lakukan selama permulaan permainan. Setiap kali saya ingin menambahkan sistem baru, katakan AI, saya bisa saja mengatakan menulis kode itu lalu beri tahu permainan saya apa itu tergantung dan apa yang harus bergantung padanya.

Loop game utama saya muncul setelah itu dan menjalankan setiap sistem secara berurutan. Input pertama ditangani, kemudian pembaruan dunia, lalu hal-hal lain ... UI sudah mendekati akhir, dan rendering adalah yang terakhir. Saat gim pertama kali dimulai, tidak ada dunia atau fisika atau AI, sehingga langkah-langkah tersebut pada dasarnya dilewati, dan hanya layar judul yang ditampilkan. Ketika Anda memulai gim yang tepat, UI mengirim pesan ke sistem dunia untuk dihidupkan, dan itu akan mengurus dirinya sendiri. Mengelola status permainan berarti menghidupkan dan mematikan berbagai sistem. Setiap sistem memiliki rangkaian informasi keadaan sendiri yang ditangani lebih atau kurang secara independen dari semua yang lain (Itu tidak sepenuhnyabenar sebenarnya, banyak sistem bertindak pada set data yang sama - sistem UI misalnya mengambil data dari dunia untuk menampilkan info misalnya. Sistem AI juga perlu melihat dan mengirim pesan ke entitas di dunia).

Alex Ames
sumber
Jawaban ini adalah jawaban yang bagus untuk pertanyaan yang berbeda .
Matsemann
Bagaimana? Dia bertanya bagaimana mengatur berbagai status gimnya, dan solusi saya bukan menggunakan mesin keadaan seperti sekarang, tetapi untuk membagi bit menjadi berbagai sistem yang bukan mesin negara melainkan DAG.
Alex Ames
1

Inilah cara saya mengatur status saya di Lua + Love2d. Ini menghindari pernyataan if / then yang panjang.

Pertama, saya membuat kelas dasar yang berisi metode pembaruan (dt) dan render (). Anda juga bisa memberikannya metode penanganan acara, seperti onKeyDown (kunci). Saya menyebutnya Tahap kelas, tetapi objek apa pun yang mengimplementasikan metode akan bekerja. Lalu, saya membuat instance kelas itu untuk setiap status permainan, menerapkan metode yang diperlukan. Saya kemudian membuat tabel kunci / nilai dengan nama negara dan instance dari negara. Kemudian melacak kondisi saat ini di lingkup global sehingga negara dapat mengubahnya ketika kondisi tertentu terpenuhi.

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
h4tch
sumber
-1

Yah, meskipun tidak cantik, tidak masalah untuk menangani keadaan seperti ini, IMO. Anda dapat membuatnya lebih bersih menggunakan fungsi untuk setiap negara, seperti:

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

atau sesuatu yang lain mengganggu Anda dalam pendekatan ini (maksud saya kecuali bahwa metode Pembaruan sangat panjang)?

Petr Abdulin
sumber