Содержание урока · 10 разделов
- Карты источников: где живут бесплатные ассеты
- Читать лицензию: CC0, CC-BY и CC-BY-SA
- Ресурс, лицензия и обязанность разработчика
- Папка assets и go:embed: от файла к бинарнику
- Титры: CREDITS.md как часть проекта
- Чек-лист принятия ассета в проект
- Шрифты и звуки: отдельные правила
- Песочница урока
- Коротко: что запомнить
- Вопросы и ответы
Ни один движок не поставляется с героем: картинки, шрифты и звуки в игру приносит разработчик, и берёт их из двух источников — рисует сам или берёт готовое. Рисовать самому долго и не обязательно, а готовое несёт с собой чужие условия: у каждого файла есть автор и лицензия, и они не отменяются копированием в проект. Отсюда три вопроса урока: где искать паки, что именно разрешает лицензия и что вы обязаны сделать в ответ — указать автора, сохранить копию лицензии или просто взять и молчать. Игровые ассеты — единственная часть курса, где главная работа происходит не в редакторе кода, а в текстовом файле LICENSE, и это тоже инженерный навык: релизная игра — это код плюс честно оформленные заимствования. Правовая часть пугает сильнее указателей, но объём у неё скромный: пять обозначений — CC0, CC-BY, CC-BY-SA, OFL и NC — покрывают почти весь рынок бесплатных ассетов, а исполняются условия одним файлом титров и дисциплиной коммитов. Остальное — организация: папка assets, директива embed и загрузчик, возвращающий понятные ошибки.
Карты источников: где живут бесплатные ассеты#
Начните с мест, где лицензии организованы честно. Kenney.nl — библиотека из тысяч паков: двухмерные спрайты, тайлсеты, UI-наборы, звуки — всё под CC0, то есть в общественном достоянии: брать можно без спроса, менять как угодно и продавать игру без отчислений и даже без упоминания автора. OpenGameArt — агрегат, где у каждого ресурса своя карточка: CC0, CC-BY или CC-BY-SA, и читать надо страницу конкретного пака, а не правила сайта. Раздел game assets на itch.io полон бесплатных материалов, но «free» говорит только о цене: лицензия у каждого пака своя, от щедрой до запретительной.
Шрифты ищите на Google Fonts: большинство семейств живут под OFL, которая прямо разрешает встраивание в приложения и игры. Звуки — Freesound, где лицензия назначается клипу отдельно, и рядом с честным CC0 соседствует неудобный CC-BY-NC. Отдельная категория — процедурные генераторы sfxr, jsfxr и Bfxr: сгенерированный звук ничей — он ваш с первой секунды. Общее правило: источник — витрина, лицензия живёт у конкретного файла. Держите карту в закладках и пополняйте по мере проектов: проверенный источник экономит час поиска в следующей игре, а привычка смотреть лицензию до скачивания превращается в рефлекс, который дальше работает сам.
Спрайт из встроенной папки
GOpackage main
import (
"embed"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
//go:embed assets/*
var assetsFS embed.FS
func loadPlayer() (*ebiten.Image, error) {
img, _, err := ebitenutil.NewImageFromFileSystem(assetsFS, "assets/player.png")
if err != nil {
return nil, err
}
return img, nil
}Директива go:embed над переменной embed.FS пакует папку assets внутрь бинарника при компиляции: файловая система перестаёт быть внешним миром и едет вместе с игрой. assetsFS реализует стандартный интерфейс fs.FS, а NewImageFromFileSystem открывает путь и декодирует PNG в ebiten.Image — тот же тип, что рисовал спрайты раньше, только источник теперь встроенный и одинаковый на всех платформах. Ошибка возвращается наверх без проглатывания: вызывающий код решает сам, падать целиком или рисовать заглушку.
В проект попал спрайт-пак под CC-BY. Что лицензия обязывает сделать?
Читать лицензию: CC0, CC-BY и CC-BY-SA#
Creative Commons выглядит как один значок, а требует разного. CC0 — автор отказался от прав целиком: условий нет, атрибуция не нужна, менять и продавать можно; единственная лицензия, которая не создаёт обязательств. CC-BY добавляет одно условие — атрибуцию: доступное место — обычно титры игры — должно назвать автора, источник и лицензию. Обязанность не истекает с релизом: она живёт столько, сколько живёт игра.
CC-BY-SA добавляет пункт ShareAlike: производные работы обязаны распространяться под той же лицензией. Для открытого проекта это естественно, для закрытой игры — риск: в спорных трактовках производной оказывается вся игра целиком. Отдельно запомните NC: «некоммерческое использование» разом отсекает платный магазин, рекламу и платные версии; формулировка «free for non-commercial» — та же ловушка другими словами. Рабочее правило: лицензия не прочиталась за минуту — файл не берётся, а поиск продолжается с фильтром CC0; во всех источниках выше такой фильтр есть. Ещё одна деталь, о которую спотыкаются: у пака и у отдельного файла из него условия бывают разными, как и у ремикса чужого ресурса — читается не «что написал сайт», а что написано рядом с конкретным файлом.
Загрузчик: один вход для всех картинок
GOtype Assets struct {
Player *ebiten.Image
Enemy *ebiten.Image
Tileset *ebiten.Image
}
func LoadAssets() (Assets, error) {
var a Assets
var err error
a.Player, _, err = ebitenutil.NewImageFromFileSystem(assetsFS, "assets/player.png")
if err != nil {
return a, fmt.Errorf("player: %w", err)
}
a.Enemy, _, err = ebitenutil.NewImageFromFileSystem(assetsFS, "assets/enemy.png")
if err != nil {
return a, fmt.Errorf("enemy: %w", err)
}
a.Tileset, _, err = ebitenutil.NewImageFromFileSystem(assetsFS, "assets/tileset.png")
if err != nil {
return a, fmt.Errorf("tileset: %w", err)
}
return a, nil
}Один вход для всех картинок: структура Assets хранит готовые ebiten.Image, а LoadAssets возвращает ошибку с именем ресурса — при опечатке в пути вы сразу увидите, какой файл не встроился. Game получает весь набор один раз на старте, и ни одна сцена не ходит к файлам сама. Порядок загрузки фиксирован, и игра до завершения LoadAssets просто не начинается. Шрифты и звуки подключаются тем же способом: из того же embed.FS, через текстовый и аудио-механизмы курса.
Ресурс, лицензия и обязанность разработчика#
| Ресурс | Лицензия | Что обязан сделать разработчик |
|---|---|---|
| Паки Kenney.nl | CC0 | ничего: атрибуция не требуется, продажа разрешена |
| Пак с OpenGameArt | CC-BY | титры: автор, источник, название лицензии |
| Тайлсет CC-BY-SA | CC-BY-SA | титры плюс производное под той же лицензией — риск для закрытой игры |
| Пак «free» с itch.io | у каждого своя | прочитать LICENSE до скачивания и действовать по нему |
| Шрифт с Google Fonts | OFL | копия лицензии рядом с файлом; сам шрифт не продавать |
| Клип Freesound с пометкой NC | CC-BY-NC | титры и никакого платного использования — не для коммерции |
Что вернёт путь без префикса assets?
Прочитайте код и выберите, что он выведет:
//go:embed assets/*
var assetsFS embed.FS
img, _, err := ebitenutil.NewImageFromFileSystem(
assetsFS, "player.png",
)Папка assets и go:embed: от файла к бинарнику#
Папка assets — единственный источник ассетов, который вы контролируете целиком: скачанные PNG, шрифты и звуки складываются туда, и дальше с ними работает только компилятор. Директива go:embed встраивает файлы в бинарник на этапе сборки, и это не стилистическое предпочтение: после урока про сборку на платформы вы знаете, что у WASM и мобильных версий нет доступа к вашей локальной файловой системе — относительный путь через обычный os.Open там не найдёт ничего. Встроенный FS ведёт себя одинаково на всех платформах.
Нюанса два. Первый: файлы, чьи имена начинаются с точки или подчёркивания, в бинарник не попадают — держите имена чистыми. Второй: пути внутри embed.FS сохраняют префикс assets, и запрос без него не найдёт файл — ошибка новичка номер один. Третий практический пункт — размер: встроенные файлы увеличивают бинарь на свой вес, поэтому тяжёлые видео и сотни мегабайт аудио туда не кладут; для игр курса паков хватает с запасом. Структуру папки ведите плоско или с понятными подпапками: это продолжение структуры проекта, а не свалка для скачанного.
Чем CC0 отличается от CC-BY с точки зрения разработчика игры?
Типовая история: в игру заходит красивый тайлсет CC-BY-SA с OpenGameArt, игра собирается и уезжает в платный магазин — а пункт ShareAlike требует распространять производные работы на тех же условиях. Граница производного для ассетов внутри проприетарной игры размыта, и спорить придётся не с движком, а с автором. Что сломалось бы дальше: либо проект открывает изменённые ассеты, либо автор требует удалить контент из продажи. Правило для закрытых релизов: CC0 и CC-BY — да, SA и NC — нет, пока вы не готовы делиться или не купили отдельную лицензию у автора. Вторая половина ловушки — обновления: новая версия пака может выйти под другой лицензией, и честно скачанный файл заменяется файлом с новыми условиями; дата в строке CREDITS.md покажет, какая версия была в игре.
Титры: CREDITS.md как часть проекта#
Атрибуция исполняется не намерением, а файлом. Заведите CREDITS.md в корне рядом с assets и добавляйте строку в тот же коммит, что и сам ассет: название ресурса, автор, источник, лицензия, дата. Строка выглядит так: «Ninja Sprite Pack — Kenney, kenney.nl, CC0, 2024». Для CC0 это вежливость и аудит — при обновлении пака вы вспомните, откуда файл; для CC-BY — прямое исполнение лицензии, записанное до того, как память подвела.
Титры дублируются в саму игру: пункт «Credits» в сцене меню — такой же элемент интерфейса, как пауза, потому что игрок должен иметь возможность увидеть имена. Данные читаются из того же списка: CREDITS.md служит и игроку, и разработчику одновременно. Перед релизом сверьте направления: каждый файл из assets/ упомянут, у каждой строки есть живой файл; расхождение в любую сторону — либо неоплаченный долг лицензии, либо мусор в репозитории. Имя файла не случайно: markdown читается в diff, на хостинге репозитория и в телефоне, а простой текст переживёт любой рефакторинг — таблица в редакторе документов таких гарантий не даёт.
Чек-лист принятия ассета в проект#
- Лицензия прочитана у конкретного пака, а не на главной странице источника
- Тип лицензии назван словами: CC0, CC-BY, CC-BY-SA, OFL или своё условие
- Для CC-BY записаны автор, источник и версия лицензии
- NC-варианты отсеяны, если игра когда-нибудь будет продаваться
- Файл лёг в assets/ без точки или подчёркивания в начале имени
- Строка в CREDITS.md добавлена тем же коммитом, что и файл
- Пункт титров в игре обновлён вместе с ассетом
- Непонятная лицензия означает поиск замены, а не обещание разобраться потом
Соберите объявление встроенных файлов
Восстановите два пропуска: имя пакета и тип встроенной файловой системы.
В песочнице сайта нет файловой системы проекта и директивы go:embed — код этого урока запускается только в локальном Go. Зато чтение лицензий, заведение CREDITS.md и выбор источников работают без компилятора, а место героя до первой настоящей картинки в песочнице занимает прямоугольник из примитивов: заглушка честнее отсутствующей картинки. Полный путь ассета отрабатывайте в своём окружении, а переносить имеет смысл то, что не зависит от файлов: шаблон строки титров и порядок шагов чек-листа.
Путь ассета: от скачивания до экрана
Расставьте шаги от пакета до работающего спрайта.
Строки
Ваша программа
Нажимайте на строки слева, чтобы собрать программу
Шрифты и звуки: отдельные правила#
Шрифты живут по своим законам: Google Fonts раздаёт большинство семейств под OFL — встраивать в игру можно и нужно, копию лицензии держите рядом с файлом шрифта, а продавать сам шрифт нельзя. Механика отрисовки текста уже готова из урока про шрифты — меняется только источник, а текстовый рисующий код не замечает подмены.
Звуки дисциплинируют сильнее графики: на Freesound лицензия назначается клипу, поэтому фильтр CC0 ставьте до прослушивания — иначе через час поиска никто не вспомнит, какой клип был под каким условием. NC-варианты отметайте сразу, если игра когда-нибудь окажется платной. Альтернатива без правовых вопросов — генераторы sfxr и Bfxr: ползунки, кнопка экспорта, и результат полностью ваш; выстрелы, прыжки и подбор монет генерируются за минуты и встают в аудио-систему как обычные файлы, встроенные тем же go:embed. Отдельный совет про музыку: треки ищите по тем же правилам, что и эффекты, только цена ошибки выше — фоновый трек слышен весь сеанс и именно его чаще всего забывают в титрах.
К концу урока у проекта появляется материальная часть: папка assets с честными лицензиями, встроенная в бинарник директивой go:embed, загрузчик, возвращающий готовые спрайты, и CREDITS.md, где у каждого ресурса есть строка. Это закрывает последний инфраструктурный вопрос перед содержательным: впереди гейм-дизайн с балансом и итоговый проект, где всё соберётся в одну аркаду. Домашнее задание проводит первый ассет по полному пути — от страницы источника до экрана и титров. И держите рядом правило проверки: непонятная лицензия — это не обещание разобраться потом, а немедленный поиск замены под CC0; в релизной сборке репутация живёт в тех же файлах, что и игра. Дисциплина переносится и вне игр: любой проект с чужими зависимостями — от иконок до библиотек — живёт по тем же правилам чтения лицензий.
Термины урока
Песочница урока
Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.
Запустите код, чтобы увидеть вывод.
Коротко: что запомнить
- Источник — витрина; лицензия живёт у конкретного пака: CC0, CC-BY, CC-BY-SA, OFL или своё условие.
- CC0 не требует ничего; CC-BY требует атрибуции; SA и NC опасны для закрытых коммерческих игр.
- Папка assets плюс go:embed пакует ассеты в бинарник и одинаково работает на всех платформах сборки.
- Пути внутри embed.FS сохраняют префикс assets; файлы с точкой или подчёркиванием в имени не встраиваются.
- Один загрузчик возвращает готовые ebiten.Image и честную ошибку с именем файла.
- CREDITS.md в корне и пункт титров в меню — исполнение атрибуции и часть релиза.
- Непонятная лицензия означает немедленный поиск замены под CC0, а не обещание разобраться потом.
Домашнее задание
Соберите первую партию ассетов по чек-листу урока. Скачайте два пака Kenney и один CC-BY-пак с OpenGameArt; создайте папку assets и CREDITS.md, внеся строку для каждого ресурса в момент скачивания. Подключите go:embed и замените прямоугольник героя на спрайт из урока про спрайты — загрузку оформите через LoadAssets с проверкой ошибок и понятными сообщениями. Добавьте в меню пункт «Credits» и выведите титры на экран в сцене из урока про сцены. Соберите бинарь и WASM-версию из урока про сборку: на встроенных ассетах обе должны запуститься одинаково. Найдите на Freesound один CC0-звук и один NC — второй не подключайте, а запишите в заметку, почему нельзя. В конце проверьте, что файлы с точкой или подчёркиванием в начале имени не попали в assets: embed их молча пропустит. Финальная проверка — запустить бинарь из другой папки: встроенные ассеты обязаны загрузиться без зависимости от текущей директории, потому что едут внутри бинарника.
Личные заметкиПусто
Вопросы и ответы по уроку
Можно ли брать ассеты из Unity Asset Store или Figma Community в игру на Ebitengine?
Каждый магазин пишет свои условия, и они не привязаны к движку напрямую, но часто ограничивают рантайм или требуют упоминания магазина. Правило то же: читать лицензию конкретного пака до скачивания. Универсальные CC0-источники дешевле по вниманию: условия знакомые и короткие, а если сомнение осталось — пишите автору: молчаливое «наверное можно» в релизе хуже отказа.
Kenney просит указывать себя? Пак ведь CC0.
Не просит: CC0 снимает обязанность атрибуции. Строка в CREDITS.md остаётся хорошей практикой — при обновлении пака вы вспомните, откуда взяли файл, а не будете искать источник по названию спрайта через полгода. Та же строка — публичное уважение к чужому труду: авторы видят использование и продолжают делиться.
Ассет уже в игре, а лицензия нашлась позже — что делать?
Прочитать её спокойно. Если условия исполняются — дописать CREDITS.md и жить дальше. Если нет — NC в платной игре или SA в закрытом проекте — заменить ассет и вычистить файл из релиза; замена через загрузчик урока — правка одной строки пути, остальной код подмену не замечает.
Термины курса
Понятия, на которых строится этот курс, — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылок на практику.
Изучайте дальше
Следующая ступень учебного пути
Chromedp в Go: автоматизация Chrome без Selenium
Курс chromedp для Go: навигация, селекторы, клики и формы, скриншоты и PDF, JS-оценка, вкладки, прокси, пул браузеров и скрапинг. 25 уроков.
- Запускать Chrome из Go и управлять страницами
- Находить элементы селекторами и ждать их появления
- Кликать, заполнять формы и извлекать данные
- Делать скриншоты, PDF и выполнять JavaScript