Войти
ПрограммированиеФорумОбщее

Как работает восстановление состояния игры из файла сохранения, и что такое файл сохранения?

Страницы: 1 2 Следующая »
#0
22:08, 27 июля 2021

Всем привет, у меня очень большой вопрос, так как я не понимаю как сохраняется состояние игры, и тем более, как восстановить это состоянии при инициализации. Не имеет значения какой язык я использую, давайте использовать псевдокод.

Для того, чтобы разобраться с вопросом решил создать простой проект. Есть несколько сундуков (я так буду называть любой ящик, в который можно что-то положить), и одновременно на экран можно вывести содержимое только одного сундука. Экземпляры сундуков хранятся в массиве, один из сундуков является "Текущим".

На экран выводится:
1) Название сундука,
2) Описание сундука,
3) Предметы, которые в нём лежат,
4) Предметы в инвентаре игрока,
4) Кнопки "ПРЕДЫДУЩИЙ", "СЛЕДУЮЩИЙ", "ГЛАВНОЕ МЕНЮ"

Нажатие на предмет в сундуке перемещает его в инвентарь, нажатие на предмет в инвентаре перемещает предмет в сундук.

Нажатие на кнопку "ПРЕДЫДУЩИЙ" открывает предыдущий сундук в массиве, а нажатие на кнопку "СЛЕДУЮЩИЙ" выведет на экран следующий сундук.

Кнопка "ГЛАВНОЕ МЕНЮ" откроет меню со следующими кнопками: "ЗАГРУЗИТЬ", "СОХРАНИТЬ", "НОВАЯ ИГРА", ну может быть будет кнопка "ВЕРНУТЬСЯ", чтобы закрыть главное меню.

Я не могу понять, как должно происходить сохранение игры. Как сохраняется информация о размещённых объектах? Допустим нажимаем на кнопку "СОХРАНИТЬ", тогда происходит событие сохранения, все сундуки подписаны на это событие, и попытаются сохранить себя. Но что это значит? Не будет же объект сохраняться как последовательность байт, со своими полями и методами. Как я понимаю каждый сундук попытается сохранить своё состояние, а именно набор объектов. Но как? Просто побитно запишет объекты? Или создастся некий файл с описанием атрибутов, которые потом нужно восстановить?

Так же не понимаю как происходит инициализация каждого сундука. Допустим мы начали новую игру, сначала создаётся последовательно 3 пустых (без объектов) экземпляра сундуков, потом некий сборщик наполняет их объектами?

Представим сундук:
СТАРЫЙ СУНДУК, а нём 3 объекта: "Кирпич", "Нож" и "Бутылка", каждый из этих объектов экземпляр своего класса, который наследуется от класса Item. Как бы выглядел файл сохранения, и как сборщик по нему бы заново их разместил бы в сундуке?

Приведу пример кирпича:

class Brick : Item
{
  title = "Кирпич";
  name = "item_brick_01";
  description = "Старый немытый кирпич";
  icon = sprite_brick_01;
  weight = 3.00;
  endurance = 100.0;

  //Куча методов
}

Сомневаюсь, что при сохранение мне нужно сериализовать объект, наверное сохраняются только данные, но не весь класс со своими методами.

Например, когда в Skyrim сохраняемся во время драки, в файл сохранения попадают классы все бойцов, существ, и прочего? Скорее всего сохраняется некоторая информация, по которой происходит сборка при загрузке.

Наколхозил диаграмму, может понятней станет о чём я говорю. diagram | Как работает восстановление состояния игры из файла сохранения, и что такое файл сохранения?
Может у кого есть исходник крайне простой игры с реализацией сохранения/загрузки на c/c++?


#1
22:26, 27 июля 2021

Serialization. Должна быть частью ECS.
https://docs.cryengine.com/display/CEPROG/Serialization+Library

#2
22:31, 27 июля 2021

>Всем привет, у меня очень большой вопрос, так как я не понимаю как сохраняется состояние игры, и тем более, как восстановить это состоянии при инициализации. Не имеет значения какой язык я использую, давайте использовать псевдокод.

Есть пять точек, куда прописывается каждая новая глобальная переменная игры: места где она создаётся, задание параметров всегда, задание параметров перед новой игрой, сохранение игры, загрузка игры. В общем и целом, когда ты заводишь новую глобальную переменную, ты должен прописать её в в нескольких местах из пяти вышеперечисленных. Для каждой переменной решаешь где надо. При сохранении игры ты врубаешь процедуру записи уже прописанных там глобальных переменных - поштучно и массивами. А при запуске игры активируешь процедуру "задание параметров всегда", после процедуру "задание параметров перед новой игрой", после загружаешь глобальные переменные из своей сохранки и запускаешь игру. И всё. А если у тебя есть классы, то сохраняешь и данные из классов, а после загрузки переменных из сохранки даёшь классам задание скушать оттуда данные.

>Может у кого есть исходник крайне простой игры с реализацией сохранения/загрузки на c/c++?

Есть исходник тестовой демки "догони меня кирпич" на паскале. В ней для облегчения загрузки и сохранения используется "резиновый" массив глобальных переменных. Сохранил массив и ещё несколько переменных и игра сохранилась. Переписать сохранение на плюсы не сложно, там без классов, на гото:) novellotyk-1.0.2.tar.xz Добавь тормозов, глюков и готово!

#3
22:32, 27 июля 2021

Есть более десятка разных способов сохранить. Как угодно можно. Выбирай нужный тебе способ. У каждого есть как преимущества, так и недостатки.

> Сомневаюсь, что при сохранение мне нужно сериализовать объект, наверное
> сохраняются только данные, но не весь класс со своими методами.
Не знаю где ты увидел способ сохранить вместе с методами, в какой среде вообще такое возможно... Ты вообще хоть на чем-нибудь программируешь?

#4
22:37, 27 июля 2021

>title = "Кирпич";
> name = "item_brick_01";
> description = "Старый немытый кирпич";

Ты точно не играл в демку "догони меня кирпич"? Там основной предмет, которым играют "кирпич несъедобный".

#5
23:08, 27 июля 2021
Не знаю где ты увидел способ сохранить вместе с методами, в какой среде вообще такое возможно... Ты вообще хоть на чем-нибудь программируешь?

Потому и спросил, мало ли бывает). В вузе на C/C++ программировал, игру делаю не на плюсах, на плюсах стараюсь исходники читать.

Serialization. Должна быть частью ECS.
https://docs.cryengine.com/display/CEPROG/Serialization+Library

Правильно ли я понял, что ты про Entity-Component-System? Я не буду реализовывать такую архитектуру, во первых для данного примера не требуется, во вторых я нуб. Самая сложная программа, что я писал — консольный ту-ду лист.


Skvoznjak, Спасибо за пример. Не совсем понятно, что вы имеете ввиду под глобальной переменной. Глобальная переменная должны быть доступна из любого контекста программы, но объекты в "Сундуках" доступны лишь менеджеру, который занимается транспортировкой этих объектов (между инвентарём и сундуком).

#6
0:41, 28 июля 2021

zakhardelov
>Не совсем понятно, что вы имеете ввиду под глобальной переменной.

Обычные глобальные переменные. Логика в процедурах/объектах такая, что действие часто выполняется за много запусков процедуры, а между запусками она где-то должна хранить данные, по которым при следующем запуске восстановит своё состояние. Где их ещё хранить, как не в массивах глобальных переменных - локальные после окончания работы процедуры ведь пропадают.

>Глобальная переменная должны быть доступна из любого контекста программы,

Нет. В идеале у них должна быть область видимости. В плюсах с этим не всё хорошо. В некоторых глобальных переменных хранится информация, нужная для обеспечения работы программы. Эти переменные нужны техническим переключателям просто чтобы система запускалась и видеть их лишним сущностям не обязательно. То есть, это какие-то кишки системы, которые работают сами по себе и скриптами управлять ими не надо. Когда будешь лепить систему, тебе обязательно понадобятся скрутки чтобы её слепить в неразваливающееся целое.

Также в массивах глобальных переменных можно записать какие объекты создать при старте. Менеджер объектов этот массив прочитает, создаст объекты и накормит их данными. Зачем организовывать доступ к этому массиву, тем, кому он не нужен. Там же без описания что где лежит заблудишься. То есть ты организовываешь какую-то свалку данных, с минимальным описанием что где лежит, в которой найти нужное можно доставая данные из массивов последовательно, в том же порядке, в каком они были положены. В движках это автоматизируют, чтобы таким не заниматься, но ты же хотел знать как такое изготовить, например чтобы впендюрить параллельно к создаваемому движком.

#7
1:33, 28 июля 2021

Эту тему - во флейм. Ибо бред. Автора послать читать учебники. И не по сейв-лоаду ученики, а по программированию вообще. С таким уровнем даже зачет по основам программирования не получишь в институте, а не то что игры писать. Объяснять что-либо бесполезно, даже не поймет о чем речь идет, при отсутствии базового образования.

#8
4:31, 28 июля 2021

отвечу просто. если в сундуке с номером 5 хранится объект с номером 1119, а всего в игре тысяча сундуков. то файл сохранения будет выглядеть так
колво сундуков 1000
сундук 1 колво предметов х
сундук Н колво предметов ХХ ЧЧЧ ЧЧЧЧ ЧЧ ЧЧЧЧ ЧЧЧЧ
сундук 5 колчисво предметов 1 1119
и так дальше. просто куча целочисленных данных. целое число 4 байта итого на сундук будет 4 + 4 * колво предметов в сундуке. пара десятков байт на сундук - пара десятков килобайт на тысячу сундуков соответвенно

#9
8:06, 28 июля 2021

Zab
Автор сдал все экзамены по основам программирования, просто из-за отсутствия опыта, не знаю как лучше организовать сохранение. Я понимаю, как можно сохранить данные в файл и считать их, просто не уверен как правильно это делают при сохранении данных в игре. Вы не можете знать мой уровень, а по вашим ответам похоже, что он от моего не сильно отличается.

отвечу просто. если в сундуке с номером 5 хранится объект с номером 1119, а всего в игре тысяча сундуков. то файл сохранения будет выглядеть так
колво сундуков 1000
сундук 1 колво предметов х
сундук Н колво предметов ХХ ЧЧЧ ЧЧЧЧ ЧЧ ЧЧЧЧ ЧЧЧЧ
сундук 5 колчисво предметов 1 1119
и так дальше. просто куча целочисленных данных. целое число 4 байта итого на сундук будет 4 + 4 * колво предметов в сундуке. пара десятков байт на сундук - пара десятков килобайт на тысячу сундуков соответвенно

Спасибо, это многое прояснило. То-есть действительно, сборщик анализируя файл сохранения создаст объекты, и мне незачем сохранять структуры самих объектов в файл сохранения, если конечно, у них самих не будет своего состояния.

#10
(Правка: 14:21) 8:17, 28 июля 2021

zakhardelov
> просто не уверен как правильно это делают при сохранении данных в игре
По разному делают.
Чаще всего в объекты вставляют функции save и load, сохраняющие/восстанавливающие состояние. Плюс, делают менеджер, который создает объекты по идентификатору типа. Формат сохранения может быть разный, дешевле всего при исполнении - двоичный. Текстовый порождает меньше проблем при совмещении разных версий.
Иногда используют чанковую систему.
Можно и не сохранять каждый объект, вместо этого хранить затравку для генератора случайных чисел, скармливаемую процедурному генератору.

После тезиса о сохранении методов или вопроса что такое глобальные переменные, ты отправляешься с экзамена по основам программирования на пересдачу. Проскочить ты можешь если преподаватель завалил свою преподавательскую работу, ничему вас не научил и теперь пытается скрыть это, поставив зачеты ни за что, чтобы его самого не уволили нафиг. Таких преподавателей много, к сожалению.

#11
14:12, 28 июля 2021

tl;dr

Как было сказано выше, делают по разному, но по сути это (де)сериализация.

И тут в основном 2 варианта, куда поместить "сериализационную" часть: в сам объект, или в некую глобальную фабрику-менеджер.

#12
(Правка: 15:31) 15:27, 28 июля 2021

Обычно создают фабрику сохранений.
Каждый объект подписан на событие сохранения.
Потом выходит почтальон, разносит уведомления.
Потом звонят директору фабрики Синглтону и спрашивают, какое название файла.
Директор фабрики сначала должен выяснить если у него лицензия на осуществление сериализационной деятельности. Если нет он должен позвонить директору фабрики ошибок, чтобы они запустили конвеер и добавили в очередь ошибку.
Если лицензия есть, то директор фабрики передаёт заместителю директора фабрики, который уже в каждом треде свой, что надо сериализовать объекты.
Где-то в это время глобальные переменные выходят на марш протеста, потому что их запретили.
Затем объекты присылают свои данные как полуфабрикаты, в какой-то момент они абстрагируются на фабрике абстракций.
Компилятор всё это оптимизирует, так что работало. Надо только отключить агрессивные оптимизации - они будут бить почтальонов - это плохая практика.

Потом игрок орёт ФАСРАДА и игра крашится. Игру называют Кибирпук 2000.

#13
15:45, 28 июля 2021

у меня тоже раньше были фабрики, объекты, синглтоны и т.д.
имхо, они только усложняют и запутывают код.

самый простой и быстрый способ - тупо сохранять на диск дамп памяти игры (и для ассетов тоже подходит).
потом его остаётся только загрузить и расставить указатели, и всё готово к работе.
только желательно какую-нибудь рефлексию заюзать, чтобы знать, где в теле объекта находятся указатели, чтобы их патчить при загрузке.

#14
16:42, 28 июля 2021

NyakNyakProduction
> Обычно создают фабрику сохранений.

Для сохранений то зачем? В терминах этого паттерна сохранение - это сырьё а не продукт.

Даже если делаешь попытки шуток, логику не стоит отбрасывать.

Страницы: 1 2 Следующая »
ПрограммированиеФорумОбщее