Внутреигровые формы
Помимо стандартных "полноблочных" блоков, формы могут быть самыми разными. Игра предоставляет различные вариации базовых моделей, таких как ступеньки или полублоки. Обычно их реализации используются совместно со стандартными, полноблочными блоками. Здесь представлено большинство существующих форм, а также различные типы смешивания текстур атласа.
Определимся с форматом
Прежде всего, форма блока может быть изменена несколькими способами. Это дополни тельные свойства посредством добавления внутреигрового типа, любая параллелепипедная форма (в виде коробки; или же шейп), рендеры с использованием коробок или создания разверток меж вершин, а также нативное изменение формы. Мы поверхностно рассмотрим все кроме последнего.
Для регистрации блока с такой формой воспользуемся дополнительными свойствами:
const BLOCK_TYPE_SOME_NAME = Block.createSpecialType({
rendertype: 0 // просто цельный блок, базовое значение
// некоторые свойства, которые будут изменены: если в примере
// подается лишь объект, его необходимо выделить именно сюда
});
И помимо этого, некоторым формам нужно будет добавить функционал.
Листва
Не учитывая различные интеграции вроде Better Foliage, листва это полноблочный блок лишь с измененными дополнительными свойствами. Общее определение сводится лишь к паре функций:
IDRegistry.genBlockID("oxidized_leaves");
Block.createBlock("oxidized_leaves", [{
name: "tile.oxidized_leaves.name",
texture: [["oxidized_leaves", 0]],
inCreative: true
}], BLOCK_TYPE_LEAVES);
И конечно же, перед этим определите BLOCK_TYPE_LEAVES по формату, и желательно, в отдельном месте для всех блоков:
{
base: VanillaBlockID.leaves,
explosionres: 1,
renderlayer: EBlockRenderLayer.RAY_TRACED_WATER,
renderallfaces: true,
lightopacity: 1,
translucency: 0.5,
destroytime: 0.7,
sound: "grass"
}
Translation.addTranslation("tile.oxidized_leaves.name", {
en: "Oxidized Leaves",
ru: "Окислевшаяся листва"
});
Стекло и панели
Для реализации стекол достаточно добавить прозрачность текстурам и изменить их уровень поглощения света. Помимо самого блока стекла, вероятно, вы захотите реализовать и панели, отдельно, или вместе с этим стеклом.
Определим еще один окислевшийся блок, но теперь уже стекла и панелей из него:
IDRegistry.genBlockID("oxidized_glass");
Block.createBlock("oxidized_glass", [{
name: "tile.oxidized_glass.name",
texture: [["oxidized_glass", 0]]
}], BLOCK_TYPE_GLASS);
IDRegistry.genBlockID("oxidized_glass_pane");
Block.createBlock("oxidized_glass_pane", [{
name: "tile.oxidized_glass_pane.name",
texture: [["oxidized_glass", 0]]
}], BLOCK_TYPE_GLASS_PANE);
Дополнительные свойства для прозрачных стекол будут выглядеть весьма просто:
{
// TODO: это внутреигровая форма стекла, но я не уверен
// следует ли ее использовать; реальный пример лишь один
// rendertype: 4,
renderlayer: EBlockRenderLayer.RAY_TRACED_WATER,
lightopacity: 1,
destroytime: .4,
sound: "glass"
}
{
rendertype: 87,
renderlayer: EBlockRenderLayer.RAY_TRACED_WATER,
lightopacity: 1,
destroytime: .4,
sound: "glass"
}
И пусть автор этой статьи против использования "жабных фишек", но соединения меж стекол выглядят действительно неплохо. Попробуйте библиотеку Connected Texture для подобной реализации:
ConnectedTexture.setModelForGlass(BlockID.oxidized_glass, -1, "oxidized_glass");
Translation.addTranslation("tile.oxidized_glass.name", {
en: "Oxidized Glass",
ru: "Окислевшееся стекло"
});
Translation.addTranslation("tile.oxidized_glass_pane.name", {
en: "Oxidized Glass Pane",
ru: "Окислевшаяся стеклянная панель"
});
Растения
Можно разделить на три типа: зерновые культуры, саженцы и различные виды травы с цветами. Первые представляют собой горизонтальные пересечения нескольких слоев текстур, тогда как остальные состоят из пары текстур, расположены наискосок и пересекаются в центре. Разница между двумя последними в отсутствии случайного расположения внутри блока для первого.
Начнем с создания розоподобного растения, это весьма просто:
IDRegistry.genBlockID("oxidized_rose");
Block.createBlock("oxidized_rose", [{
name: "tile.oxidized_rose.name",
texture: [["oxidized_rose", 0]],
inCreative: true
}], BLOCK_TYPE_PLANT);
BlockRenderer.setCustomCollisionShape(BlockID.oxidized_wheat, -1, new ICRender.CollisionShape());
Определите дополнительные свойства перед созданием блока:
{
base: VanillaBlockID.tallgrass,
explosionres: 0,
rendertype: 6,
lightopacity: 0,
destroytime: 0,
sound: "grass"
}
Можете также реализовать разрушение блока, если блок под растением будет разрушен:
Callback.addCallback("DestroyBlock", function(coords, block, playerUid) {
let region = BlockSource.getDefaultForActor(playerUid);
if (region.getBlockId(coords.x, coords.y + 1, coords.z) == BlockID.oxidized_rose) {
region.destroyBlock(coords.x, coords.y + 1, coords.z);
}
});
В целом этого вполне достаточно для декоративных растений. Но когда дело доходит до семян и других зерновых культур, их создание может потребовать чуть большего времени.
Рассмотрим создание простой бахчи, добавив события и функционал:
IDRegistry.genBlockID("oxidized_wheat");
Block.createBlock("oxidized_wheat", [{
name: "tile.oxidized_wheat.name",
texture: [["oxidized_wheat", 0]]
}], BLOCK_TYPE_CROP);
BlockRenderer.setCustomCollisionShape(BlockID.oxidized_wheat, -1, new ICRender.CollisionShape());
Не забудьте прежде объявить дополнительные свойства, правила почти те же что и других растений:
{
base: VanillaTileID.wheat,
explosionres: 1,
rendertype: 1,
lightopacity: 0,
destroytime: 0,
sound: "grass"
}
Мы не добавляем пшеницу в творческий инвентарь, так как обычно на такой случай реализовывают предмет для установки блока:
IDRegistry.genItemID("oxidized_wheat");
Item.createItem("oxidized_wheat", "item.oxidized_wheat.name", {
name: "oxidized_wheat", data: 0
}, { stack: 64 });
Item.registerUseFunction("oxidized_wheat", function(coords, item, block, playerUid) {
if (block.id == VanillaTileID.farmland && coords.side == 1) {
let region = BlockSource.getDefaultForActor(playerUid);
let block = region.getBlock(coords.relative.x, coords.relative.y, coords.relative.z);
if (World.canTileBeReplaced(block.id, block.data)) {
region.setBlock(coords.relative.x, coords.relative.x, coords.relative.x, BlockID.oxidized_wheat, 0);
}
}
});
Block.registerNeighbourChangeFunction("oxidized_wheat", function(coords, block, changedCoords, region) {
if (region.getBlockId(coords.x, coords.y - 1, coords.z) != VanillaTileID.farmland) {
region.destroyBlock(coords.x, coords.y, coords.z);
}
});
Block.registerDropFunction("oxidized_wheat", function(coords, blockID, blockData, level) {
return [[ItemID.oxidized_wheat, Math.floor(Math.random() * 3 + 1), 0]];
});
Так, предмет пшеницы установит семена на грядку; если обновление соседнего блока приведет к отсутствии грядки под растением, будет вызвано событие его разрушения; а разрушение выбросит случайное количество предмета от 1 до 3. Почему пшеница размещает семена пшеницы?.. Вероятно, окислевшаяся пшеница может разложиться до семян. Реализуйте предмет семян самостоятельно если вам нужна внутреигровая форма растения.
Если вам понадобится создать росток для дерева, используйте случайный тик как для роста растений, так и для бахчевых культур; дополнительные свойства будут выглядеть так:
{
base: VanillaBlockID.sapling,
explosionres: 1,
rendertype: 109,
renderallfaces: true,
lightopacity: 1,
translucency: .5,
destroytime: 0,
sound: "grass"
}
Воспользуйтесь библиотекой CropLib для реализации роста растений, грядок и удобрений.
Translation.addTranslation("tile.oxidized_rose.name", {
en: "Oxidized Rose",
ru: "Окислевшееся роза"
});
Translation.addTranslation("item.oxidized_wheat.name", {
en: "Oxidized Wheat",
ru: "Окислевшаяся пшеница"
});
Translation.addTranslation("tile.oxidized_wheat.name", {
en: "Oxidized Crops",
ru: "Окислевшиеся зерновые культуры"
});
Стены и забор
Наиболее примитивная реализация из всех видов форм; игра автоматически создает соединения с соседними блоками, что значительно упрощает весь процесс. Достаточно лишь дополнительных свойств:
IDRegistry.genBlockID("oxidized_log_fence");
Block.createBlock("oxidized_log_fence", [{
name: "tile.oxidized_log_fence.name",
texture: [["oxidized_log_top", 0]]
}], BLOCK_TYPE_WOODEN_FENCE);
IDRegistry.genBlockID("oxidized_log_wall");
Block.createBlock("oxidized_log_wall", [{
name: "tile.oxidized_log_wall.name",
texture: [["oxidized_log_top", 0]]
}], BLOCK_TYPE_WOODEN_WALL);
Ну и не забудьте о дополнительных свойствах для обоих блоков в том же порядке:
{
rendertype: 11,
renderlayer: EBlockRenderLayer.BLEND,
lightopacity: 1,
sound: "wood"
}
{
rendertype: 32,
renderlayer: EBlockRenderLayer.BLEND,
lightopacity: 1,
sound: "wood"
}
Разница между ними лишь в толщине стенок и видами соединений. Представьте себе забор и стены из булыжника.
Translation.addTranslation("tile.oxidized_log_fence.name", {
en: "Oxidized Log Fence",
ru: "Забор из окислевшегося бревна"
});
Translation.addTranslation("tile.oxidized_log_wall.name", {
en: "Oxidized Log Wall",
ru: "Стена из окислевшегося бревна"
});