Найкраще рішення для "рівня рядка"?


10

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

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

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

Чи вдалий варіант "рядок рівня" буде хорошим варіантом? Це була б якась конверсія "base60"? Як би я це здійснив?

Відповіді:


20

Імовірно, все, що вам потрібно зберегти, - це випадкове насіння, яке, як правило, є лише цілим. Ви можете закодувати int до base64, якщо хочете зробити його трохи більш непрозорим, але це, мабуть, не потрібно.


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

Це нормально, але йому також доведеться зберігати динамічні дані, якщо гра ведеться. У рядку потрібно буде зберегти позиції символів / оцінка тощо. Що таке найкращий спосіб генерувати цей рядок?
Адам Харте

Я, ймовірно, використовую JSON (або, якщо ви хочете, XML), щоб серіалізувати світовий стан, а потім base64-кодувати цей рядок. Не впевнений, що все корисне, чому б просто не зробити більш орієнтовану на GUI систему збереження / завантаження? Я припускаю, що це веб-основа, і ви не хочете обробляти цю сторону сервера. Може, подивіться для прикладу shygypsy.com/farm/p.cgi ?
кодерангер

23

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

Ви пошкодуєте, якщо цього не зробите.


7
+1 насправді не відповідає на питання, але настільки важливий.
Джонатан Фішофф

10

JSON - це добре, але YAML - це краще. :) http://www.yaml.org/ та http://code.google.com/p/yaml-cpp/ для однієї з приємних у використанні реалізації.

YAML - це набір JSON, який додає підтримку кількох приємних функцій, а саме:

  • Двійкові вузли. Це чудово для серіалізації типу даних, з якими ви можете мати справу для описів рівнів. JSON вимагає, щоб ви перевели в якийсь проміжний формат на ваш вибір, наприклад Base64, перед написанням / після розбору. YAML має тип бінарного вузла !!, який повідомляє бібліотеці аналізатора зробити це за вас.
  • Внутрішньодокументні посилання. Якщо один і той же об’єкт з’явиться два рази в документі, JSON напише його двічі, а коли ви прочитаєте його назад, ви отримаєте дві копії. Багато емітерів YAML можуть виявити цю ситуацію і замість другої копії вивести посилання на першу, коли її можна буде виявити при завантаженні.
  • Спеціальні типи вузлів Ви можете позначити кожну карту в списку, наприклад, програвач !!, програвач, ворог тощо, і таким чином зберігайте інформацію про свій тип поза межами діапазону.
  • YAML підтримує більш читабельне форматування.
  • Оскільки JSON - це підмножина YAML, більшість читачів YAML не матимуть проблем із читанням документів JSON.

1
Yaml дуже крутий, і якщо уникнути деяких функцій суперсети, його можна без особливих труднощів перетворити на json.
Jethro Larson

3

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

Я використав цю бібліотеку для C ++, і вона працює дуже добре.

http://jsoncpp.sourceforge.net/


3

XML - хороший вибір, якщо ви не обмежені розміром, і він підтримується вбудовано (наприклад, у .NET і Flash), але якщо ви хочете тонкий формат, ви можете створити свій власний формат і аналізатор досить легко. Я зазвичай використовую 1 символ, наприклад. кома для відокремлення кожного об'єкта. Щоб розшифрувати рядок, зробіть розділення на коми. Тепер кожен об'єкт потребує різних властивостей, тому відокремте їх з різним символом, наприклад, двокрапкою, і використовуйте інший символ, щоб відокремити імена властивостей від домен властивостей, наприклад. Товста кишка. Все, таким чином, можна легко розшифрувати без регулярного вираження, лише використовуючи string.split. Ось приклад:

id:1;x:5;y:45.2;angle:45,id:28;x:56;y:89;angle:12;health:78

ви можете заощадити ще більше місця, зберігаючи імена властивостей до 1 символу, наприклад, h для здоров'я. Напр.

i:1;x:5;y:45.2;a:45,i:28;x:56;y:89;a:12;h:78

Порівняйте з альтернативою JSON:

{"o":[{"i":1, "x":5, "y":45.2, "a":45}, {"i":28, "x":56, "y":89, "a":12, "h":78}]}

Крім того, якщо ви хочете зменшити розмір своїх номерів, ви можете їх кодувати за допомогою повного набору символів для друку UTF16. Цей потік надихнув мене задати питання щодо переповнення стека, скільки даних ви можете упакувати в один екранний символ . Здається, у відповіді десь понад 40 000 значень для цілого числа, якщо ви не заперечуєте, щоб мати фігури з шарами, кандзі та шахи: ♔♕♖♗♘♙♚♛♜♝♞♟

Щоб отримати подальше зменшення розміру, ви можете використовувати порядок читання / запису, щоб визначити, яке значення є, тому перші два символи представляють ідентифікатор, наступні два - х, наступні два у, потім кут, потім здоров'я і т. д. Отже:

F5DGP@%&002DFTK#OP1F

може зберігати всю ту саму інформацію, що й інші приклади.

Сітки плитки можуть зберігатися лише як рядок із кожним символом, що представляє різний тип плитки, наприклад:

i789pog5h3kl

де я можу означати лаву, 9 означає траву тощо


Це більше за те, що я прошу. У своєму питанні я згадую XML, але все ще люди пропонують це!
Адам Харте

1
Додайте {} навколо цього і в основному у вас JSON ;-)
coderanger

Вам також потрібно буде додати багато лапок. Можливо, подвоїться кількість символів, але ви отримаєте вкладення об'єктів.
Iain

1

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

TheMap буде змінною типу Map, у яку ви завантажені всі ваші дані.

Dim TheMap As New Map

Якщо припустити, що у вас вже створений клас Map, це дозволить зберегти вашу карту в XML:

Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(TheMap))
Dim Strm As New FileStream("c:\Map.xml", FileMode.Create, FileAccess.Write, FileShare.None)
Serializer.Serialize(Strm, TheMap)
Strm.Close()

Потім це завантаження XML повернеться у ваш клас карт, щоб знову використовуватись у коді.

Dim Reader As New StreamReader("map.xml")
Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(TheMap))

TheMap = Serializer.Deserialize(Reader)
Reader.Close()

З цього моменту ваш XML-файл завантажується у ваш клас для зручного використання.

Що стосується випуску "Рядок рівня", то, що було заявлено раніше, буде чудово працювати, ви можете просто використовувати номер насіння як "Рядок рівня".

В іншому випадку ви можете заздалегідь генерувати скільки завгодно різноманітних карт, і зберегти їх за допомогою "Рядок рівня", а потім використовувати їх, щоб підтягнути відповідну карту.


+1, навіть якщо я ненавиджу XML - Якщо мова надає формат серіалізації за замовчуванням, найкраще це врахувати спочатку, особливо якщо це формат, який інші інструменти теоретично могли б розібрати (наприклад, XML / JSON / YAML).

0

Я б використовував простий structчи подібний пристрій (залежно від вашої мови), щоб зберігати всі стани гри в центральному місці. Якщо ви хочете захистити сетери / геттери, ви можете обернути структуру в class.

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

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

Ви також можете використовувати #pragma(наприклад #pragma pack(1)) або __attribute__тісно упакувати структуру, виключаючи набивання. Це може бути, а може не працювати, залежно від архітектури компілятора та цілі.

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

(Наприклад, Pac-Man, ця структура може наївно містити ідентифікатор карти або насіння карти, положення Pac-Man x і y, чотири позиції x і y привидів і велике бітове поле для наявності або відсутності 32-64 гранул, незалежно від максимуму.)

Отримавши структуру, передайте їй щось на зразок функції xxencode :

encode_save( char * outStringBuf, size_t outStringBufSize,
             const SaveStruct * inSaveData, size_t inSaveDataSize )

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

Ніколи не варто недооцінювати силу старої школи structв потрібних місцях. Тут ми використали його для гри GBA та DS.


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

@Joe: Я вже згадував, що він не є портативним, і деякі з потенційних проблем. Питання спеціально задало для людини зрозумілу "рядок рівня", як старі ігри Sega та згадане перетворення base60; передача структури через щось на зразок xxencode зробить це. Це не обов'язково передчасна оптимізація: проста структура, не розрядна, є приємним "центральним" способом зберігання збережених даних і може спростити велику частину коду, який взаємодіє з даними. Дивіться, наприклад, останні статті Ноеля Льопіса про недружні структури та програмування "всередину". Це просто KISS.
орендувач

1
Я повністю згоден з таким чином. Так, це не портативно для версій, ні для систем, але знову-таки збереження-ігри - це не ресурси, які потрібно використовувати повторно під час розробки, або копіювати на платформи. Налагоджуваність навряд чи є проблемою з місцем читання / запису, реалізуйте це один раз, і воно буде працювати назавжди. ЯКЩО розширюваність насправді є проблемою - додайте номер версії як перший ібайт / слово, і ви можете ввімкнути це (хоча це призведе до вразливості даних). Це не так, як xml вирішує проблеми з версією - як правило, це більше, ніж просто встановлення значення. Так, я прагматичний.
Кай

0

XML хороший для довільно структурованих документів (елементи можуть з’являтися на різних рівнях дерева) або вбудовування іноземного формату (наприклад, розміщення svg на сторінці xhtml). Якщо у вас немає цих вимог, це дійсно неефективний формат, а щось більш просте, як csv або json, бажано.

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