Перемещение, вращение и масштаб
Позиция, поворот и масштаб созданных, найденных и выделенных объектов BDEngine: setPosition, setRotation, setScale, единицы и обновление редактора.
Чтобы переместить созданный блоковый дисплей или объект из выделения, используйте методы самого объекта. Они подходят и для встроенных объектов редактора; создавать собственный класс для этого не нужно.
Какой объект можно изменить
BlockDisplay, ItemDisplay, TextDisplay и обычные группы Collection наследуют методы трансформации от Selectable. Получите живой объект через editorAPI.add, editorAPI.find или editorAPI.getSelectedObjects и вызовите нужный метод на нём. Это одна и та же операция независимо от того, как вы получили объект.
Например, создайте обычный блоковый дисплей и задайте его положение, поворот и масштаб:
const block = await editorAPI.add( 'stone', 'BlockDisplay', null, true);if (block) { block.setPosition({ x: 2, y: 1, z: 0 }); block.setRotation({ y: 90 }); block.setScale({ x: 0.5, y: 0.5, z: 0.5 }); editorAPI.update(true);}Или переместите один уже выделенный блоковый дисплей на единицу по локальной Y:
const block = editorAPI.getSelectedObjects() .find(object => object.isBlockDisplay && !object.isStructureBlock);if (block) { const position = block.getPosition(); block.setPosition({ y: position.y + 1 }); editorAPI.update(true);}Примеры рассчитаны на готовый редактор в обычном режиме редактирования.
Для настоящих блоков StructureBlock действуют другие правила: целочисленная
позиция, отключённые вращение и масштабирование. У групп структур вращение и
масштаб зависят от режима предпросмотра структуры. Наличие метода ещё не означает,
что любой служебный объект поддерживает ту же операцию.
editorAPI остаётся стабильной публичной точкой входа. Методы полученного объекта относятся к классам редактора; сам факт получения через editorAPI не делает все его свойства частью стабильного API. Различие описано в editorAPI и внутреннем editor. Собственный класс и геометрия рассматриваются отдельно в собственных объектах и зависимостях.
Координаты и общие правила
Описанные ниже сеттеры и геттеры синхронны. Позиция, вращение и масштаб локальны относительно родителя. Сеттеры по умолчанию помечают изменившуюся геометрию, рамки и данные пересечения для обновления, но сами не создают Undo-команду, не рассылают трансформацию в Share Party и не обновляют все панели.
У сеттеров есть skipDirty = false. В обычном плагине оставьте значение
по умолчанию. true пропускает служебную отметку изменения и требует
самостоятельного управления обновлениями.
Для setPosition, setRotation и setScale можно передать часть осей:
отсутствующая или равная undefined ось остаётся без изменения. Переданные
значения должны быть конечными числами. Строки, NaN и бесконечности вызывают
ProjectValidationError; при ошибке набор значений не применяется частично.
При повёрнутом или масштабированном родителе локальная Y может не совпадать
с мировой вертикалью, а перемещение на 1 не обязательно даст один блок в мире.
Сеттер задаёт итоговое локальное значение; чтобы сдвинуть объект относительно
текущей позиции, сначала прочитайте getPosition(), как в примере выше.
У параметра objPos в editorAPI.add другой контракт: это начальное смещение
в мировых координатах. Не подменяйте им описание setPosition.
Перемещение
setPosition
object.setPosition({ x, y, z }, skipDirty = false) меняет локальную позицию.
Единицы - единицы сцены BDEngine, для обычных дисплеев одна единица соответствует
одному блоку Minecraft. Значения округляются по object.stepPosition
(по умолчанию 0.000625). Возвращает undefined.
object.setPosition({ x: 2, z: -1 }); // Y сохраняется.getPosition
object.getPosition() возвращает новый обычный объект { x, y, z } с
округлёнными локальными координатами. Изменение этого результата не меняет
исходную позицию. Сам геттер позицию не переписывает.
const position = object.getPosition();object.setPosition({ y: position.y + 1 });Вращение
setRotation
object.setRotation({ x, y, z }, skipDirty = false) принимает градусы,
округляет по object.stepRotation (по умолчанию 0.01) и обновляет
соответствующие углы Three.js. Возвращает undefined.
object.setRotation({ y: 90 });В отличие от этого метода, обычное свойство Three.js object.rotation
содержит радианы. Не передавайте градусы напрямую в object.rotation.y.
getRotation
object.getRotation() возвращает { x, y, z } в градусах.
Если внутреннее представление ещё не создано, оно вычисляется из вращения.
В отличие от getPosition(), здесь возвращается ссылка на внутренний
customRotation. Для снимка скопируйте её. Изменение этой ссылки вручную
не запускает пересчёт Three.js-вращения и уведомления об изменении:
const rotation = { ...object.getRotation() };object.setRotation({ y: rotation.y + 15 });Углы могут сохранять накопленные обороты. Не ожидайте обязательной нормализации
в диапазон от -180 до 180.
setQuaternionRotation
object.setQuaternionRotation(quaternion, skipDirty = false) копирует
кватернион и обновляет представление поворота в градусах с учётом изменения
относительно предыдущего кватерниона. Возвращает undefined; пустой аргумент
ничего не меняет.
Передавайте нормализованный THREE.Quaternion. Проверка требует конечные
компоненты x/y/z/w и ненулевую длину, но метод не нормализует присваиваемый
кватернион автоматически. Невалидный кватернион вызывает ProjectValidationError.
const quaternion = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3(0, 1, 0), Math.PI / 2);object.setQuaternionRotation(quaternion);Угол в setFromAxisAngle - радианы, а getRotation() по-прежнему возвращает
градусы. Кватернион описывает ориентацию, но сам по себе не хранит число полных
оборотов, поэтому не используйте его как замену многовитковым ключам анимации.
Масштаб
setScale
object.setScale({ x, y, z }, skipDirty = false) задаёт множители масштаба.
Значения округляются по stepScale (по умолчанию 0.0001) и ограничиваются
снизу minScale (по умолчанию 0.0011). Возвращает undefined.
У частицы дополнительно обновляет масштаб её gizmo.
object.setScale({ x: 2, y: 2, z: 2 });Нулевой или отрицательный масштаб не создаёт нулевой размер или отражение:
он поднимается до минимального положительного значения. Для поддерживаемых
объектов отражение задаётся отдельно через setMirrorX.
getScale
object.getScale() возвращает новый объект { x, y, z }.
Геттер может изменить исходный объект: если текущий масштаб не соответствует
округлению или минимуму, он вызывает setScale и обновляет локальную и мировую
матрицы. Поэтому это не всегда чтение без побочных эффектов.
Скосы, отражение и матрицы
Аффинная трансформация включается для объектов, у которых isDisplay или
isCollection истинно. У обычного собственного наследника Selectable
это не включено. Не назначайте эти флаги только ради эффекта: другие системы
редактора ожидают соответствующий встроенный тип.
Таблица описывает базовые методы Selectable. Специализированные типы могут
их переопределять: например, StructureBlock не применяет скос и отражение,
а группа структуры также отключает эти операции.
| Метод | Контракт |
|---|---|
supportsAffineTransform() |
Возвращает boolean, включена ли поддержка скоса и отражения |
getShear() |
Возвращает копию { xy, xz, yz }, углы в радианах |
setShear({ xy, xz, yz }, skipDirty = false, updateMatrix = true) |
Обновляет указанные компоненты. Для каждой нужен конечный угол строго между -Math.PI / 2 и Math.PI / 2; неверный угол возвращает false без изменения, успех - true |
getMirrorX() |
Возвращает boolean отражения по локальной X |
setMirrorX(value, skipDirty = false, updateMatrix = true) |
Приводит значение к boolean, обновляет матрицу и служебные данные по флагам. Возвращает undefined |
setFromAffineMatrix(matrix, options = {}) |
Разбирает THREE.Matrix4 в компоненты и возвращает сам объект |
applyMatrix4(matrix) |
Применяет матрицу слева к локальной матрице, возвращает сам объект |
updateMatrix() |
Пересобирает локальную матрицу с учётом поддерживаемых скоса и отражения; возвращает undefined |
setShear допускает частичный набор осей. Значения очень близко к границе
дополнительно ограничиваются до Math.PI / 2 - 0.000001 по модулю.
У setFromAffineMatrix доступны referenceRotation = null (опорный
THREE.Euler), skipDirty = false и updateWorld = true.
Для объекта без аффинной поддержки матрица раскладывается в обычные позицию,
кватернион и масштаб.
if (object.supportsAffineTransform()) { object.setShear({ xy: THREE.MathUtils.degToRad(10) }); object.setMirrorX(true); editorAPI.update(true);}Обновление, история и совместная работа
После прямых изменений вызовите editorAPI.update. Если изменялся выделенный объект или само выделение, передайте true, чтобы редактор также пересобрал временное выделение контроллера. Для серии изменений достаточно одного вызова после всех сеттеров:
const block = editorAPI.getSelectedObjects() .find(object => object.isBlockDisplay && !object.isStructureBlock);if (block) { block.setPosition({ x: 2 }); block.setRotation({ y: 45 }); block.setScale({ x: 1.5, y: 1.5, z: 1.5 }); editorAPI.update(true);}Сеттеры помечают данные для обновления, но не создают отдельную команду Undo/Redo
и не передают произвольные изменения участникам Share Party. editorAPI.update
этого тоже не делает и не сохраняет файл. Даже если объект создан через add
с включённой историей, последующие прямые трансформации не становятся отдельными
отменяемыми действиями автоматически.
Если плагину нужны собственные команды истории или синхронизация, их потребуется реализовать через внутренние механизмы editor и проверять при обновлениях. Для программного выделения см. свойство selected.