Знакомство с JSON в Defold

JSON (англ. JavaScript Object Notation ) — текстовый формат обмена данными, основанный на JavaScript . Но при этом формат независим от JS и может использоваться в любом языке программирования.

Ключевые понятия JSON:

1. Объект:

  • Объект в JSON — это набор пар "ключ: значение", заключённый в фигурные скобки {}.
  • Ключ — это строка, окружённая двойными кавычками ("key"), за которой следует двоеточие (:).
  • Значение может быть строкой, числом, булевым значением (true/false), null, объектом или массивом.

Пример:

{
  "name": "Anastasia",
  "age": 18,
  "isStudent": false
}

2. Массив:

  • Массив — это упорядоченный список значений, заключённый в квадратные скобки [].
  • Значения в массиве могут быть любого типа: строки, числа, объекты, другие массивы и т.д.
["яблоко", "груша", "банан"]

3. Типы данных:

  • Строка: Текст в двойных кавычках, например, "hello".
  • Число: Целое или с плавающей точкой, например, 42 или 3.14.
  • Булево: true или false.
  • null: Пустое значение, обозначает отсутствие данных.
  • Объект: Как описано выше.
  • Массив: Как описано выше.

4. Синтаксис:

  • JSON чувствителен к синтаксису: ключи всегда в двойных кавычках, значения разделяются запятыми, пробелы не влияют на структуру.
  • Неправильный синтаксис (например, одинарные кавычки или пропущенные запятые) вызовет ошибку при разборе.

5. Вложенность:

  • Объекты и массивы могут быть вложенными.

Например:

{
  "person": {
    "name": "Алексей",
    "hobbies": ["чтение", "спорт"]
  }
}

Основы работы с JSON в Lua и Defold:

Defold предоставляет встроенный модуль json для работы с JSON-данными, который позволяет преобразовывать JSON-строки в Lua-таблицы и обратно. Это удобно для хранения данных (например, уровней, настроек, таблиц лидеров) и обмена данными с внешними API.

Ключевые функции в Defold [API reference (JSON) | Defold]

json.decode(json_string):

  • Преобразует строку JSON в Lua-таблицу.
  • Если JSON некорректен, вызывает ошибку Lua.

Создадим новый проект со скриптом, затем добавим в загрузочную коллекцию игровой объект и компонент созданного скрипта. Должно получиться примерно так:
image
image

Добавим в функцию init(self) скрипта такой код:

function init(self)
	local json_string = '{"name": "Ваня", "score": 100}'
	local data = json.decode(json_string)
	print(data.name) -- Вывод: Ваня
end

Соберём и запустим проект (ctrl + B):
image

json.encode(lua_table):

  • Преобразует Lua-таблицу в строку JSON.
  • Если таблица содержит неподдерживаемые типы данных (например, функции), вызовет ошибку.

Изменим код в функции init(self) на такой:

function init(self)
	local data = { name = "Ваня", score = 100 }
	local json_string = json.encode(data)
	print(json_string) -- Вывод: {"name":"Ваня","score":100}
end

Соберём и запустим проект (ctrl + B):
image

Особенности Lua в Defold:

  • Индексация с 1: В Lua массивы начинаются с индекса 1, а не 0, что важно учитывать при работе с JSON-массивами. Например, если JSON содержит массив ["a", "b"], в Lua он будет доступен как data[1] = "a", data[2] = "b".
  • Ограничения типов: JSON поддерживает только строки, числа, булевы значения, null, объекты и массивы. Lua-таблицы могут содержать более сложные типы (например, функции или пользовательские данные), но они не конвертируются в JSON.
  • Производительность: Работа с большими JSON-файлами (например, 4 МБ) может быть медленной. Например, json.decode может вызывать задержки, особенно на мобильных устройствах.

Работа с JSON в Defold: пошаговое руководство:

1. Чтение JSON из файла:

В Defold JSON-файлы часто загружаются как ресурсы с помощью sys.load_resource(). После загрузки строка JSON преобразуется в Lua-таблицу.

Пример: Загрузка JSON-файла с данными об игроках.

  1. Создайте файл data.json в проекте Defold:


    С таким содержимом:
{
  "players": [
    {"name": "Алексей", "score": 100},
    {"name": "Мария", "score": 150}
  ]
}

В main.script, изменим содержимое функции init(self):

function init(self)
	local file_path = "/main/data.json" -- Путь к файлу в проекте
	local content = sys.load_resource(file_path) -- Чтение файла
	if content then
		local success, data = pcall(json.decode, content)
		if success then
			pprint(data) -- Вывод таблицы для отладки
			-- Пример доступа к данным
			for i, player in ipairs(data.players) do
				print("Игрок: " .. player.name .. ", Очки: " .. player.score)
			end
		else
			print("Не удалось расшифровать JSON: " .. data)
		end
	else
		print("Ошибка загрузки файла: " .. file_path)
	end
end

Мой вывод:
image

Чтобы предотвратить эту ошибку. Нужно добавить путь к файлу с json как пользовательский ресурс в game.project:


Собираем и запускаем проект:

Может быть полезно:
API reference (System) | Defold
Defold project settings

Объяснение:

  • sys.load_resource(file_path) загружает содержимое файла как строку.
  • pcall(json.decode, content) безопасно декодирует JSON, предотвращая краш игры при ошибке.
  • pprint(data) используется для отладочного вывода структуры таблицы.
  • Доступ к данным осуществляется как к обычной таблице Lua: data.players[1].name.

Совет: Всегда используйте pcall для обработки ошибок, чтобы избежать краша игры из-за некорректного JSON.

2. Запись данных в JSON:

Для сохранения данных в JSON вы можете преобразовать таблицу Lua в строку JSON с помощью json.encode() и затем сохранить её в файл. Однако Defold не предоставляет встроенной функции для записи файлов в проект, так как проектные файлы считаются неизменяемыми во время выполнения. Вместо этого данные обычно сохраняются в пользовательские файлы (например, в папке приложения) или отправляются на сервер.

Пример: Создание и сохранение JSON

Предположим, вы хотите сохранить данные игрока в JSON:

function init(self)
	-- Создаем таблицу Lua
	local player_data = {
		players = {
			{ name = "Alice", score = 100 },
			{ name = "Bob", score = 200 }
		}
	}

	-- Кодируем таблицу в JSON
	local json_string = json.encode(player_data)
	print(json_string)

	-- Сохранение в файл (пример для платформ, где доступна запись)
	local file_path = sys.get_save_file("my_game", "data.json")
	local file = io.open(file_path, "w")
	if file then
		file:write(json_string)
		file:close()
		print("Data saved to " .. file_path)
	else
		print("Failed to open file for writing")
	end
end

Вывод:
image
Функция sys.get_save_file возвращает путь, зависящий от платформы, чтобы узнать, куда сохранился этот файл, подправим код:

local file, error_msg = io.open(file_path, "w")
if file then
	file:write(json_string)
	file:close()
	print("Data saved to " .. file_path)
else
	print("Failed to open file for writing: " .. (error_msg or "Unknown error"))
end

Вывод:
image

Объяснение:

  • json.encode(player_data) преобразует таблицу в строку JSON.
  • sys.get_save_file("my_game", "data.json") возвращает путь для сохранения файла в папке приложения (зависит от платформы).
  • io.open(file_path, "w") открывает файл для записи (работает на платформах, где доступна файловая система, например, на десктопе).

Ограничение: Запись файлов возможна только в определённых местах (например, папка приложения на мобильных устройствах). Для веб-платформ (HTML5) лучше отправлять данные на сервер через HTTP.

Итоговый код:

function init(self)
	-- Создаем таблицу Lua
	local player_data = {
		players = {
			{ name = "Alice", score = 100 },
			{ name = "Bob", score = 200 }
		}
	}

	-- Кодируем таблицу в JSON
	local json_string = json.encode(player_data)
	print(json_string)

	-- Сохранение в файл (пример для платформ, где доступна запись)
	local file_path = sys.get_save_file("my_game", "data.json")
	local file, error_msg = io.open(file_path, "w")
	if file then
		file:write(json_string)
		file:close()
		print("Data saved to " .. file_path)
	else
		print("Failed to open file for writing: " .. (error_msg or "Unknown error"))
	end
end

На этом пока что всё, по мере необходимости и использования JSON на практике, буду дополнять эту ему новыми разделами.

Может быть интересно:

Ссылки, используемые в этом посте:
API reference (JSON) | Defold
API reference (System) | Defold
Defold project settings

3 лайка