Сохранение в игре.
Модераторы: Sanja, Максим Кич
Сохранение в игре.
Возник вопрос - как сделать сохранение в игре? Да и просто при генерации следующего уровня как предыдущий сохранить в файл? Ведь наверняка уже есть наработанные решения поданному вопросу, не хотелось бы запросто изобретать велосипед. Вопрос относится к языку С++.
Сложность в том, что надо несколько массивов различных данных загнать в один файл, причем некоторые массивы - динамические,а кроме того еще есть и списки <list>. Пока с трудом представляю, как это сделать.
И еще вопрос - если каждый тайл карты будет содержать несколько полей плюс список вещей лежащих на клетке карты. Этот список может быть пустой, а может и содержать ID вещей. Т.е. получается что каждая клетка карты занимает разное место в памяти. Тогда выходит, что записать в файл то в принципе получится, а вот корректно всё это дело считать - уже будет сложно. Т.е. надо писать метод, который будет всю нужную информацию загонять в отдельный единый массив тех же char, а его уже писать в файл, ну и в начале файла добавить всю служебную информацию, списки вещей на клетках писать отдельно единым куском данных. Ну а при считывании проводить обратные преобразования.
Сложность в том, что надо несколько массивов различных данных загнать в один файл, причем некоторые массивы - динамические,а кроме того еще есть и списки <list>. Пока с трудом представляю, как это сделать.
И еще вопрос - если каждый тайл карты будет содержать несколько полей плюс список вещей лежащих на клетке карты. Этот список может быть пустой, а может и содержать ID вещей. Т.е. получается что каждая клетка карты занимает разное место в памяти. Тогда выходит, что записать в файл то в принципе получится, а вот корректно всё это дело считать - уже будет сложно. Т.е. надо писать метод, который будет всю нужную информацию загонять в отдельный единый массив тех же char, а его уже писать в файл, ну и в начале файла добавить всю служебную информацию, списки вещей на клетках писать отдельно единым куском данных. Ну а при считывании проводить обратные преобразования.
- Jesus05
- Сообщения: 1840
- Зарегистрирован: 02 дек 2009, 07:50
- Откуда: Норильск, сейчас Санкт-петербург.
- Контактная информация:
Re: Сохранение в игре.
Я использовал JSON когда реализовывал сохранение, но мой JSON-велосипед получился медленным
А вообще читай про рефлексию в сях https://habrahabr.ru/post/277329/
Насколько я понимаю без кодогенерации тут не обойтись.
Пробовал когда-то разобраться с https://en.wikipedia.org/wiki/ODB_(C%2B%2B) но там тоже рефлексия, и свой дополнительный прекомпилятор который занимается кодогенерацией. (по идеи ODB + SQLite и бд в файле будет достаточно для сохранений)
Самый быстрый но самый неправильный способ это тупо сваливать данные класса в файл как есть.
write(file, &someCLassInstance, sizeof(someCLassInstance));
но надо помнить во время загрузки про таблицы виртуальных методов, про указатели\ссылки. в общем так можно хранить только простые данные.
как вариант можно отделить данные от поведения... делать классы:
someclassdata
{
int ...;
char ...;
someotherclassdata ...;
}
someclass
{
someclassdata ...;
поведение
}
и сохранять соответсвенно только классы данных и не трогать классы поведения.
но опять-же не забывать про указатели, умные указатели, и все остальные подвиды ссылок.
А вообще читай про рефлексию в сях https://habrahabr.ru/post/277329/
Насколько я понимаю без кодогенерации тут не обойтись.
Пробовал когда-то разобраться с https://en.wikipedia.org/wiki/ODB_(C%2B%2B) но там тоже рефлексия, и свой дополнительный прекомпилятор который занимается кодогенерацией. (по идеи ODB + SQLite и бд в файле будет достаточно для сохранений)
Самый быстрый но самый неправильный способ это тупо сваливать данные класса в файл как есть.
write(file, &someCLassInstance, sizeof(someCLassInstance));
но надо помнить во время загрузки про таблицы виртуальных методов, про указатели\ссылки. в общем так можно хранить только простые данные.
как вариант можно отделить данные от поведения... делать классы:
someclassdata
{
int ...;
char ...;
someotherclassdata ...;
}
someclass
{
someclassdata ...;
поведение
}
и сохранять соответсвенно только классы данных и не трогать классы поведения.
но опять-же не забывать про указатели, умные указатели, и все остальные подвиды ссылок.
Re: Сохранение в игре.
JSON-велосипед писал построчно в файл?
Т.е. для записи состояния игры нужны были десятки тысяч обращений к жесткому диску? Ежели да, то это выходит весьма медленно.
Большие объемы данных лучше писать одним куском в бинарном режиме.
Т.е. для записи состояния игры нужны были десятки тысяч обращений к жесткому диску? Ежели да, то это выходит весьма медленно.
Большие объемы данных лучше писать одним куском в бинарном режиме.
Re: Сохранение в игре.
О, нашел вроде хорошую статью про сериализацию данных, изучаю.
http://procplusplus.blogspot.ru/2012/12/c.html
http://procplusplus.blogspot.ru/2012/12/c.html
- Jesus05
- Сообщения: 1840
- Зарегистрирован: 02 дек 2009, 07:50
- Откуда: Норильск, сейчас Санкт-петербург.
- Контактная информация:
Re: Сохранение в игре.
Все не настолько плохо я собирал данные в памяти, а потом уже ложил их на диск.
вот код... много кода последняя правка была в 15 году.
Скрытый текст: ПОКАЗАТЬ
именно для JSON по работе использую RapidJson.
- Максим Кич
- Администратор
- Сообщения: 1642
- Зарегистрирован: 03 дек 2006, 20:17
- Откуда: Витебск, Беларусь
- Контактная информация:
Re: Сохранение в игре.
Ни разу не сишник, но думаю, что решения как минимум на каком-то уровне примерно схожие.
Сериализация в JSON/XML. Рекурсивно. Каждый игровой объект должен уметь сериализовать себя с обходим принадлежащих ему объектов и десериализовать себя (и/или своё добро) из строки. Куда потом писать это — не принципиально. Можно на диск, можно в базу, можно на сервер отправлять.
Имхо, оверкилл. Реляционная БД, как мне кажется, имеет смысл на сервере, если между игроками есть возможность обмениваться вещами/персонажами и т.д. А так смысла нет от слова «никакого». Вложенные структуры из реляционной БД восстанавливать — тоже удовольствие не для слабых духом. Даже если делать удалённое сохранение, но при этом между пользователями никаких взаимодействий не планируется от слова «никогда» — имеет смысл брать NoSQL типа Redis-а или MongoDB и тупо туда сгружать одной записью/документом JSON.
Dump the screen? [y/n]
Re: Сохранение в игре.
Да, это я уже прочитал и в других источниках - что каждый класс должен сам уметь себя сериализовать и собирать обратно. Что в общем то логично.Максим Кич писал(а): ↑07 фев 2017, 09:10
Сериализация в JSON/XML. Рекурсивно. Каждый игровой объект должен уметь сериализовать себя с обходим принадлежащих ему объектов и десериализовать себя (и/или своё добро) из строки. Куда потом писать это — не принципиально. Можно на диск, можно в базу, можно на сервер отправлять.
В общем то уже что-то намечается, до разработки самого сохранения еще далеко, думаю к тому времени уже надумаю рабочий алгоритм.
Re: Сохранение в игре.
На самом деле самое сложное в сериализации это циклические зависимости.
Я делал свой велосипед. Бинарный. Получается очень быстро
Я делал свой велосипед. Бинарный. Получается очень быстро
Re: Сохранение в игре.
sqlite кстати неплохо подходит для сохранения в файл. Даже больше подходит именно для сохранения в файл, нежели в роли клиент-серверной реляционной субд. Но в целом - нафиг он нужен, если можно просто сериализовать бинарно.
В редакторе сериализовал в xml, чтоб быть уверенным, что если весь сейв навернётся, то я хоть что-то смогу вытащить. А обычные сейв-файлы вполне можно в бинарном виде. Особенно если не сильно париться вопросами совместимости между версиями.
Как у меня было сделано : есть класс Serializator, а каждый класс имеет метод Serialize(Serializator *sler), который рекурсивно будет всё содержимое сериализовать, ну, как обычно. Загрузка и сохранение проходят в два этапа. Это нужно, чтобы сериализовать указатели. На этапе сохранения в первом проходе каждому объекту присваивается serId, который увеличивается на единицу каждый раз, на втором проходе собственно сохраняются указатели. при загрузке первым проходом все объекты создаются, а указатели инициализируются на втором проходе. Разумеется, нужна рефлексия, что-то типа NewObjectById(int obId).
Главное, чётко определить, где нужно сериализовать сам объект, а где просто указатель на него.
Как это выглядит:
Работает как часы, без нареканий. (Периодически что-то где-то ломалось или забывалось изза внутренних косяков, но быстро чинилось.)
В редакторе сериализовал в xml, чтоб быть уверенным, что если весь сейв навернётся, то я хоть что-то смогу вытащить. А обычные сейв-файлы вполне можно в бинарном виде. Особенно если не сильно париться вопросами совместимости между версиями.
Как у меня было сделано : есть класс Serializator, а каждый класс имеет метод Serialize(Serializator *sler), который рекурсивно будет всё содержимое сериализовать, ну, как обычно. Загрузка и сохранение проходят в два этапа. Это нужно, чтобы сериализовать указатели. На этапе сохранения в первом проходе каждому объекту присваивается serId, который увеличивается на единицу каждый раз, на втором проходе собственно сохраняются указатели. при загрузке первым проходом все объекты создаются, а указатели инициализируются на втором проходе. Разумеется, нужна рефлексия, что-то типа NewObjectById(int obId).
Главное, чётко определить, где нужно сериализовать сам объект, а где просто указатель на него.
Как это выглядит:
Скрытый текст: ПОКАЗАТЬ
- Cfyz
- Сообщения: 776
- Зарегистрирован: 30 ноя 2006, 10:03
- Откуда: Санкт-Петербург
- Контактная информация:
Re: Сохранение в игре.
Раз речь идет о сохранении состояния игры, несправедливо было бы не упомянуть альтернативный подход: сохранение начального состояния ГСЧ и всего списка действий с начала игры. При загрузке действия применяются и на выходе должно получиться сохраненное состояние.
Из плюсов -- никакой головной боли с сериализацией чего-либо и плеер игровых сессий как побочный эффект. Из минусов -- несовместимость сейвов при любых изменених в игре и общая неэффективность подхода при большом количестве фоновой работы (большой живой мир и т. п.).
Алсо,
Из плюсов -- никакой головной боли с сериализацией чего-либо и плеер игровых сессий как побочный эффект. Из минусов -- несовместимость сейвов при любых изменених в игре и общая неэффективность подхода при большом количестве фоновой работы (большой живой мир и т. п.).
Алсо,
Ни одна ОС не будет делать тысячи обращений к диску, даже если писать по одному байту (ну если только не попросить ее об этом явно). Накладные расходы на запись меркнут на фоне подготовки записываемой информации (составления строк, построения таблиц и пр.).altmax писал(а):JSON-велосипед писал построчно в файл? Т.е. для записи состояния игры нужны были десятки тысяч обращений к жесткому диску?
Пытается раскуклиться
Re: Сохранение в игре.
О да! И как фичу, в процессе самой загрузки убыстренно прокручивать все происходящее перед глазами игрока. Так чтобы вложилось секунд в 10.
Если механизм откатать, можно даже игровые фичи таким образом сделать. Эдакий амулет воскрешения, то есть возврата времени. При гибели лог пишет - "нет, нет, нет, все было не так" и возвращает пошагово игрока на 50 ходов назад.
- Максим Кич
- Администратор
- Сообщения: 1642
- Зарегистрирован: 03 дек 2006, 20:17
- Откуда: Витебск, Беларусь
- Контактная информация:
Re: Сохранение в игре.
Тут главное не применять это ни к чему вроде Ангбанда. В эндшпиле «краткое содержание предыдущей серии» может занять чуть дольше, чем игрок сможет вынести.
Dump the screen? [y/n]
- Jesus05
- Сообщения: 1840
- Зарегистрирован: 02 дек 2009, 07:50
- Откуда: Норильск, сейчас Санкт-петербург.
- Контактная информация:
Re: Сохранение в игре.
Не в БД дело. Скорее мое предложение в уходе от ручной рефлексии. у ODB как и возможно и других ORM`ок есть свой прекомпилер который сам формирует "таблицы" из классов. Сам учитывает зависимости построенные на shared_pointer сам разруливает циклические зависимости(хотя мне не удалось тогда растащить пример с циклической зависимостью из 1 хедера в 2-ва, но думаю я просто плохо читал документацию).
Т.е. суть предложение не в том что использовать БД, а в том что-бы использовать OMR-ки способные сами накодогенерить сериализацию классов сохранив\загрузив все поля без переписывания кода при каждом добавлении\изменении поля.
- Jesus05
- Сообщения: 1840
- Зарегистрирован: 02 дек 2009, 07:50
- Откуда: Норильск, сейчас Санкт-петербург.
- Контактная информация:
Re: Сохранение в игре.
По поводу JSON у меня сложилось впечатление, что "не сишники" считаю, что в Сях JSON реализуеться как-то так:Максим Кич писал(а): ↑07 фев 2017, 09:10Ни разу не сишник, но думаю, что решения как минимум на каком-то уровне примерно схожие.
...
Код: Выделить всё
json_encode(get_object_vars($class));
Код: Выделить всё
public function toJSON(){
return json_encode($this);
}
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 29 гостей