збереження / завантаження ігрового стану?


12

який найбільш використовуваний метод чи алгоритм для збереження ігрового стану (профілів), текстові файли баз даних, як відбувається шифрування та пов'язані речі.

Я бачив, як Цезар IV використовував mySQL.

будь-які пропозиції.

Відповіді:


20

Я впевнений, що найчастіше це робиться у фірмовому (двійковому) форматі, просто записуючи кожну змінну з будь-якої структури гри гри, яку ви використовуєте у файл, або читання цього файлу в екземпляр структури. Наприклад, в C ++ ви можете обробити об'єкт, як масив байтів, і просто переписати його () у файл або завантажити Fread () з файлу та повернути його в його об'єктну форму.

Якщо ви використовуєте Java або іншу мову, ви можете вибрати серіалізацію, щоб зробити завдання справді легким. Пояснення Java знаходиться внизу цієї відповіді; інші мови (вищий рівень, ніж C ++), безумовно, також мають власні бібліотеки серіалізації або вбудовані функції, які ви бажаєте використовувати. Незалежно від того, наскільки неефективним може бути рутифікація серіалізації, простір на жорсткому диску в даний час коштує дешево, особливо коли ігровий стан взагалі не повинен бути дуже великим, і це заважає писати та підтримувати власні процедури серіалізації.

Вам абсолютно не слід використовувати MySQL (просто прочитайте перше речення цього огляду ). Якщо вам дійсно потрібна реляційна база даних з якихось причин, використовуйте SQLite ; це легка система баз даних і існує в одному файлі бази даних. Але для більшості ігор реляційні бази даних - це не шлях, і компанії, які намагаються їх використовувати, зазвичай використовують їх як таблицю пошуку ключових значень, а не як справжню реляційну базу даних.

Будь-яке зашифрування файлів локальних дисків є лише придушенням ; будь-який хакер просто обнюхає дані відразу після того, як програма розшифрує їх. Я особисто проти такої речі, ОСОБЛИВО з іграми для одного гравця. На мою думку, власникам гри (платять клієнти, майте на увазі), слід дозволити хакнути гру, якщо вони хочуть. У деяких випадках це може створити більше почуття спільності, і "модники" можуть бути розроблені для вашої гри, які приводять більше клієнтів до вас. Найновіший приклад, який спадає на думку, - нещодавно випущений портал в моді Minecraft . Він публікується на сайтах новин для геймерів по всьому Інтернету, і ви можете поставити під сумнів, що це збільшило продажі Minecraft.


Якщо з якоїсь причини ви насправді досить божевільні, щоб використовувати Java для розвитку ігор, як я, ось коротке пояснення серіалізації на Java:

Зберігайте всі ваші дані про стан ігор в одному класі, зробіть клас серіалізаційним шляхом впровадження Serializable, використовуйте transientключове слово, якщо ви змішуєте спеціальні змінні змінні в клас (перехідні об'єкти не серіалізуються), і просто використовуйте ObjectOutputStreamдля запису у файл та ObjectInputStreamдля читання з файлу . Це воно.


2
Хе-хе, Відьмак не зашифрував їх дані. Дуже просто відкрити файл збереження гри в шестигранному редакторі, трохи повозитися з ним і дістати всі голі пташенятні карти ... о боже, мені так шкода!
Ентоні

Я використовував бінарну серіалізацію .NET для збереження ігор, а C # - це, можливо, трохи більш розумна платформа, ніж Java, на якій можна розвивати ігри. Мені подобається, як він автоматично зберігає весь графік об'єкта автоматично. Це раніше було набагато складніше. Звичайно, зараз є завдання виключити непотрібні шматочки, наприклад, текстури, але це не велика справа.
BlueMonkMN

Я не погоджуюся з тим, що C # трохи популярніше, ніж Java для розробки ігор. Більш розумне передбачає деяку суб’єктивність, і як розробник як XNA, так і Java, я віддаю перевагу Java. Сміливо перелічіть інструкції щодо серіалізації в C #, якщо ви хочете, я ніколи цього не робив, але можу змінити його у свою відповідь. Серіалізація Java дійсно зберігає весь графік об'єкта, а ключове слово "перехідне" на змінних виключає непотрібні фрагменти, наприклад текстури; будь-які неперехідні члени повинні бути Serializable або ви можете написати власний метод writeObject, щоб обійти це.
Ricket

Підберезник Python також збереже весь графік об'єктів і для вас, і він є легким у використанні. Коли настає час десеріалізувати, вам повертають повністю гідратовані об'єкти, прості як пиріг: docs.python.org/library/pickle.html
drhayes

При використанні вбудованого бінарного форматера виключення певних полів із серіалізації в C # /. NET така ж проста, як прикрашати їх атрибутом [NonSerialized]. Однак легко не помітити те, що події, створені компілятором (тобто будь-яка подія без спеціальних операторів додавання / видалення), створюють резервне поле для зберігання своїх передплатників. Таким чином, легко випадково (і несвідомо) включити обробників подій в серіалізований графік об'єктів. Щоб обійти це, вам потрібно додати атрибут NonSerialized до декларації події, але вам потрібно додати класифікатор "field:":[field: NonSerialized]
Майк Стробель

3

Якщо ви пишете власний код, скажімо, на C ++, ви можете використовувати двійкові файли. Бінарні файли надають форму шифрування за допомогою обтурації. Але як це зафіксовано у всіх мережах, це дуже слабка форма безпеки.

АБО ви можете використовувати щось на зразок RapidXML, якщо хочете зрозуміти людину.

Якщо ви використовуєте якийсь фреймворк, перегляньте його функції підтримки файлів. HTH


0

Більшість ігор, які я бачив, просто використовують рукописний код для читання / запису з двійкових файлів. Часто формат на диску є точною репліку макета пам’яті об’єкта, тому завантаження просто:

  1. Читання файлу в пам'яті.
  2. Відкиньте вказівник на буфер на тип об'єкта.

Це швидко, але це завдання для обслуговування, орієнтованого на платформу та негнучкість.

Останнім часом я бачив, як пара ігор використовує SQLite. Людям, з якими я говорив, здається, це подобається.


0

Серіалізація згадується в деяких інших відповідях, і я згоден, що це розумне рішення. Один із способів цього не вдається, але це версія.

Скажімо, ви випускаєте свою гру і люди в неї грають і створюють кілька ігор для збереження. Потім в наступному патчі потрібно виправити помилку або додати деякі функції. Якщо ви використовуєте простий метод бінарної серіалізації та додаєте учасника до своїх класів, ваша серіалізація може бути не сумісна зі старими іграми збереження, коли клієнти встановлюють ваш патч.

Отже, яким би підходом ви не користуєтесь, обов’язково подумайте над цим питанням перед тим, як випустити гру вперше! Клієнти не будуть раді, якщо їм доведеться починати заново після накладення виправлення.

Один із способів уникнути цього - це кожен базовий тип даних реалізувати Save (version) та Load (version) методи, які досить розумні, щоб знати, які дані зберігати та завантажувати для кожної версії гри. Таким чином ви можете підтримати зворотну сумісність своїх ігор для збереження та вийти з ладу, якщо користувач намагається завантажити збережену гру з нової версії гри, ніж вона працює.


1
Як коротке зауваження: реалізація функцій «збереження» та «завантаження» для кожної версії гри швидко перетворюється на кошмар технічного обслуговування. Я знайшов кращого рішення - вбудувати номер версії, написати функції «збереження / завантаження» для поточної версії гри та написати функцію «перетворення» з найновішої непоточної версії в поточну версію. Тоді просто тримайте всі свої функції перетворення. При спробі завантажити гру з десятьма версіями буде запущено десять функцій перетворення послідовно, тоді нативна функція "завантажує поточну версію гри".
ZorbaTHut

Набагато простіше підтримувати довгостроковий - збереження серії функцій "завантажувати кожен попередній ігровий файл" швидко перетворюється на багаточленну операцію.
ZorbaTHut

В іграх, над якими я працював, це не так вже й складно - замість того, щоб зберігати кілька копій методів завантаження / збереження, один єдиний метод використовує номер версії, щоб визначити, які байти читати та писати. Це стає ще простішим, якщо ви не просто записуєте структури, але реалізуєте завантаження та збереження як операції на примітивному рівні типу даних (наприклад, ReadByte / ReadFload / тощо). Потім, якщо ви додасте нового члена, ви можете зробити щось на зразок if (версія> 10) {someNewByte = ReadByte (); } Реалізація цього способу також спрощує підтримку різних ендіанських платформ.
kevin42

Інший спосіб уникнути покращення підтримки версій - уникнути того, щоб методи серіалізації / десеріалізації ваших об'єктів записували / читали окремі значення безпосередньо з потоку. Натомість об'єкти можуть записувати свої власні дані у мішок властивостей за допомогою пар ключів / значень, а потім виписувати мішок у потік. Під час десеріалізації об’єкти могли читати значення з мішка за назвою. Але замість встановлення певних перевірок номерів версії, як, наприклад, запропоновано kevin42, ви можете просто встановити правила поводження з пропущеними значеннями (тобто використовувати стандартне значення за замовчуванням, коли необхідне значення не знаходиться в сумці).
Майк Стробель

0

Якщо ви можете використовувати той самий формат, який ви використовуєте для зберігання своїх рівнів, це бонус.

Наприклад, така гра, як Peggle, може мати початковий макет дошки, кількість кульок, поточний рахунок (0 для початкової дошки) тощо. Потім збережена гра може використовувати саме той самий формат.

Якщо ви використовуєте той самий формат, то гра збереження та завантаження рівнів можуть ділитися кодом, полегшуючи вашу роботу!

Для гри з дійсно великими картами, гра збереження може включати файл карти за посиланням. Файли початкового рівня можуть зробити те саме, що навіть полегшує повернення на цю карту, якщо з якоїсь причини історія має характер повернутися до того самого місця, за винятком того, що деякі NPC загинули, а трупи лежать усі над.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.