From 8abbde9d6764bd484234480f57ee1e83c3e4a596 Mon Sep 17 00:00:00 2001 From: min Date: Tue, 9 Jun 2026 19:52:16 +0300 Subject: [PATCH] =?UTF-8?q?feat(g15):=20=D0=BF=D0=BE=D0=BB=D0=BD=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=BF=D0=B0=D1=80=D0=B8=D1=82=D0=B5=D1=82=20=C2=AB?= =?UTF-8?q?=D0=A2=D0=B8=D1=80=C2=BB=20+=20ClickDetector=20=D0=B2=20shim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/community/docsGamesBuildersLua.js | 93 ++++++++++++++++++++------- src/editor/engine/lua/RobloxShim.js | 26 ++++++++ 2 files changed, 95 insertions(+), 24 deletions(-) diff --git a/src/community/docsGamesBuildersLua.js b/src/community/docsGamesBuildersLua.js index 2d56ae2..db17b2d 100644 --- a/src/community/docsGamesBuildersLua.js +++ b/src/community/docsGamesBuildersLua.js @@ -1277,38 +1277,83 @@ end)`; // ═══════════════════════════════════════════════════════════════ // ИГРА 15 — «Тир» // ═══════════════════════════════════════════════════════════════ - 'shooting-range': { - g15_main: `-- === ИГРА «ТИР» (Lua) === -local UserInputService = game:GetService("UserInputService") -local Players = game:GetService("Players") + 'shooting-range': (function() { + // Мишени имеют id 2, 4, 6, 8, 10, 12, 14, 16 (постамент → нечётный, мишень → чётный) + const TARGET_IDS = [2, 4, 6, 8, 10, 12, 14, 16]; + const TOTAL = TARGET_IDS.length; + const overrides = { + g15_main: `-- === ИГРА «ТИР» — главный скрипт (Lua) === ${SNIPPET_BROADCAST} +local Players = game:GetService("Players") +local player = Players.LocalPlayer local score = 0 -print("Стреляй ЛКМ по красным шарам!") +local TOTAL = ${TOTAL} +local won = false -local ev = getEvent("TargetHit") -ev.Event:Connect(function() +__rbxl_show_text("Кликай по красным мишеням!", 3) + +-- Счётчик в правом верхнем углу +local screenGui = Instance.new("ScreenGui", player.PlayerGui) +local label = Instance.new("TextLabel", screenGui) +label.Size = UDim2.new(0, 220, 0, 50) +label.Position = UDim2.new(1, -240, 0, 20) +label.BackgroundColor3 = Color3.fromRGB(0, 0, 0) +label.BackgroundTransparency = 0.4 +label.TextColor3 = Color3.fromRGB(255, 100, 100) +label.TextScaled = true +label.Font = Enum.Font.SourceSansBold +label.Text = "Мишени: 0 / " .. TOTAL + +local hitSound = Instance.new("Sound", workspace) +hitSound.SoundId = "hit"; hitSound.Volume = 0.7 +local winSound = Instance.new("Sound", workspace) +winSound.SoundId = "win"; winSound.Volume = 1 + +local hitEvent = getEvent("TargetHit") +hitEvent.Event:Connect(function() + if won then return end score = score + 1 - print("Попал! Очки: " .. score) -end) - --- ЛКМ — пускаем луч из камеры -UserInputService.InputBegan:Connect(function(input, gp) - if gp then return end - if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end - local player = Players.LocalPlayer - local mouse = player:GetMouse() - local target = mouse.Target - if target and target:GetAttribute("IsTarget") then - local hitEv = workspace:FindFirstChild("TargetHit") or ev - ev:Fire() - target:Destroy() + label.Text = "Мишени: " .. score .. " / " .. TOTAL + hitSound:Play() + if score >= TOTAL then + won = true + winSound:Play() + __rbxl_show_text("Победа! Все мишени выбиты!", 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)`, - g15_target: `-- === Скрипт мишени (Lua) === + }; + // Скрипт каждой мишени — ClickDetector + взрыв искр + сообщение + const targetScript = `-- === Скрипт мишени (Lua) === +-- Клик ЛКМ по мишени = выстрел. ClickDetector ловит клик в 3D. +local ReplicatedStorage = game:GetService("ReplicatedStorage") local part = script.Parent -part:SetAttribute("IsTarget", true)`, - }, +local hit = false + +local clickDet = Instance.new("ClickDetector", part) +clickDet.MaxActivationDistance = 50 + +clickDet.MouseClick:Connect(function() + if hit then return end + hit = true + -- Взрыв искр на месте мишени + local pos = part.Position + __rbxl_spawn_particles("explosion", pos.X, pos.Y, pos.Z, 0.5, 1) + -- Сообщаем главному скрипту + local ev = ReplicatedStorage:FindFirstChild("TargetHit") + if ev then ev:Fire() end + -- Мишень исчезает + part:Destroy() +end)`; + for (const tid of TARGET_IDS) { + overrides['g15_target_' + tid] = targetScript; + } + return overrides; + })(), // ═══════════════════════════════════════════════════════════════ // ИГРА 16 — «Лавовый пол» diff --git a/src/editor/engine/lua/RobloxShim.js b/src/editor/engine/lua/RobloxShim.js index 72d05a5..71d7f6a 100644 --- a/src/editor/engine/lua/RobloxShim.js +++ b/src/editor/engine/lua/RobloxShim.js @@ -436,6 +436,11 @@ function newInstance(className, name) { value.Children.push(proxyRef); try { value.ChildAdded && value.ChildAdded.Fire(proxyRef); } catch (_) {} } + // Спец-регистрация для ClickDetector — чтобы клик по Part + // мог сфейерить MouseClick через fireTargetEvent. + if (t.ClassName === 'ClickDetector' && value) { + try { value._clickDetector = proxyRef; } catch (_) {} + } try { t.AncestryChanged && t.AncestryChanged.Fire(proxyRef, value); } catch (_) {} return true; } @@ -1387,6 +1392,15 @@ export function registerRobloxShim(lua, opts) { inst.Scale = new RbxVector3(1, 1, 1); inst.Offset = new RbxVector3(0, 0, 0); inst.VertexColor = new RbxVector3(1, 1, 1); + } else if (className === 'ClickDetector') { + // ClickDetector — клик по 3D-объекту (нужен Тиру и т.п.). + // Регистрация в part._clickDetector происходит автоматически + // через Proxy.set когда юзер делает clickDet.Parent = part. + inst = newInstance('ClickDetector', 'ClickDetector'); + inst.MouseClick = makeSignal(); + inst.MouseHoverEnter = makeSignal(); + inst.MouseHoverLeave = makeSignal(); + inst.MaxActivationDistance = 32; } else if (className === 'BindableEvent') { inst = newInstance('BindableEvent', 'BindableEvent'); inst.Event = makeSignal(); @@ -2164,6 +2178,18 @@ export function registerRobloxShim(lua, opts) { part.Touched.Fire(hrp); } else if (p.kind === 'untouch' || p.kind === 'untouched') { part.TouchEnded.Fire(hrp); + } else if (p.kind === 'click') { + // ClickDetector создаётся лениво — стрельба по 3D-объектам. + // Юзер делает: part.ClickDetector = Instance.new('ClickDetector', part) + // + clickDet.MouseClick:Connect(fn). Здесь фейерим сигнал. + try { + const cd = part._clickDetector; + if (cd && cd.MouseClick) cd.MouseClick.Fire(localPlayer); + } catch (_) {} + // Также фейерим Part.Clicked если есть (наш расширенный API). + try { + if (part.Clicked) part.Clicked.Fire(); + } catch (_) {} } }, fireGlobalEvent(p) {