Первый предмет
Мы называем предметами вещи, которые находятся в инвентаре или контейнере. Эта обширная категория включает в себя материалы для крафта, еду, инструменты, броню и подобные. Существуют даже бесполезные предметы, вроде гнилой картошки. Игрок может взаимодействовать с ними, надевать на себя, кидать или съедать, это основные игровые объекты для мира и начала изучения.
Создадим текстуру
Это первый и самый главный шаг к созданию предмета, от визуально приятной текстуры зависит многое, и возможно даже, общее впечатление от нововведения. Внутреигровые тексуры предметов представляют собой растровые изображения (.png или .tga) размером 16x16 пикселей. И если размер, при необходимости, может быть каким угодно, то расширения файлов ограничены лишь этими двумя.
Создайте новую текстуру или используйте существующую, во втором случае убедитесь что она представлена в поддерживаемом формате. Для примера мы перекрасили стандартную текстуру палки, это вполне распространенная практика — например, текстуры руд и инструментов в некоторых модах созданы именно так.
->
Поместим ее в ресурсы
Текстуры для предметов располагаются в подпапке items-opaque в одной или нескольких папках ваших ресурсов. Прежде всего, убедитесь что build.config содержит хотя бы один ресурс с типом resource
:
{
...
"resources": [
...
{
"path": "assets/resources/",
"resourceType": "resource"
}
]
}
Так выглядит часть содержимого папки с текстурами предметов в игре:
/assets/resource_packs/vanilla/textures/items
├─ apple.png
├─ apple_golden.png
├─ armor_stand.png
└─ ...
Формат именования файлов текстур предметов в Inner Core немного отличается от него: some_texture_<мета>.png
, где мета - целочисленное число, определяющее вариацию текстуры. Оставим ее нулем.
Создали папку items-opaque в одной из папок ресурсов? Теперь поместите текстуру с правильным названием в нее. В примере полным путем будет что-то вроде assets/resources/items-opaque/oxidized_stick_0.png. Все готово!
Зарегистрируем предмет
Перед этим создайте файл в вашей рабочей директории мода (например, папке dev/) или откройте существующий скрипт. Не забудьте включить его в .includes если это необходимо. Мы будем работать в файле oxidized_stick.js.
Для начала нам необходимо зарезервировать за собой идентификатор:
IDRegistry.genItemID("oxidized_stick");
А теперь мы можем создать и сам предмет:
Item.createItem("oxidized_stick", "item.oxidized_stick.name", {
name: "oxidized_stick", data: 0
}, { stack: 64 });
Дополним получившийся код переводом, итоговый вариант будет выглядеть так:
Translation.addTranslation("item.oxidized_stick.name", {
en: "Oxidized Stick",
ru: "Окислившаяся палка"
});
IDRegistry.genItemID("oxidized_stick");
Item.createItem("oxidized_stick", "item.oxidized_stick.name", {
name: "oxidized_stick", data: 0
}, { stack: 64 });
Разберем происходящее
Все начинается с создания перевода. Это одна из практик хорошего тона.
Прежде чем создать предмет, мы генерируем числовой идентификатор для строкового. В игре он будет представлен как minecraft:item_<идентификатор>
, в нашем случае minecraft:item_oxidized_stick
.
И наконец, вызывается комплексный метод Item.createItem, вот его параметры:
- Зарегистрированный строковый идентификатор.
- Имя предмета; мы не обязаны использовать формат
item.<идентификатор>[.<состояние>].name
здесь, и могли бы просто назвать предмет"Oxidized Stick"
или"Окислившаяся палка"
, но тогда потеряется смысл локализации. - Объект, представляющий текстуру; текстура это исключительно имя файла без расширения, подпапки вроде
assets/resources/category
в нее не входят. Мета это и есть наше число после слеша в конце. - Дополнительные свойства предмета, в данном случае мы задаем стандартный размер стака (максимального количества предметов в одной ячейке инвентаря или контейнера).
Игровые идентификаторы могут описывать материал, тип предмета и свойство или цвет в одном месте. Для реализации новых идентификаторов должна быть использована именно подобная последовательность, например diamond_pickaxe
или minecart_command_block
. Разделяйте элементы описания с помощью _
.
Однако, существуют и исключения вроде appleEnchanted
, muttonCooked
, muttonRaw
. Состояния предмета должны быть приписаны в конце основного идентификатора с заглавной буквы.
Технические предметы
По умолчанию, любые предметы которые вы создаете добавляются в инвентарь творческого режима. Если же нам необходимо изменить логику этого поведения, для каждого типа предметов можно дополнить последний параметр регистрации:
Item.createItem("oxidized_stick", "item.oxidized_stick.name", {
name: "oxidized_stick", data: 0
}, {
stack: 64,
isTech: true
});
Пример такого технического предмета — яйцо дракона. Его нет в творческом инвентаре, но его все еще можно получить с помощью команды /give
.
Привяжем событие
Пока мы лишь создали предмет, он не имеет функционала, и является тем самым бесполезным предметом из начала статьи. Обратимся к калбекам, на их основе можно реализовать большую, если не всю логику взаимодействия.
Следующая функция привяжет калбек ItemUse к предмету:
- JavaScript
- TypeScript
Item.registerUseFunction("oxidized_stick", function(coords, item, block, playerUid) {
Entity.addVelocity(playerUid, 0, 0.5 * Math.random(), 0);
});
Item.registerUseFunction("oxidized_stick", (coords, item, block, playerUid) =>
Entity.addVelocity(playerUid, 0, 0.5 * Math.random(), 0));
Под использованием предмета подразумевается нажатие им по любому блоку или его удержание в воздухе, как например при поедании еды. В нашем случае палка якобы будет отталкивать игрока со случайной скоростью, если тот воспользуется ей.
Ускорение задается в блоках за тик, где в одной секунде 20 тиков. То есть, максимальное ускорение за секунду может достичь 10 блоков в секунду (0.5 блоков/сек. * 20 тиков). Мы еще рассмотрим ускорение подробнее в будущем.
Метод приравнивается к вызову другого метода, который регистрирует событие уже по числовому идентификатору:
- JavaScript
- TypeScript
Item.registerUseFunctionForID(ItemID.oxidized_stick, function(coords, item, block, playerUid) {
Entity.addVelocity(playerUid, 0, 0.5 * Math.random(), 0);
});
Item.registerUseFunctionForID(ItemID.oxidized_stick, (coords, item, block, playerUid) =>
Entity.addVelocity(playerUid, 0, 0.5 * Math.random(), 0));
Объект ItemID предоставляет числовые идентификаторы для идентификаторов предметов, которые были созданы в следствии вызова метода IDRegistry.genItemID. Для игры основными являются именно числовые идентификаторы, строковые же отображаются в различных интерфейсах и используются нами для удобства.
Почему просто не воспользоваться калбеком?
Вариант со схожим функционалом выглядит так:
- JavaScript
- TypeScript
Callback.addCallback("ItemUse", function(coords, item, block, isExternal, playerUid) {
if (item.id == ItemID.oxidized_stick) {
Entity.addVelocity(playerUid, 0, 0.5 * Math.random(), 0);
}
});
Callback.addCallback("ItemUse", (coords, item, block, isExternal, playerUid) =>
item.id == ItemID.oxidized_stick && Entity.addVelocity(playerUid, 0, 0.5 * Math.random(), 0));
Вот список дополнительных проверок, которые осуществляет функция Item.registerUseFunction перед вызовом вашего события:
- Проверяется является ли блок тайлом, мы еще рассмотрим их, главное здесь лишь знать что они могут прервать дальнейший вызов события.
- В случае если у блока есть интерфейс (например открылся верстак или сундук), событие будет остановлено.
- Если же интерфейс не открылся или игрок находится на шифте (в таком случае интерфейс не открывается) событие будет вызвано.
В случае регистрации калбека эти проверки необходимо будет реализовывать самостоятельно, так что мы не использовали прямую регистрацию этого калбека в примере. Ну и не забывайте о проверке идентификатора, калбек вызывается при использовании любого предмета.