Инвентарь, добыча ресурсов, крафт и сохранение survival-игры в один контур. Никакой новой механики — намеренно классическая система, ценность которой в границе ответственности: C++ описывает правила, ассеты описывают содержание. Новый предмет, инструмент, одежда или рецепт добавляются из редактора обычными Data Asset и Blueprint — без строчки кода, без пересборки и без меня.
Код не знает, что в игре есть кокос, каменный топор или плащ. Он знает, что бывают предметы, у предметов есть тип инструмента, а рецепты превращают одни предметы в другие.
Дизайнер работает не с кодом, а с данными — прямо в окнах свойств редактора. Новый предмет здесь не новый класс, а новый ассет. Та же линия проходит и через сохранение: сейв хранит ссылки на ассеты, а не их содержимое, поэтому правка иконки или питательности кокоса не ломает старые сохранения.
На схеме снизу средняя колонка — правила в C++. Она не меняется ни в одном сценарии: подсвечивается только то, что уже написано и просто начинает работать с новыми данными. Слева дизайнер создаёт ассет (прямо в редакторе), справа появляется игровой результат.
Это и есть весь фокус системы: контент растёт, код стоит на месте. Счётчик внизу схемы всегда показывает ноль.
UItemDataAsset; неиспользуемые поля просто остаются нулевыми.
EditCondition только у съедобного предмета — нерелевантных настроек дизайнер просто не видит.
Как я и сказал один ассет — один вид предмета. Поля сгруппированы по назначению, поэтому один класс обслуживает ресурсы, инструменты, еду, одежду и все остальное.
Поля восстановления активируются в редакторе только у съедобного предмета. Дизайнер физически не видит нерелевантных настроек — а значит не заполнит их по ошибке.
Результат, его количество и массив пар «предмет + количество». Рецепт из одного компонента и рецепт из шести описываются одинаково и обрабатываются одним циклом.
// целиком редактируется в окне свойств DisplayName : "Каменный топор" RecipeIcon : T_Icon_StoneAxe ResultItem : DA_Item_StoneAxe ResultQuantity : 1 Ingredients : [ { Item: DA_Item_Wood, Quantity: 3 }, { Item: DA_Item_Stone, Quantity: 2 } ]
Третий тип данных, UResourceNodeData, описывает дерево или залежь: требуемый инструмент, прочность, выпадающий предмет. Проверка соответствия инструмента — одна строка сравнения ToolType с RequiredTool: дизайнер выбирает «Axe» в выпадающем списке, и правило начинает действовать.
Две записи из проекта: как контент создаётся в редакторе и как состояние переживает перезаход.
Центральное решение системы, и оно следует прямо из того, как Unreal именует акторов. У расставленного на карте дерева имя стабильно между запусками — достаточно запомнить факт «уничтожено», и актор сам удалит себя в BeginPlay. У выпавшего лута имя генерируется по порядку спавна и в следующей сессии будет другим — такие объекты сохраняются целиком и пересоздаются.
Различает их флаг bIsRuntimeDrop, выставляемый в момент спавна. Без этого разделения возможна тихая ошибка: сгенерированное имя случайно совпадает с именем расставленного объекта, и предмет исчезает при загрузке без всяких сообщений.
Порядок критичен: BeginPlay у разных акторов вызывается независимо, и часть состояния перетирается значениями по умолчанию, если применить её слишком рано.
Игрок рубит дерево топором, подбирает три доски, крафтит плащ, надевает его и жмёт P. В файл попадут имя срубленного дерева, инвентарь после списания досок, ссылка на DA_Cloack в слоте одежды и фаза суток. При загрузке дерево не вернётся, плащ окажется надет, а защита от жары снова начнёт действовать — потому что она вычисляется из поля Protection того же ассета.
Реальные сценарии. Ни один не требует правки C++ или пересборки проекта.
UItemDataAsset: имя, иконка, меш, стак.AvailableRecipes виджета крафта.ToolType и ToolDamage.EquipMesh — меш в руке.ToolType с RequiredTool — удары наносятся.
Category → Cloth.Overlay для накидки или BodySwap для замены тела.Protection → Heat или Cold.UResourceNodeData: прочность, инструмент, дроп, разброс.AResourceNode с этим ассетом.Перечисления EItemType, EToolType и EClothProtection заданы в C++: новый вид материала или принципиально новый класс инструмента — это правка кода. Внутри существующих категорий предметов можно создавать сколько угодно. Массив AvailableRecipes тоже заполняется вручную — осознанное упрощение, которое стоит заменить автоматическим сбором ассетов через Asset Manager, и тогда третий шаг из CASE 01 исчезнет совсем.