diff --git a/src/community/docsGamesBuildersLua.js b/src/community/docsGamesBuildersLua.js index e54f241..9809525 100644 --- a/src/community/docsGamesBuildersLua.js +++ b/src/community/docsGamesBuildersLua.js @@ -1563,25 +1563,75 @@ end)`, // ИГРА 18 — «Качели» // ═══════════════════════════════════════════════════════════════ 'swing': { - g18_main: `-- === ИГРА «КАЧЕЛИ» (Lua) === -local TweenService = game:GetService("TweenService") -local swing = workspace:WaitForChild("Качели") -local startPos = swing.Position + g18_main: `-- === ИГРА «КАЧЕЛИ» — главный скрипт (Lua) === +${SNIPPET_BROADCAST} --- Качаем туда-сюда бесконечно -task.spawn(function() - while true do - local up = TweenService:Create(swing, - TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), - { Position = startPos + Vector3.new(0, 0, 5) }) - up:Play(); up.Completed:Wait() - local down = TweenService:Create(swing, - TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), - { Position = startPos + Vector3.new(0, 0, -5) }) - down:Play(); down.Completed:Wait() +local Players = game:GetService("Players") +local RunService = game:GetService("RunService") +local player = Players.LocalPlayer +local won = false + +__rbxl_show_text("Запрыгни на качели и прокатись!", 3) + +local winSound = Instance.new("Sound", workspace) +winSound.SoundId = "win"; winSound.Volume = 1 + +-- Раскачиваем качели туда-сюда через изменение Position.Z. +-- WaitForChild может зависнуть — берём напрямую с задержкой. +local swing = nil +local startZ = 0 + +task.delay(0.2, function() + swing = workspace:FindFirstChild("Качели") + if swing then + startZ = swing.Position.Z end end) -print("Запрыгни на качающуюся платформу!")`, + +local elapsed = 0 +RunService.Heartbeat:Connect(function(dt) + if won then return end + if not swing then return end + elapsed = elapsed + (dt or 0.016) + -- Синусоидальное качание с амплитудой 4 и периодом ~2.8 сек + local amp = 4 + local period = 2.8 + local offsetZ = amp * math.sin(elapsed * 2 * math.pi / period) + local pos = swing.Position + swing.Position = Vector3.new(pos.X, pos.Y, startZ + offsetZ) + + -- Если упал — респаун + local py = __rbxl_player_y() + if py < -3 then + player:LoadCharacter() + end +end) + +-- Финиш сообщает о победе +local winEvent = getEvent("WinReached") +winEvent.Event:Connect(function() + if won then return end + 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)`, + g18_finish: `-- === Скрипт финиша (Lua) === +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local part = script.Parent +local fired = false + +part.Touched:Connect(function(hit) + if fired then return end + local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid") + if not h then return end + fired = true + local ev = ReplicatedStorage:FindFirstChild("WinReached") + if ev then ev:Fire() end +end)`, }, // ═══════════════════════════════════════════════════════════════ diff --git a/src/editor/ConfirmModal.jsx b/src/editor/ConfirmModal.jsx index e1e12b3..2a4284c 100644 --- a/src/editor/ConfirmModal.jsx +++ b/src/editor/ConfirmModal.jsx @@ -25,8 +25,12 @@ export default function ConfirmModal({ cancelLabel = 'Отмена', confirmTone = 'primary', // 'primary' | 'danger' onConfirm, + onCancel, // если задан — вызывается при клике на «cancel» вместо тихого закрытия onClose, }) { + const handleCancel = () => { + try { onCancel?.(); } finally { onClose?.(); } + }; const confirmBtnRef = useRef(null); useEffect(() => { @@ -119,7 +123,7 @@ export default function ConfirmModal({ gap: 8, }}>