From c9acb4fb3bab5670d1a5da003ffd701da259a850 Mon Sep 17 00:00:00 2001 From: min Date: Tue, 9 Jun 2026 17:38:16 +0300 Subject: [PATCH] =?UTF-8?q?fix(g7):=20=D1=81=D0=BF=D0=B0=D0=B2=D0=BD=20?= =?UTF-8?q?=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20=5F=5Frbxl=5Fspawn=5Fpart=20+?= =?UTF-8?q?=20Heartbeat=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20task.spaw?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Корни: 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 СРАЗУ — куб создаётся динамическим и падает. --- src/community/docsGamesBuildersLua.js | 78 +++++++++++++++------------ src/editor/engine/lua/RobloxShim.js | 35 ++++++++++++ 2 files changed, 79 insertions(+), 34 deletions(-) diff --git a/src/community/docsGamesBuildersLua.js b/src/community/docsGamesBuildersLua.js index a4d3662..2166f9f 100644 --- a/src/community/docsGamesBuildersLua.js +++ b/src/community/docsGamesBuildersLua.js @@ -510,42 +510,52 @@ coinSound.SoundId = "coin"; coinSound.Volume = 1 local winSound = Instance.new("Sound", workspace) winSound.SoundId = "win"; winSound.Volume = 1 --- Каждые 1.5 сек роняем куб -task.spawn(function() - while not won do - task.wait(1.5) - if won then break end - local cube = Instance.new("Part", workspace) - cube.Size = Vector3.new(0.8, 0.8, 0.8) - cube.Position = Vector3.new(math.random(-6, 6), 14, math.random(-6, 6)) - cube.Color = Color3.fromRGB(255, 204, 51) - cube.Material = Enum.Material.Neon - cube.Anchored = false -- падает под действием гравитации +-- Каждые 1.5 сек роняем куб (через Heartbeat — task.spawn не умеет yield) +local RunService = game:GetService("RunService") +local _spawnTimer = 0 - -- Куб исчезает через 6с если не поймали - Debris:AddItem(cube, 6) +local function spawnCube() + -- Используем хелпер __rbxl_spawn_part — он сразу создаёт примитив + -- с правильными свойствами (включая anchored=false → реальная гравитация). + local cube = __rbxl_spawn_part({ + type = "cube", + x = math.random(-6, 6), y = 14, z = math.random(-6, 6), + sx = 0.8, sy = 0.8, sz = 0.8, + color = "#ffcc33", + anchored = false, -- падает + canCollide = true, + }) + if not cube then return end + Debris:AddItem(cube, 6) - -- Ловля: при касании игроком +1 очко - local caught = false - cube.Touched:Connect(function(hit) - if caught or won then return end - local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid") - if not h then return end - caught = true - score = score + 1 - label.Text = "Поймано: " .. score .. " / " .. GOAL - coinSound:Play() - cube:Destroy() - if score >= GOAL then - won = true - winSound:Play() - __rbxl_show_text("Победа! Ты поймал 15 кубов!", 5) - local px = __rbxl_player_x() - local py = __rbxl_player_y() - local pz = __rbxl_player_z() - __rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3) - end - end) + local caught = false + cube.Touched:Connect(function(hit) + if caught or won then return end + local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid") + if not h then return end + caught = true + score = score + 1 + label.Text = "Поймано: " .. score .. " / " .. GOAL + coinSound:Play() + cube:Destroy() + if score >= GOAL then + won = true + winSound:Play() + __rbxl_show_text("Победа! Ты поймал 15 кубов!", 5) + local px = __rbxl_player_x() + local py = __rbxl_player_y() + local pz = __rbxl_player_z() + __rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3) + end + end) +end + +RunService.Heartbeat:Connect(function(dt) + if won then return end + _spawnTimer = _spawnTimer + (dt or 0.016) + if _spawnTimer >= 1.5 then + _spawnTimer = 0 + spawnCube() end end)`, }, diff --git a/src/editor/engine/lua/RobloxShim.js b/src/editor/engine/lua/RobloxShim.js index a431ac5..122086d 100644 --- a/src/editor/engine/lua/RobloxShim.js +++ b/src/editor/engine/lua/RobloxShim.js @@ -1826,6 +1826,41 @@ export function registerRobloxShim(lua, opts) { count: Number(count) || 1, }); }); + // Спавн примитива (паритет с JS game.scene.spawn) — кладёт в сцену + // примитив с указанным состоянием (включая anchored/canCollide). Возвращает + // id примитива (число) для дальнейших операций. + let _nextSpawnedId = 800000 + Math.floor(Math.random() * 10000); + global.set('__rbxl_spawn_part', (opts) => { + try { + const id = _nextSpawnedId++; + const o = opts || {}; + send('sceneCreate', { + primId: id, + type: String(o.type || 'cube'), + x: +o.x || 0, y: +o.y || 0, z: +o.z || 0, + sx: +o.sx || 1, sy: +o.sy || 1, sz: +o.sz || 1, + color: o.color || '#A0A0A0', + anchored: o.anchored !== false, + canCollide: o.canCollide !== false, + }); + // Создаём Lua-side представление для скриптов + const fakePrim = { + id, name: o.name || `Spawned_${id}`, + x: +o.x || 0, y: +o.y || 0, z: +o.z || 0, + sx: +o.sx || 1, sy: +o.sy || 1, sz: +o.sz || 1, + color: o.color || '#A0A0A0', + anchored: o.anchored !== false, + canCollide: o.canCollide !== false, + }; + const part = newPart(fakePrim, send); + partById.set(id, part); + return part; + } catch (e) { + // eslint-disable-next-line no-console + console.warn('[__rbxl_spawn_part]', e?.message || e); + return null; + } + }); // Позиция игрока для удобства — отдельные функции для x/y/z, чтобы // wasmoon не оборачивал результат в userdata-proxy. global.set('__rbxl_player_x', () => {