Autor Wątek: [C++]Zapis stanu gry  (Przeczytany 4721 razy)

Offline snajper_44

  • Użytkownik

# Październik 30, 2010, 21:47:10
Witam! Jestem początkującym programmerem. Piszę sobie pseudo grę w konsoli. Już trochę w miare jest ~500 linijek. Usiłuję zrobić zapis stanu gry, lecz nie wiem jak się do tego zabrać wiem jak odczytać zmienne itp. ale jak powrócić do danego fragmentu kodu? Narazie stworzyłem coś takiego:
void SaveGame(character &Hero)
{
    ofstream osave;
    osave.open("frpg_dbsv", ios::out);
    osave << Hero.name << "\n" << Hero.hp << "\n" << Hero.MinDmg << "\n" << Hero.MaxDmg << "\n" << Hero.lvl << "\n" << Hero.exp << "\n" << Hero.atk;
    osave.close();
};

void LoadGame(character &Hero)
{
    fstream isave("frpg_dbsv", ios::in);
    getline(isave, Hero.name);
    isave.close();
};

int main(int argc, char *argv[])
{
    //blablabla
    cout << "-+-+-+-+-+TRYB+-+-+-+-+-" << endl;
        cout << "Wybierz tryb:" << endl;
        cout << " 1. Nowa gra" << endl;
        cout << " 2. Wczytanie gry" << endl;
        cin >> game;
        if (game == 2)
        {
            LoadGame(Hero);
        }
        if (game == 1)
        //blablabla
        SaveGame(Hero);

Jak widać Hero to obiekt klasy. I moje pytanie jak zrobić właśnie żeby skoczyć po wczytaniu do danego fragmentu? Proszę o pomoc.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline FoToN

  • Użytkownik

# Październik 30, 2010, 21:52:17
Najprościej byłoby otworzyć plik binarnie (std::ios::binary) i wpakować od razu całą klasę. Takie rozwiązanie daje Ci też możliwość łatwego wczytywania. Ważne tylko byś w klasie bohatera nie trzymał np. std::string, tablic, bo wtedy takie rozwiązanie nie zda egzaminu.

Offline snajper_44

  • Użytkownik

# Październik 30, 2010, 21:57:03
Ok, lecz to tylko 1/2 odpowiedzi, mi bardziej chodzi oto, że po wywołaniu funkcji LoadGame() załadował by się no nie wiem etykieta? fragmentu kodu i tam by historia była kontunuowana. Zapisać do pliku gdzie jestem to raczej łatwo nawet integerem i dać komenta, że x to gdzieś a y gdzieś.

Offline Kos

  • Użytkownik
    • kos.gd

# Październik 30, 2010, 22:01:42
Dla gry realtime (well, dla jakiejkolwiek gry z pętlą główną) nie ma potrzeby wracać do tego samego "miejsca w kodzie", bo to się robi samo. Przerywasz grę gdzieś w mainloopie (np. przy eventach), zapisujesz dane, a przy wczytywaniu przywracasz stan gry i odpalasz ponownie pętlę główną - tyle.

A może Twoja gra nie ma pętli głównej i stąd problem?

Offline Xirdus

  • Redaktor

# Październik 30, 2010, 22:02:07
Tak jak powiedział FoToN, zapisuj binarnie. Ja polecam taki sposób: w pierwszej linii wszystkie inty i podobne, a stringi jeden na linię, na początku każdej linii ze stringiem dajesz inta z rozmiarem.

Plik wyglądałby mniej więcej tak:
[lvl][exp][hp]
[size]Imię bohatera

(za chwilędam przykładowy kod)

A co do zaczynania w miejscu gdzie się skończyło, to po prostu zapisz miejsce, gdzie się skończyło (pole mapy, stage, cokolwiek).

Offline Kos

  • Użytkownik
    • kos.gd

# Październik 30, 2010, 22:03:11
@Xirdus - ale kolega napisał, że nie chodzi mu o dane, nie powtarzaj Fotona :)

Offline FoToN

  • Użytkownik

# Październik 30, 2010, 22:07:27
Zapisywanie stanów przykładowo questów możesz zrobić tak:

// Nagłówek pliku
struct NaglowekPliku
{
       (...)
       unsigned int LiczbaQuestow;
       unsigned int OffsetDoPierwszegoQuesta;
       (...)
};

struct Quest
{
      Tutaj id questu, nazwa lub co tam chcesz
      unsigned int EtapQuestu;
};

Opis:
W nagłówku masz liczbę questów i offseta do pierwszego questa. Przesuwasz wskaźnik pobierania na tenże offset i  zaczynasz pobieranie stanu questów. Pobierasz tyle questów, że AktualnyQuest < LiczbaQuestow.
Oczywiście w pliku możesz, a nawet musisz trzymać inne informacje. Robisz to analogicznie do questów.
« Ostatnia zmiana: Październik 30, 2010, 22:09:12 wysłana przez FoToN »

Offline snajper_44

  • Użytkownik

# Październik 30, 2010, 22:18:11
Wiem, że to zabrzmi głupio, ale nie rozumiem Was. Sorry jak powiedziałem moje c++ = 7 dni (wcześniej 3 miechy Pascala) Jak wziąść rozmiar stringa czy o co tam chodziło? Ja pomyślałem tak i mam takie coś: co ileś tam czasu będzie można wybrać zapis tak/nie, tak - zapisz grę (zmienne itp., chapter = 1). Potem w LoadGame() jeżeli chapter == 1 to przejdź do etykiety 'xyz' ale teraz następne pytanie. To będzie ujęte w funkcji Load i Save [Game] a jak odwołać się do etykiety funkcji main()? Przekazać parametry? Czy jak?

Offline Kos

  • Użytkownik
    • kos.gd

# Październik 30, 2010, 22:21:03
Cytuj
Sorry jak powiedziałem moje c++ = 7 dni (wcześniej 3 miechy Pascala)

To dużo. Powinieneś móc mi odpowiedzieć, jak jest zbudowany control flow w Twojej grze? Bez tego nie poradzimy.

Offline snajper_44

  • Użytkownik

# Październik 30, 2010, 22:24:09
What is control flow?! Mogę Ci podać co chcesz, lecz ty masz dośw. w programowaniu pewnie z 5+ lat a ja? I mi tu z control flowem wyjeżdzasz? :D Podać Ci funkcję main()? czy co i jak?

Offline siso

  • Użytkownik

# Październik 30, 2010, 22:28:38
Coś mi się widzi, drogi Kolego, że flow masz w całości w kodzie, hmmm, zakodowany :)
W którejś części "Perełek..." jest rozdział "Magia sterowania danymi" czy jakoś tak. Gdybyś odseparował kod od danych, to dane te byłyby właśnie stanem gry. Jeśli masz logikę rozgrywki w kodzie, to zapisz tylko te dane, które na rozgrywkę wpływają, jak radzi Kos, i po bajce.

Jeśli chcesz wiedzieć, gdzie wrócić po wczytaniu, możesz zastosować system checkpoint'ów. Zapis będzie możliwy jedynie w checkpointach, ale wtedy checkpoint jest elementem zapisu. Wczytujesz i jedziesz od tego czheckpointa dalej.

Jakoś tak...

PS.
Flow - to po prostu przepływ, czyli wszystko to, co robi Twój kod, co można by nazwać logiką biznesową, ale z punktu widzenia wykonania, nie definicji. Czyli ciąg wywołań po prostu :)

Offline Xirdus

  • Redaktor

# Październik 30, 2010, 22:29:31
Jak wybierasz chapter na początku gry? I jak potem wybierasz kolejny?

Offline snajper_44

  • Użytkownik

# Październik 30, 2010, 22:32:01
chapter = 1; Po walce z wilkiem :D i zapis odrazu do pliku zmienne i na końcu chapter. I jak LoadGame to jeżeli chapter == 1 przejście do etykietki np. po_walce_wilk; Tylko jak przekazać etykietę z funkcji do main?
EDIT:
Mogę wam wstawić cały kod i program nawet;
http://www.wklej.org/id/409845/
« Ostatnia zmiana: Październik 30, 2010, 22:36:31 wysłana przez snajper_44 »

Offline Xirdus

  • Redaktor

# Październik 30, 2010, 22:44:11
Odrzucając możliwość kompletnego refactoringu, zrób po prostu switcha:
switch (chapter)
{
    case 1: goto adventure;
    case 2: goto przed_wioska;
    case 3: goto wioska;
    // i tak dalej
}

Offline snajper_44

  • Użytkownik

# Październik 30, 2010, 22:52:52
Wiem już, dzięki wszyskim za pomoc  8) switch się przyda, ale teraz szukałem na necie i nie znalzazłem nic sensownego. A więc jak zrobić wczytywanie kilku linii lub pojednyczo po kolei, mam to: getline(isave, Hero.name); Ale wiadomo wczytuje tylko jedną pierwszą linijkę, a ja chce wszystkie jak odczytać te linijki??