player/src/engine/PrimitiveTypes.js
МИН a46829c5f7
Some checks failed
CI / Lint (pull_request) Failing after 42s
CI / Build (pull_request) Successful in 1m30s
CI / Secret scan (pull_request) Successful in 2m28s
CI / PR size check (pull_request) Successful in 6s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
feat: синхронизация движка плеера со студией (задачи 01-07)
Плеер отстал на несколько задач — игры из студии не открывались с механиками.
Перенёс из rublox-studio в движок плеера:

Новые файлы движка:
- engine/ModalManager.js (задача 04 — модальные сцены)
- engine/BillboardUiManager.js (задача 01 — 3D-таблички)

Точечный перенос в существующие файлы:
- ScriptSandboxWorker.js: namespace game.modal/billboard/environment, скины в
  game.player, game.gui.tween, _guiHandlerKeys(localId), события
  modalOpened/modalClosed/skinChanged/billboardClick
- GameRuntime.js: команды modal.*/billboard.*/player.setSkin.*/gui.tween +
  _broadcastSkinsSnapshot/_ensureSkinState + routeGlobalEvent с localId
- PlayerController.js: non-humanoid скины (loadNonHumanoid+reloadSkin+
  процедурная анимация+pivot-центрирование), setInputBlocked/focusOnTarget,
  камера задачи 02 (zoom/shift-lock), клавиша B (магазин)
- BabylonScene.js: init modalManager/billboardUiManager, методы магазина скинов,
  чтение scene.skins, modalManager.tick, Esc-приоритет
- ScriptSandbox.js: sendSkinsSnapshot
- GuiManager.js: поля анимаций задачи 03 (синхронизирован со студией)
- PrimitiveTypes.js / PrimitiveManager.js: тип billboard + рендер

React-слой (editor-shared):
- ModalOverlay.jsx, SkinShopOverlay.jsx (новые) + подключены в KubikonPlayer
- GuiOverlay.jsx, GameHud.jsx синхронизированы со студией

eslint.config: послабления стилевых правил (no-empty off и т.п.).

Локальный build зелёный.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 03:15:43 +03:00

120 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* PrimitiveTypes — параметрические 3D-примитивы (как Part в Roblox).
*
* Каждый тип:
* id — стабильный ключ
* name — отображаемое имя
* icon — emoji для палитры
* defaultScale — стартовый размер (X, Y, Z)
* defaultColor — цвет
*
* kind:
* geometry — обычная видимая фигура (cube/sphere/cylinder/...)
* trigger — невидимый объём, события на касание
* checkpoint — точка респавна (подсвечена)
*
* Создание mesh идёт в PrimitiveManager._createMeshForType.
*/
export const PRIMITIVE_TYPES = [
// === Геометрия ===
{ id: 'cube', name: 'Куб', icon: 'prim-cube', kind: 'geometry',
defaultScale: { x: 1, y: 1, z: 1 }, defaultColor: '#9ca3af' },
{ id: 'sphere', name: 'Сфера', icon: 'prim-sphere', kind: 'geometry',
defaultScale: { x: 1, y: 1, z: 1 }, defaultColor: '#3b82f6' },
{ id: 'cylinder', name: 'Цилиндр', icon: 'prim-cylinder', kind: 'geometry',
defaultScale: { x: 1, y: 2, z: 1 }, defaultColor: '#f59e0b' },
{ id: 'cone', name: 'Конус', icon: 'prim-cone', kind: 'geometry',
defaultScale: { x: 1, y: 2, z: 1 }, defaultColor: '#a83232' },
{ id: 'plane', name: 'Плоскость', icon: 'prim-plane', kind: 'geometry',
defaultScale: { x: 4, y: 0.1, z: 4 }, defaultColor: '#7a8071' },
{ id: 'torus', name: 'Тор', icon: 'prim-torus', kind: 'geometry',
defaultScale: { x: 1, y: 0.4, z: 1 }, defaultColor: '#22d3ee' },
// Клин — куб со срезанной верхней гранью (наклонная плоскость).
// Для пандусов, рамп, крыш. Скос идёт по оси Z (выше при +Z).
{ id: 'wedge', name: 'Клин', icon: 'prim-wedge', kind: 'geometry',
defaultScale: { x: 1, y: 1, z: 1 }, defaultColor: '#9ca3af' },
// Угловой клин — клин со скосом по двум осям (внутренний угол крыши).
{ id: 'cornerwedge', name: 'Угловой клин', icon: 'prim-cornerwedge', kind: 'geometry',
defaultScale: { x: 1, y: 1, z: 1 }, defaultColor: '#9ca3af' },
// === Триггер — невидимая зона ===
{ id: 'trigger', name: 'Триггер', icon: 'prim-trigger', kind: 'trigger',
defaultScale: { x: 2, y: 2, z: 2 }, defaultColor: '#ffeb3b' },
// === Чекпоинт — точка респавна ===
{ id: 'checkpoint', name: 'Чек-поинт', icon: 'prim-checkpoint', kind: 'checkpoint',
defaultScale: { x: 1, y: 1, z: 1 }, defaultColor: '#10b981' },
// === Лампа — источник света (PointLight) ===
// Маленькая светящаяся сфера-маркер + привязанный точечный свет.
// Свет настраивается в инспекторе: цвет, яркость, радиус.
{ id: 'light', name: 'Лампа', icon: 'prim-light', kind: 'light',
defaultScale: { x: 0.4, y: 0.4, z: 0.4 }, defaultColor: '#ffe9a0' },
// === Эмиттер — постоянный источник частиц (костёр/дым/искры/магия) ===
// Маркер-сфера + ParticleSystem. Эффект выбирается в инспекторе.
{ id: 'emitter', name: 'Эмиттер частиц', icon: 'prim-emitter', kind: 'emitter',
defaultScale: { x: 0.4, y: 0.4, z: 0.4 }, defaultColor: '#ff8833' },
// === Табличка — 3D-карточка с GUI (как BillboardGui в Roblox) ===
// Плоскость с натянутой DynamicTexture, на которой рендерится контент
// (заголовок, иконка, кнопка). Поддерживает 4 пресета (см. BillboardUiManager):
// shop-item, shop-purchase, banner, sign. Может смотреть на камеру
// (face=camera) или быть фиксированной (face=fixed). Клик по кнопке
// эмитит событие через game.billboard.onClick.
{ id: 'billboard', name: '3D-табличка', icon: 'prim-billboard', kind: 'billboard',
defaultScale: { x: 2, y: 1.2, z: 0.05 }, defaultColor: '#1a1a2e' },
// === GD-порталы (Geometry Dash 2.0) — переключают гейммод игрока ===
// Все цилиндры-«столбы» с neon-материалом. Цвета и gdMode задают режим.
{ id: 'gd_cube', name: 'Портал: Куб', icon: 'prim-portal', kind: 'gd_portal', gdMode: 'cube',
defaultScale: { x: 0.5, y: 7, z: 0.5 }, defaultColor: '#3366ff' },
{ id: 'gd_ship', name: 'Портал: Корабль', icon: 'prim-portal', kind: 'gd_portal', gdMode: 'ship',
defaultScale: { x: 0.5, y: 7, z: 0.5 }, defaultColor: '#ff8833' },
{ id: 'gd_ball', name: 'Портал: Шар', icon: 'prim-portal', kind: 'gd_portal', gdMode: 'ball',
defaultScale: { x: 0.5, y: 7, z: 0.5 }, defaultColor: '#22ff66' },
{ id: 'gd_ufo', name: 'Портал: НЛО', icon: 'prim-portal', kind: 'gd_portal', gdMode: 'ufo',
defaultScale: { x: 0.5, y: 7, z: 0.5 }, defaultColor: '#44ccff' },
{ id: 'gd_wave', name: 'Портал: Волна', icon: 'prim-portal', kind: 'gd_portal', gdMode: 'wave',
defaultScale: { x: 0.5, y: 7, z: 0.5 }, defaultColor: '#bb44ff' },
{ id: 'gd_robot', name: 'Портал: Робот', icon: 'prim-portal', kind: 'gd_portal', gdMode: 'robot',
defaultScale: { x: 0.5, y: 7, z: 0.5 }, defaultColor: '#22ccaa' },
// === GD-объекты уровня ===
// Шип (cone) — касание = смерть. Можно ставить на полу (остриём вверх) или вращать на потолок.
{ id: 'gd_spike', name: 'GD: Шип', icon: 'prim-spike', kind: 'gd_spike',
defaultScale: { x: 1.3, y: 1.6, z: 1.3 }, defaultColor: '#ff3344' },
// Финиш (cylinder neon) — касание = победа (триггерит showWinScreen в скрипте через событие).
{ id: 'gd_finish', name: 'GD: Финиш', icon: 'prim-finish', kind: 'gd_finish',
defaultScale: { x: 1.2, y: 8, z: 1.2 }, defaultColor: '#ffe44a' },
// Монета (sphere) — касание = +1 монета.
{ id: 'gd_coin', name: 'GD: Монета', icon: 'prim-coin', kind: 'gd_coin',
defaultScale: { x: 0.6, y: 0.6, z: 0.6 }, defaultColor: '#ffd700' },
];
/** Категории для группировки в палитре. */
export const PRIMITIVE_CATEGORIES = [
{ id: 'geometry', name: 'Фигуры', ids: ['cube','sphere','cylinder','cone','plane','torus','wedge','cornerwedge'] },
{ id: 'gameplay', name: 'Геймплей', ids: ['trigger', 'checkpoint', 'light', 'emitter', 'billboard'] },
{ id: 'gd-portals', name: 'GD-порталы', ids: ['gd_cube','gd_ship','gd_ball','gd_ufo','gd_wave','gd_robot'] },
{ id: 'gd-objects', name: 'GD-объекты', ids: ['gd_spike','gd_finish','gd_coin'] },
];
export function getPrimitiveType(id) {
return PRIMITIVE_TYPES.find(t => t.id === id) || PRIMITIVE_TYPES[0];
}
// kind-ы примитивов Geometry Dash. Эти типы остаются в PRIMITIVE_TYPES
// (нужны движку для загрузки старых GD-проектов и getPrimitiveType),
// но НЕ показываются в палитре инструментов.
const GD_KINDS = new Set(['gd_portal', 'gd_spike', 'gd_finish', 'gd_coin']);
/**
* Список примитивов для ПАЛИТРЫ редактора — без GD-инструментов.
* Палитра должна рендерить именно его, а не полный PRIMITIVE_TYPES.
*/
export const PALETTE_PRIMITIVE_TYPES = PRIMITIVE_TYPES.filter(
t => !GD_KINDS.has(t.kind)
);