372 Commits

Author SHA1 Message Date
min
1be06343ec fix(g20): отложенный setLabel для NPC до npcSpawned-резолва
setLabel сразу после spawnNpc возвращал null от _resolveTweenTarget
(маппинг localRef→realId ещё не записан). Метки молча терялись.

Фикс: если ref начинается с npc_lua_ — откладываем через _npcCmd
(re-вызов после npcSpawned). Иначе retry через 0.3с.
2026-06-09 20:41:09 +03:00
min
b83c9bb75c fix(g20): использовать api.setNpcLocalRef вместо прямого access
Lua-runtime FATAL: 'Cannot access api before initialization' — я
обращался к api._localToRealNpc на 1852 до const api = на 2027.

Фикс:
- _localToRealNpc объявил как const до api (доступен в closures)
- api.setNpcLocalRef(localRef, realRef) — публичный метод
- GameRuntime: sb.api.setNpcLocalRef?.(ref, 'npc:'+npcId)
- В fireGlobalEvent npcDeath используем _localToRealNpc напрямую
2026-06-09 20:38:49 +03:00
min
8a3405e34a feat(g20): полный паритет «Имена над врагами» + shim NPC API
JS:
- 3 NPC (Гоблин, Скелет, Орк) через spawnNpc('character-b')
- setLabel над каждым с HP, обновляется при уроне
- ЛКМ → бьём ближайшего врага в радиусе 4 (damage 30)
- onDeath → clearLabel + hit sound + при 0 врагов — победа+confetti

Расширения shim/runtime:
- __rbxl_spawn_npc уже было, добавил api._localToRealNpc Map
- __rbxl_npc_damage(ref, amount) → cmd 'npc.damage'
- __rbxl_set_label(ref, text, color, height) → cmd 'scene.setLabel'
- __rbxl_clear_label(ref) → cmd 'scene.clearLabel'
- __rbxl_npc_on_death(ref, fn) — регистрирует cb. shim слушает global
  event 'npcDeath' (resolveTweenTarget теперь поддерживает kind='npc')
  и зовёт зарегистрированные cb с подходящим ref (local или real).
- GameRuntime.npc.spawn.then синхронизирует _localToRealNpc в Lua-sb.

Lua-скрипт игры 20 (паритет):
- showText 'Победи всех врагов! Кликай по ним'
- 3 спавна с метками HP над головой
- UserInputService.InputBegan MouseButton1 → ближайший враг в r=4 → -30hp
- На смерть: clearLabel + при 0 — Победа + win Sound + confetti
2026-06-09 20:34:20 +03:00
min
3cdbbc5049 docs: CodeBoth для урока 19 «Лифт» (main+finish) 2026-06-09 20:28:37 +03:00
min
c489a31854 feat(g19): полный паритет «Лифт» — Heartbeat yo-yo
Игра 19 падала на WaitForChild + Vector3 + (оператор не поддержан).

Lua паритет с JS:
- showText 'Встань на синий лифт — он повезёт наверх'
- task.delay 0.2c для FindFirstChild('Лифт') (WaitForChild может зависать)
- Heartbeat yo-yo по Y: startY (1) ↔ TOP_Y (12.3) с периодом 7с
  (3.5с вверх + 3.5с вниз через треугольную функцию)
- Vector3.new напрямую (без +)
- Респаун при y<-3
- BindableEvent WinReached + g19_finish.Touched → ev:Fire
- При победе: showText 'Победа!' + win Sound + confetti
2026-06-09 20:26:19 +03:00
min
98e92b23a7 docs: CodeBoth для урока 18 «Качели» (main+finish) 2026-06-09 20:24:48 +03:00
min
430b9eddcd feat: игра 18 «Качели» Lua + кастомная модалка выхода
Игра 18:
- Падало на WaitForChild + task.spawn + Completed:Wait (yield-across-C).
- Полный переписан: Heartbeat-таймер раскачивает swing по синусу
  с амплитудой 4 и периодом 2.8с (вместо TweenService).
- task.delay 0.2с чтобы дождаться появления свинга в scene.
- Vector3.new напрямую (без оператора + который не работает).
- BindableEvent WinReached + g18_finish.Touched → ev:Fire.
- Полный паритет: showText, win Sound, confetti, respawn при y<-3.

Модалка выхода:
- Заменил window.confirm в KubikonEditor.handleBack на ConfirmModal.
- 3 варианта: Сохранить и выйти / Выйти без сохранения / Отмена.
- ConfirmModal расширен onCancel prop (отделяет 'cancel-кнопка'
  от 'клик мимо/Escape').
2026-06-09 20:22:16 +03:00
min
b5ba62cca8 docs: CodeBoth для урока 17 «Ключ и сундук» (main+key+chest) 2026-06-09 20:15:54 +03:00
min
1345f51436 feat(g17): полный паритет с JS «Ключ и сундук»
JS:
- showText 'Найди ключ и открой сундук!'
- onMessage 'takeKey' → inventory.add('Ключ') + 'Ты нашёл Ключ!' + pickup
- onMessage 'openChest' → если has('Ключ'): 'Победа!' + win + confetti
                         иначе: 'Сундук заперт. Сначала найди ключ.'
- key: onTouch → broadcast 'takeKey' + delete
- chest: onInteract E (distance=4) → broadcast 'openChest'

Lua (паритет, юзер указал на отсутствие надписей/инвентаря/звуков):
- __rbxl_show_text для всех подсказок (вместо print)
- __rbxl_inventory_define('key','Ключ') → итем в hotbar инвентаря
- __rbxl_inventory_add('key',1) при подборе (вместо leaderstats BoolValue)
- __rbxl_inventory_has('key') проверка ключа в сундуке
- Sounds 'pickup'/'win'/'lose' (раньше только print)
- BindableEvents TakeKey + OpenChest
- g17_key: Touched → ev:Fire + Destroy (с taken-флагом)
- g17_chest: убран ошибочный Touched-handler.
  Heartbeat distance-check как в Торговце:
  при near=true → __rbxl_hud_set '[E] Открыть сундук'
  UserInputService E → OpenChest:Fire
- При победе: confetti над игроком + win Sound
2026-06-09 20:13:52 +03:00
min
1a6a92b431 docs: CodeBoth для урока 16 «Лава-пол» (main+lava+finish) 2026-06-09 20:11:16 +03:00
min
2979104931 fix(g16): урон только когда игрок РЕАЛЬНО в лаве (не над островком)
Раньше: фильтр по Y-капсулы не работал — игрок стоит на островке на
realPos.y=1.54 > порога 1.35, фильтр пропускал.

Стало: проверяем где игрок по X/Z. Если над островком (любой из 6) или
над финишной площадкой — пропускаем урон. Иначе — урон каждый кадр пока
Touched активно (RunService.Heartbeat). У damage есть i-frames ~0.5с
так что урон ~2/сек.

Также: переход с Touched-разово на Heartbeat-постоянно. Раньше Touched
срабатывал только при ВХОДЕ в лаву — если игрок стоит в лаве долго,
TouchEnded не вызывался, и урон шёл только раз. Теперь Touched/TouchEnded
выставляют inLava-флаг, Heartbeat считает урон каждый кадр.
2026-06-09 20:09:07 +03:00
min
f0f739071a feat(g16): полный паритет «Лава-пол» + защита от ложного хитбокса
JS:
- showText 'Прыгай по островкам! Лава жжёт!'
- onTick: y<-2 → respawn
- onMessage 'win' → showText + win + confetti
- g16_lava: onTouch → damage(20) + hit sound
- g16_finish: onTouch → broadcast 'win'

Lua (паритет):
- __rbxl_show_text + win Sound + confetti
- Heartbeat: __rbxl_player_y() < -2 → LoadCharacter
- BindableEvent WinReached + g16_finish.Touched → ev:Fire
- g16_lava: __rbxl_damage_player(20) + hit Sound
  ВАЖНО: лава-зона на y=1±0.3 (верх 1.3), островки на y=1.2±0.3 (верх 1.5).
  AABB-зоны пересекаются → BabylonScene touch-detector с EPS=0.25
  активировал лаву даже когда игрок стоит на островке.
  Защита: если игрок выше Y=1.35 (стоит на островке/финише) — пропускаем
  урон. Урон срабатывает только когда игрок реально в лаве.

Shim добавил:
- __rbxl_damage_player(amount) → cmd player.damage (с i-frames)
2026-06-09 20:03:50 +03:00
min
662d0d06e4 docs: CodeBoth для урока 15 «Тир» (main+target) 2026-06-09 20:01:00 +03:00
min
d6a874c8a0 fix(g15): клик в 3-м лице по координатам курсора, не центру
В 3-м лице курсор свободный. _handlePlayClick ВСЕГДА пикал центром
экрана через _pickFromCenter — независимо от того где находится курсор.
Поэтому клик мышкой по мишени не срабатывал — пик шёл из центра.

Фикс: проверяем document.pointerLockElement:
- locked (1-е лицо) → _pickFromCenter (прицел всегда в центре)
- !locked (3-е лицо) → scene.pick(clickX, clickY) по реальной позиции
  курсора при клике.

Убрал debug-логи.
2026-06-09 19:59:38 +03:00
min
12efef7ff5 debug(g15): логи в shim fireTargetEvent + click — найти где обрывается 2026-06-09 19:56:06 +03:00
min
8abbde9d67 feat(g15): полный паритет «Тир» + ClickDetector в shim
JS:
- 8 мишеней-сфер на постаментах
- ui.score, showText 'Кликай по красным мишеням!'
- target: onClick → explosion particles + delete + broadcast 'hit'
- main: onMessage 'hit' → score++ + hit sound + при 8 победа+confetti

Lua-shim расширение:
- Instance.new('ClickDetector') создаёт инстанс с MouseClick signal
- Когда clickDet.Parent = part → Proxy.set регистрирует
  part._clickDetector = clickDet
- fireTargetEvent при kind='click' фейерит part._clickDetector.MouseClick.Fire

Lua-скрипт игры 15:
- ScreenGui 'Мишени: N / 8'
- BindableEvent TargetHit
- 8 g15_target_N (ids 2,4,6,8,10,12,14,16): ClickDetector с
  MaxActivationDistance=50 → MouseClick → spawn explosion + Destroy + Fire
- main: hit Sound, при 8 — win Sound + showText + confetti
2026-06-09 19:52:16 +03:00
min
2e1ee87ed6 docs: CodeBoth для урока 14 «Собери по тегам» (main+star) 2026-06-09 19:47:55 +03:00
min
7f3b81a531 feat: умный авто-fallback Lua для всех игр без явной реализации
Раньше для игр 15-50 при открытии 'Открыть мою копию на Lua' юзер
получал TODO-заглушки которые ничего не делали (или simpleMain
который только print). Каждая новая игра без явного override
была полностью неиграбельной.

Новый generateFallbackLua(s, gameTitle) в buildGameProject:

Главный скрипт (target=null):
  - __rbxl_show_text(gameTitle) подсказка
  - Слушает BindableEvent FinishReached → win Sound + Победа! + confetti

Скрипт-финиш (target=primitive с именем 'Финиш'/'ФинишЗона'/'Final'):
  - Touched → создаёт/находит BindableEvent FinishReached → Fire
  - fired-флаг чтобы 1 раз

Прочие target-скрипты:
  - Touched → красит примитив зелёным (визуальный feedback)
  - touched-флаг

Удалил статичные simpleMain stub-ы для игр 31-50 — теперь они
используют умный fallback. Когда дописываем полную Lua-версию
игры — добавляем явный override в LUA_OVERRIDES, fallback
автоматически перестаёт использоваться.

Это даёт минимум: победа на финише + цвет на касании во всех
35 не-готовых играх (15-50).
2026-06-09 19:43:20 +03:00
min
cc5717f5a3 feat(lua-games): полный паритет для игры 14 «Собери по тегам»
JS:
- 7 жёлтых звёзд-конусов + 5 синих кубов-обманок
- showText 'Собери все ЖЁЛТЫЕ звёзды!'
- main помечает звёзды тегом 'звезда' с задержкой 0.2с
- onMessage 'collected' → score++ + при 0 left — победа+confetti
- star: onTouch → untag + delete + broadcast 'collected'

Lua (паритет):
- 7 g14_star_N через генератор (раньше был один g14_star)
- ScreenGui 'Звёзды: N / 7' счётчик
- BindableEvent StarCollected
- main: task.delay(0.2) → AddTag всем 7 звёздам через workspace:FindFirstChild
- При collect → coin Sound + GetTagged-проверка left==0 → win+confetti
- g14_star_N: RemoveTag + Destroy + ev:Fire (с picked-флагом)
2026-06-09 19:38:55 +03:00
min
1a3c8e66e6 docs: CodeBoth для урока 13 «Торговец» (main+counter+door+finish) 2026-06-09 19:37:05 +03:00
min
b7b3c1eb81 fix(g13): подсказки [E] через HUD ui.set — паритет с JS
Юзер: подсказка в Lua была слева от центра, белая. В JS — точно по
центру внизу, жёлтая.

Корень: я использовал BillboardGui+TextLabel с явной Position, но
GUI-shim позиционирует label некорректно (UDim2 offset плохо
интерпретируется → плашка плыла).

Фикс: используем тот же механизм что JS — game.ui.set (HUD через
React). Добавил хелпер __rbxl_hud_set(id, text, x, y, color, size)
шлющий 'ui.set' cmd, GameRuntime пробрасывает в _onHud → GameHud.jsx
рендерит точно как для JS-скриптов.

В g13_counter/g13_door: при near=true → hud_set с (50, 75, #ffe44a, 20)
(центр по X, ниже центра по Y, жёлтый — точно как JS interact hint).
При выходе из зоны → hud_set(id, nil) убирает.
2026-06-09 19:34:32 +03:00
min
e8bfdda380 fix(g13): подсказки выше хотбара (0.6 центра вместо низа)
Прошлая позиция (1, -120) перекрывала хотбар инвентаря.
Новая (0.5, -160; 0.6, 0) — выше середины экрана, не мешает.
2026-06-09 19:09:34 +03:00
min
47ad608182 feat(g13): NPC-торговец + инвентарь как в JS
Юзер указал что в Lua-версии было отступление от JS:
- Торговец нарисован примитивами вместо character-a скина
- Ключ показан надписью в HUD вместо инвентаря-hotbar

Добавил в shim хелперы паритета:
- __rbxl_spawn_npc(modelType, x,y,z, name?, hp?, speed?) → cmd npc.spawn
  Возвращает локальный ref для дальнейших команд.
- __rbxl_npc_say(ref, text, duration) → cmd npc.say
- __rbxl_inventory_define(itemId, name, color) → cmd items.define
- __rbxl_inventory_add(itemId, count) → cmd inv2.add (показывает в hotbar)
- __rbxl_inventory_has(itemId) → проверка локального кеша
- __rbxl_inventory_remove(itemId, count) → cmd inv2.remove

Lua-скрипт игры 13:
- spawnNpc 'character-a' за прилавком как в JS
- inventory_define('key', 'Ключ') → hotbar
- При разговоре: npc_say + inventory_add('key', 1)
- При двери: проверяем inventory_has('key')
2026-06-09 19:05:55 +03:00
min
fb390f402c fix(g13): торговец-фигурка + подсказки внизу экрана
1) Торговец-NPC отсутствовал. Спавним фигурку из 3 частей:
   - Тело (синий куб) на (0, 2.0, 5) — за прилавком
   - Голова (бежевая сфера) на (0, 3.2, 5)
   - Шляпа (коричневый цилиндр) на (0, 3.8, 5)

2) Подсказки [E] плыли в центр экрана. Задал явную позицию:
   нижняя часть, по центру, с тёмной плашкой и тенью.
   Применил к g13_counter и g13_door.
2026-06-09 18:59:54 +03:00
min
e163fe9770 feat(lua-games): полный паритет для игры 13 «Торговец»
JS:
- spawnNpc торговец, prompts E:
  Прилавок onInteract → broadcast 'talk' → выдать ключ через inventory
  Дверь onInteract → broadcast 'openDoor' → проверка inventory.has
  → tween двери (y:9)
- Финиш onTouch → broadcast 'win' → confetti

Lua (паритет, NPC через статичный прилавок):
- ScreenGui 'Ключа нет' / 'У тебя есть Ключ' (вместо inventory)
- BindableEvents TalkTrader / OpenDoor / WinReached
- g13_counter: BillboardGui '[E] Поговорить с торговцем' в радиусе 4
  + UserInputService E → TalkTrader:Fire
- g13_door: BillboardGui '[E] Открыть дверь' в радиусе 4
  + E → OpenDoor:Fire (или 'Дверь заперта' если ключа нет)
- g13_main:
  TalkTrader → если ключа нет: hasKey=true + 'Привет!' + pickup Sound
  OpenDoor → если hasKey: tween двери +6 по Y + win Sound
  WinReached → 'Победа!' + confetti
- g13_finish: Touched → WinReached:Fire (fired-флаг)
2026-06-09 18:56:28 +03:00
min
e0a457bd7a docs: CodeBoth для урока 12 «Дверь по коду» (main+btn+finish) 2026-06-09 18:55:09 +03:00
min
89baf23877 feat(lua-games): полный паритет для игры 12 «Дверь по коду»
JS:
- CODE=[3,1,4,2], showText 'Нажми кнопки в правильном порядке (E)'
- onMessage 'press' с {num} → click sound, push в entered, проверка
  совпадения с CODE, ошибка → сброс + 'Неверно!' + lose sound
  весь код → 'Код верный! Дверь открывается' + win sound + tween двери
- onMessage 'win' → 'Победа!' + win + confetti
- кнопка: onInteract (E, distance=3) → broadcast 'press' {num}
- финиш: onTouch → broadcast 'win'

Lua (паритет):
- __rbxl_show_text всех подсказок + Sound 'click'/'lose'/'win'
- BindableEvent ButtonPress (с num аргументом) + WinReached
- g12_main: tween двери (Position.Y+=6) + CanCollide=false
- 4 g12_btn_N: BillboardGui '[E] Нажать N' видим в радиусе 3
  UserInputService.InputBegan E → ev:Fire(num)
  Hint видимость через Heartbeat + __rbxl_player_x/z
- g12_finish: Touched → ev:Fire WinReached
- При win — confetti
2026-06-09 18:53:22 +03:00
min
b2f6b084df docs: CodeBoth для урока 11 «Эхо-комната» (main+tile+finish) 2026-06-09 18:51:40 +03:00
min
eacc3f990b feat(lua-games): полный паритет для игры 11 «Эхо-комната»
JS:
- 6 цветных плиток-цилиндров со своими звуками
- ui.score, ui.showText 'Наступи на все цветные плитки!'
- onMessage 'step' → score++ + при 6 'Иди на финиш'
- onMessage 'finish' → если < TOTAL то 'Сначала пройди все плитки'
  иначе showText + win + confetti
- g11_tile_N: onTouch → sound + sparks particles, при первом — broadcast
- g11_finish: onTouch → broadcast 'finish'

Lua (паритет):
- ScreenGui 'Плитки: N / 6'
- BindableEvent EchoStep (плитка) + EchoFinish (зона)
- 6 g11_tile_N: каждая со своим Sound (coin/jump/pickup/click/hit/coin)
  + __rbxl_spawn_particles('sparks', x, y+1, z) при касании
  + Throttle 0.4с между звуками + used-флаг
- g11_main: 'Все плитки звучали! Иди на финиш' при 6
  'Сначала пройди все 6 плиток!' если рано пришёл на финиш
  При win — Sound 'win' + confetti
2026-06-09 18:47:57 +03:00
min
3be10c3cf7 docs: CodeBoth для урока 10 «Прыжок-пружина» (main+tramp+finish) 2026-06-09 18:46:08 +03:00
min
50b08b81bc feat(lua-games): полный паритет для игры 10 «Прыжок-пружина»
JS:
- showText 'Прыгай по батутам всё выше!'
- onTick: y<-3 → respawn + lose sound
- onMessage 'win' → showText + win + confetti
- g10_tramp_N: onTouch → player.boostJump(3.2) + jump sound
- g10_finish: onTouch → broadcast 'win'

Lua (паритет):
- __rbxl_show_text подсказка + 'Победа!'
- Heartbeat: __rbxl_player_y() < -3 → LoadCharacter + lose Sound
- BindableEvent WinReached + g10_finish.Touched → ev:Fire
- При win — confetti

Добавил хелпер в shim:
- __rbxl_boost_jump(strength) → send 'player.boostJump'
  3.2 = втрое выше обычного прыжка

g10_tramp_4/5/6: Touched → __rbxl_boost_jump(3.2) + jump Sound
с защитой от зацикливания (минимум 0.5с между активациями).
2026-06-09 18:44:34 +03:00
min
4186b49be4 docs: CodeBoth для урока 9 «Светофор» (g9_main + g9_finish) 2026-06-09 18:42:14 +03:00
min
f18835d5e9 fix(lua): player:LoadCharacter() / hrp.Position телепортируют через player._pos
GameRuntime обрабатывал prop:'position' и prop:'respawn' через
player.body.position.set() — но PlayerController хранит позицию в
player._pos (не body). Поэтому LoadCharacter молча ничего не делал.

Фикс: ставим player._pos.set(x, y+halfH, z) + сброс _vy.
Fallback на body если _pos нет.
2026-06-09 18:40:20 +03:00
min
bec3c478e7 feat(lua-games): полный паритет для игры 9 «Светофор»
JS:
- showText 'Зелёный — беги! Красный — замри!'
- light=findOne('Светофор'), green/red/green циклически (3с/2.5с)
- setColor light на красный/зелёный + showText
- onTick: если красный и moved/dt>0.8 — respawn + lose sound
- onMessage 'win' → showText + win + confetti
- g9_finish: onTouch → broadcast 'win'

Lua (паритет):
- __rbxl_show_text для всех подсказок
- Heartbeat-таймер фазы (task.spawn не умеет yield) — переключает
  phase 'green'/'red' каждые GREEN_TIME/RED_TIME
- light=workspace:FindFirstChild('Светофор'), .Color = Color3.fromRGB
- Heartbeat: prevX/prevZ, при phase=red и moved/dt>0.8 → LoadCharacter
  + lose Sound + 'Двинулся на красный!'
- BindableEvent WinReached
- g9_finish: Touched → ev:Fire с fired-флагом
- При победе: win Sound + confetti
2026-06-09 18:35:47 +03:00
min
41e0f7b6a4 feat(wiki): добавил CodeBoth с Lua-параллелью к скриптам игр 1-8
Создан хелпер CodeBoth в docsLessons.jsx: оборачивает <Code> в
<LangTabs js={JS-код} lua={Lua-код из LUA_OVERRIDES}>. Юзер
переключает JS↔Lua вверху урока — код в статье меняется тоже.

Заменены 17 блоков <Code> в уроках игр 1-8 на <CodeBoth>:
- collect-coins (g1_main, g1_coin_1)
- platform-jump (g2_main, g2_finish)
- dont-fall (g3_main, g3_tile_1)
- button-door (g4_main, g4_button, g4_finish)
- maze (g5_main, g5_finish)
- color-tiles (g6_main, g6_tile_1)
- catch-falling (g7_main)
- run-to-finish (g8_main, g8_finish)

Для остальных игр (9-50) остался JS-only Code — заменим
по мере прохождения.
2026-06-09 18:24:16 +03:00
min
73bf9f5c34 feat(lua-games): полный паритет для игры 8 «Беги к финишу»
JS:
- ui.timer + showText 'Беги к зелёному финишу — на время!'
- onTick: time += dt
- onMessage 'finish' → 'Финиш! Время: N сек' + win + confetti
- g8_finish: onTouch → broadcast 'finish'

Lua (паритет):
- ScreenGui+TextLabel секундомер вверху по центру '0.0 сек'
- __rbxl_show_text подсказка
- RunService.Heartbeat: time += dt → label.Text каждый кадр
- BindableEvent FinishReached
- g8_finish: Touched → ev:Fire с fired-флагом
- При финише: 'Финиш! Твоё время: X.X сек' + win Sound + confetti
2026-06-09 18:16:43 +03:00
min
1a174f2854 fix(g7): расширил радиус Touched на 1.2 — куб ловится при сближении
Куб с физикой отталкивается от игрока (DynamicsManager push) и успевает
отскочить до следующего кадра. Строгий AABB ловил только при защемлении
в углу. Расширение SLACK=1.2 единицы ловит 'почти-контакт' — куб
собирается при подходе на ~1 единицу.
2026-06-09 18:12:01 +03:00
min
8295d6f0fe fix(g7): синк позиций спавненных частей в shim для AABB-touched-check
DynamicsManager._applyToMesh обновляет pm.instances[id].x/y/z, но Lua-shim
кэширует Position в part._state.Position на момент создания. AABB-check
видел кубы навечно в небе → касание не ловилось.

Фикс: GameRuntime.tick собирает позиции всех спавненных динамических
примитивов и шлёт в shim через api.updateSpawnedPos(id, x, y, z).
Shim обновляет part._state.Position у соответствующего partById.
2026-06-09 18:09:45 +03:00
min
462ee62a9a fix(g7): Touched на спавненных частях через AABB-check в Heartbeat
BabylonScene._detectTouchEvents работает только для скриптов с явным
target. Спавненные runtime через __rbxl_spawn_part (падающие кубы)
не имеют target — Babylon их не проверяет, Touched молчит.

Решение: shim.fireHeartbeat теперь сам делает AABB игрок↔part для
всех part id >= 800000 (наш range спавненных). При пересечении
фейерит Touched.Fire(hrp); при выходе — TouchEnded.
2026-06-09 18:07:25 +03:00
min
fe2c1bb28b fix(g7): scene3d.dynamics (не dynamicsManager) — теперь регистрация работает 2026-06-09 18:04:14 +03:00
min
2c99a61bb0 debug(g7): лог про регистрацию unanchored part в физике 2026-06-09 18:02:47 +03:00
min
2af9b96088 fix(g7): спавненные unanchored примитивы регистрируются в физике
DynamicsManager.start() собирает unanchored объекты только при входе
в Play. Куб созданный из скрипта в runtime не попадал в bodies →
не падал, висел в воздухе.

Фикс: после pm.addInstance с anchored=false вызываем
dm.registerPrimitive(data) — кладёт тело в физический мир сразу
после спавна.
2026-06-09 17:41:20 +03:00
min
c9acb4fb3b fix(g7): спавн через __rbxl_spawn_part + Heartbeat вместо task.spawn
Корни:
1. task.spawn(function() task.wait() end) → 'attempt to yield across
   a C-call boundary' — task.spawn в shim синхронно зовёт fn из JS.
   Замена: накопление dt в RunService.Heartbeat → spawnCube() каждые 1.5с.

2. Instance.new('Part', workspace) с последующим .Anchored=false
   создавал anchored=true примитив + патч → primitiveManager не пересоздавал
   rigid body, куб не падал. Новый хелпер __rbxl_spawn_part(opts) шлёт
   sceneCreate с правильным anchored СРАЗУ — куб создаётся динамическим
   и падает.
2026-06-09 17:38:16 +03:00
min
8021ed6a20 feat(lua-games): полный паритет для игры 7 «Поймай падающее»
JS:
- ui.score, showText 'Лови падающие кубы! Нужно 15'
- every(1.5): random(x,z) → spawn cube y=14, anchored=false, deleteAfter 6с
- onPlayerTouch: caught[ref] флаг, +1 score, coin sound, при 15 — победа+confetti

Lua (паритет):
- ScreenGui+TextLabel 'Поймано: N / 15'
- task.spawn + task.wait(1.5) цикл спавна
- Instance.new('Part', workspace), Anchored=false (падение)
- Vector3.new для Position/Size
- Debris:AddItem(cube, 6) — авто-удаление
- cube.Touched: caught-флаг + score++ + coin Sound + Destroy
- При 15 — win Sound + showText + confetti
2026-06-09 17:34:16 +03:00
min
0603d922d4 fix(g6 builder): центрирую сетку 6×6 плиток на платформе
Было: x:-4+c*2 → плитки на x=[-4,-2,0,2,4,6], правые края до x=6.9.
Платформа grass [-6,5] (центры [-5.5, 5.5]). Плитка x=6 свешивалась.

Стало: x:-5+c*2 → плитки на x=[-5,-3,-1,1,3,5], края [-5.9, 5.9].
Чётко на платформе.

То же по Z.

Плюс лог 'ЯЗЫК СКРИПТОВ: LUA/JS' в GameRuntime — чтобы было видно
сразу что именно запущено.
2026-06-09 17:31:17 +03:00
min
8eec59af53 feat(lua-games): полный паритет для игры 6 «Цветные плитки»
JS-версия:
- 36 плиток 6×6, серые
- ui.score = painted, ui.showText
- onMessage 'paint' → score++ + pickup sound + при 36 победа+win+confetti
- tile: onTouch → setColor зелёный + broadcast 'paint'

Lua-версия:
- ScreenGui+TextLabel 'Плитки: N / 36' счётчик
- __rbxl_show_text подсказка + 'Победа!'
- BindableEvent TilePainted
- 36 g6_tile_N: Touched → part.Color=зелёный + ev:Fire (painted-флаг)
- g6_main: painted++/label.Text/pickup Sound; при 36 — win+confetti
2026-06-09 17:24:48 +03:00
min
f7074f5cd7 feat(lua-games): полный паритет для игры 5 «Лабиринт»
JS-версия:
- ui.showText('Найди выход из лабиринта!', 3)
- onMessage 'win' → showText + win sound + confetti
- g5_finish: onTouch → broadcast 'win'

Lua-версия:
- __rbxl_show_text подсказка + 'Победа!'
- BindableEvent WinReached
- g5_finish: Touched на финиш-зоне → ev:Fire (с fired-флагом)
- На победе: confetti над игроком
2026-06-09 17:21:56 +03:00
min
36321f0d17 fix(g4): label.Visible=false + Destroy при нажатии E
hintGui:Destroy() не убирает gui-overlay созданный TextLabel через
newGuiInstance. Делаем label.Visible=false (надёжный путь) + явный
label:Destroy().
2026-06-09 17:18:52 +03:00
min
c18dfc4d56 fix(g4): подсказка [E] видна только в радиусе 4 от кнопки
Heartbeat проверяет расстояние от игрока до кнопки. Управляем
видимостью через label.Visible (BillboardGui в shim не управляет
видимостью children, label.Visible работает напрямую через gui.update).
2026-06-09 17:17:03 +03:00
min
c006f58b70 debug(g4): print имена children workspace и состояние двери
Откатил метатаблицу Vector3 (она ломала TweenService instanceof RbxVector3).
2026-06-09 17:13:40 +03:00