studio/src/community/docsGamesBuildersLua.js
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

1549 lines
68 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.

/**
* docsGamesBuildersLua.js — Lua-эквиваленты скриптов для уроков.
*
* Структура: LUA_OVERRIDES[gameId][scriptId] = 'lua-code'
* Может быть строкой или функцией (script) => 'lua-code' для случаев,
* когда код зависит от target/name (например, имя примитива).
*
* Когда юзер нажимает «Открыть копию → Lua» в LessonPage,
* buildGameProject(id, {lang:'lua'}) подменяет JS-скрипт на Lua-версию
* отсюда. Геометрия (примитивы, блоки) остаётся той же — отличается
* только язык скриптов.
*
* Lua-код пишется в стандартном Roblox-стиле:
* game:GetService("Players"), workspace, Instance.new, Vector3, CFrame,
* :Connect, RunService.Heartbeat, BindableEvent через ReplicatedStorage.
*
* Конвенции:
* - target=null (глобальный JS-скрипт) → в Lua это просто script в workspace,
* общение через ReplicatedStorage:BindableEvent.
* - target.kind='primitive' (на объекте) → script лежит ВНУТРИ части,
* обращение к ней через script.Parent. Имя части совпадает с тем что
* в JS-builder указано (Монетка_N, Платформа_N и т.д.).
*
* Помощники общего назначения:
* getPlayerFromHit — извлекает Player из hit события Touched.
* getOrCreateEvent — общая BindableEvent в ReplicatedStorage для broadcast.
*/
// ══════════════════════════════════════════════════════════════════
// Общие сниппеты — вставляются в начало многих скриптов.
// ══════════════════════════════════════════════════════════════════
const SNIPPET_BROADCAST = `local ReplicatedStorage = game:GetService("ReplicatedStorage")
local function getEvent(name)
local ev = ReplicatedStorage:FindFirstChild(name)
if not ev then
ev = Instance.new("BindableEvent")
ev.Name = name
ev.Parent = ReplicatedStorage
end
return ev
end`;
const SNIPPET_PLAYER_HIT = `local Players = game:GetService("Players")
local function getPlayerFromHit(hit)
if not hit or not hit.Parent then return nil end
return Players:GetPlayerFromCharacter(hit.Parent)
end`;
export const LUA_OVERRIDES = {
// ═══════════════════════════════════════════════════════════════
// ИГРА 1 — «Собери монетки»
// ═══════════════════════════════════════════════════════════════
'collect-coins': {
g1_main: `-- === ИГРА «СОБЕРИ МОНЕТКИ» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local Players = game:GetService("Players")
local score = 0
local TOTAL = 8
-- HUD: счётчик в правом верхнем углу
local player = Players.LocalPlayer
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
screenGui.Name = "CoinHUD"
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, 215, 0)
label.TextScaled = true
label.Font = Enum.Font.SourceSansBold
label.Text = "Монеты: 0 / " .. TOTAL
-- Подсказка по центру (на 2 секунды)
local hintGui = Instance.new("ScreenGui", player.PlayerGui)
local hint = Instance.new("TextLabel", hintGui)
hint.Size = UDim2.new(0, 400, 0, 60)
hint.Position = UDim2.new(0.5, -200, 0.3, 0)
hint.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
hint.BackgroundTransparency = 0.4
hint.TextColor3 = Color3.fromRGB(255, 255, 255)
hint.TextScaled = true
hint.Text = "Собери все монетки!"
task.delay(2, function() hintGui:Destroy() end)
-- Звуки
local coinSound = Instance.new("Sound", workspace)
coinSound.SoundId = "coin"
coinSound.Volume = 1
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"
winSound.Volume = 1
-- Подписка на сбор монетки
local coinEvent = getEvent("CoinCollected")
coinEvent.Event:Connect(function()
score = score + 1
label.Text = "Монеты: " .. score .. " / " .. TOTAL
coinSound:Play()
if score >= TOTAL then
-- Победный текст
local winGui = Instance.new("ScreenGui", player.PlayerGui)
local winLabel = Instance.new("TextLabel", winGui)
winLabel.Size = UDim2.new(0, 500, 0, 80)
winLabel.Position = UDim2.new(0.5, -250, 0.4, 0)
winLabel.BackgroundColor3 = Color3.fromRGB(0, 100, 0)
winLabel.BackgroundTransparency = 0.2
winLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
winLabel.TextScaled = true
winLabel.Font = Enum.Font.SourceSansBold
winLabel.Text = "Победа! Все монетки твои!"
winSound:Play()
end
end)`,
// Скрипт каждой монетки — генератор по script-объекту
g1_coin_1: makeCoinScript(),
g1_coin_2: makeCoinScript(),
g1_coin_3: makeCoinScript(),
g1_coin_4: makeCoinScript(),
g1_coin_5: makeCoinScript(),
g1_coin_6: makeCoinScript(),
g1_coin_7: makeCoinScript(),
g1_coin_8: makeCoinScript(),
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 2 — «Прыгай по платформам»
// ═══════════════════════════════════════════════════════════════
'platform-jump': {
g2_main: `-- === ИГРА «ПРЫГАЙ ПО ПЛАТФОРМАМ» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local won = false
-- Подсказка по центру (паритет с JS game.ui.showText)
__rbxl_show_text("Допрыгай до зелёной площадки!", 3)
-- Звуки
local loseSound = Instance.new("Sound", workspace)
loseSound.SoundId = "lose"
loseSound.Volume = 1
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"
winSound.Volume = 1
-- Каждый кадр следим: не упал ли игрок
RunService.Heartbeat:Connect(function()
if won then return end
local char = player.Character
if not char then return end
local hrp = char:FindFirstChild("HumanoidRootPart")
if hrp and hrp.Position.Y < -3 then
player:LoadCharacter()
loseSound:Play()
__rbxl_show_text("Упал! Пробуй снова.", 1.5)
end
end)
-- Финиш-зона шлёт BindableEvent
local finishEvent = getEvent("FinishReached")
finishEvent.Event:Connect(function()
if won then return end
won = true
winSound:Play()
__rbxl_show_text("Победа! Ты дошёл до финиша!", 5)
-- Конфетти над игроком (паритет с JS game.scene.spawnParticles)
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)`,
g2_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("FinishReached")
if ev then ev:Fire() end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 3 — «Не упади» (платформа сужается)
// ═══════════════════════════════════════════════════════════════
'dont-fall': (function() {
const overrides = {
g3_main: `-- === ИГРА «НЕ УПАДИ» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local won = false
__rbxl_show_text("Беги вперёд! Плитки исчезают!", 3)
local loseSound = Instance.new("Sound", workspace)
loseSound.SoundId = "lose"; loseSound.Volume = 1
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
RunService.Heartbeat:Connect(function()
if won then return end
local char = player.Character
if not char then return end
local hrp = char:FindFirstChild("HumanoidRootPart")
if hrp and hrp.Position.Y < -3 then
player:LoadCharacter()
loseSound:Play()
__rbxl_show_text("Упал! Снова.", 1.5)
end
end)
local finishEvent = getEvent("FinishReached")
finishEvent.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)`,
g3_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("FinishReached")
if ev then ev:Fire() end
end)`,
};
// Скрипт каждой плитки — генератор (одинаковый код)
const tileScript = `-- === Скрипт исчезающей плитки (Lua) ===
local Debris = game:GetService("Debris")
local part = script.Parent
local triggered = false
local clickSound = Instance.new("Sound", part)
clickSound.SoundId = "click"; clickSound.Volume = 0.6
part.Touched:Connect(function(hit)
if triggered then return end
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
triggered = true
clickSound:Play()
-- через 1.2с плитка пропадает
Debris:AddItem(part, 1.2)
end)`;
for (let i = 1; i <= 14; i++) overrides['g3_tile_' + i] = tileScript;
return overrides;
})(),
// ═══════════════════════════════════════════════════════════════
// ИГРА 4 — «Кнопка и дверь»
// ═══════════════════════════════════════════════════════════════
'button-door': {
g4_main: `-- === ИГРА «КНОПКА-ОТКРЫВАШКА» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
__rbxl_show_text("Подойди к красной кнопке и нажми E", 4)
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
local winEvent = getEvent("WinReached")
winEvent.Event:Connect(function()
__rbxl_show_text("Победа! Дверь открыта, ты прошёл!", 5)
winSound:Play()
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)`,
g4_button: `-- === Скрипт кнопки (Lua) ===
-- Висит на красной кнопке. Реагирует на E когда игрок рядом.
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local part = script.Parent
local opened = false
local hintVisible = false
-- Подсказка над кнопкой. BillboardGui в shim — generic instance,
-- управляем видимостью через label.Visible.
local hintGui = Instance.new("BillboardGui", part)
hintGui.Size = UDim2.new(4, 0, 1, 0)
hintGui.StudsOffset = Vector3.new(0, 2, 0)
hintGui.AlwaysOnTop = true
local label = Instance.new("TextLabel", hintGui)
label.Size = UDim2.new(1, 0, 1, 0)
label.BackgroundTransparency = 1
label.TextColor3 = Color3.fromRGB(255, 255, 255)
label.TextStrokeTransparency = 0
label.TextScaled = true
label.Text = "[E] Открыть дверь"
label.Visible = false -- скрыт по умолчанию
local clickSound = Instance.new("Sound", part)
clickSound.SoundId = "click"; clickSound.Volume = 0.8
-- Каждый кадр проверяем расстояние до игрока. Подсказку показываем
-- только если игрок в радиусе 4 единиц.
RunService.Heartbeat:Connect(function()
if opened then return end
local px = __rbxl_player_x()
local pz = __rbxl_player_z()
local dx = part.Position.X - px
local dz = part.Position.Z - pz
local dist = math.sqrt(dx*dx + dz*dz)
local near = dist <= 4
if near ~= hintVisible then
hintVisible = near
label.Visible = near
end
end)
UserInputService.InputBegan:Connect(function(input, gp)
if gp then return end
if opened or not hintVisible then return end
if input.KeyCode ~= Enum.KeyCode.E then return end
opened = true
label.Visible = false -- скрываем подсказку (Destroy не уничтожает GUI-overlay)
label:Destroy()
hintGui:Destroy()
clickSound:Play()
__rbxl_show_text("Дверь открывается!", 2)
part.Color = Color3.fromRGB(100, 255, 100)
local door = workspace:FindFirstChild("Дверь")
if door then
local dp = door.Position
local goal = { Position = Vector3.new(dp.X, dp.Y + 6, dp.Z) }
TweenService:Create(door, TweenInfo.new(1.2), goal):Play()
door.CanCollide = false
end
end)`,
g4_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)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 5 — «Лабиринт»
// ═══════════════════════════════════════════════════════════════
'maze': {
g5_main: `-- === ИГРА «ЛАБИРИНТ» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
__rbxl_show_text("Найди выход из лабиринта!", 3)
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
local winEvent = getEvent("WinReached")
winEvent.Event:Connect(function()
__rbxl_show_text("Победа! Ты нашёл выход!", 5)
winSound:Play()
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)`,
g5_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)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 6 — «Угадай цвет»
// ═══════════════════════════════════════════════════════════════
'color-tiles': (function() {
const overrides = {
g6_main: `-- === ИГРА «ЦВЕТНЫЕ ПЛИТКИ» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local painted = 0
local TOTAL = 36
local won = false
__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(160, 255, 160)
label.TextScaled = true
label.Font = Enum.Font.SourceSansBold
label.Text = "Плитки: 0 / " .. TOTAL
local pickupSound = Instance.new("Sound", workspace)
pickupSound.SoundId = "pickup"; pickupSound.Volume = 0.7
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
local paintEvent = getEvent("TilePainted")
paintEvent.Event:Connect(function()
if won then return end
painted = painted + 1
label.Text = "Плитки: " .. painted .. " / " .. TOTAL
pickupSound:Play()
if painted >= 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)`,
};
// Скрипт для каждой из 36 плиток — одинаковый код через генератор
const tileScript = `-- === Скрипт цветной плитки (Lua) ===
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local part = script.Parent
local painted = false
part.Touched:Connect(function(hit)
if painted then return end
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
painted = true
part.Color = Color3.fromRGB(51, 221, 85) -- ярко-зелёный
local ev = ReplicatedStorage:FindFirstChild("TilePainted")
if ev then ev:Fire() end
end)`;
for (let i = 1; i <= 36; i++) overrides['g6_tile_' + i] = tileScript;
return overrides;
})(),
// ═══════════════════════════════════════════════════════════════
// ИГРА 7 — «Ловишка предметов»
// ═══════════════════════════════════════════════════════════════
'catch-falling': {
g7_main: `-- === ИГРА «ПОЙМАЙ ПАДАЮЩЕЕ» — главный скрипт (Lua) ===
local Players = game:GetService("Players")
local Debris = game:GetService("Debris")
local player = Players.LocalPlayer
local score = 0
local GOAL = 15
local won = false
__rbxl_show_text("Лови падающие кубы! Нужно 15", 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, 215, 0)
label.TextScaled = true
label.Font = Enum.Font.SourceSansBold
label.Text = "Поймано: 0 / " .. GOAL
local coinSound = Instance.new("Sound", workspace)
coinSound.SoundId = "coin"; coinSound.Volume = 1
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
-- Каждые 1.5 сек роняем куб (через Heartbeat — task.spawn не умеет yield)
local RunService = game:GetService("RunService")
local _spawnTimer = 0
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)
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)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 8 — «Беги до финиша»
// ═══════════════════════════════════════════════════════════════
'run-to-finish': {
g8_main: `-- === ИГРА «БЕГИ К ФИНИШУ» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local finished = false
local time = 0
__rbxl_show_text("Беги к зелёному финишу — на время!", 3)
-- Секундомер вверху по центру
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
local timerLabel = Instance.new("TextLabel", screenGui)
timerLabel.Size = UDim2.new(0, 220, 0, 60)
timerLabel.Position = UDim2.new(0.5, -110, 0, 20)
timerLabel.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
timerLabel.BackgroundTransparency = 0.4
timerLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
timerLabel.TextScaled = true
timerLabel.Font = Enum.Font.SourceSansBold
timerLabel.Text = "0.0 сек"
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
-- Каждый кадр прибавляем dt к таймеру
RunService.Heartbeat:Connect(function(dt)
if finished then return end
time = time + (dt or 0.016)
-- Округляем до одного знака для отображения
local rounded = math.floor(time * 10) / 10
timerLabel.Text = string.format("%.1f сек", rounded)
end)
-- Финиш-зона шлёт BindableEvent
local finishEvent = getEvent("FinishReached")
finishEvent.Event:Connect(function()
if finished then return end
finished = true
local t = math.floor(time * 10) / 10
winSound:Play()
__rbxl_show_text("Финиш! Твоё время: " .. string.format("%.1f", t) .. " сек", 6)
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)`,
g8_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("FinishReached")
if ev then ev:Fire() end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 9 — «Светофор»
// ═══════════════════════════════════════════════════════════════
'traffic-light': {
g9_main: `-- === ИГРА «СВЕТОФОР» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local won = false
local phase = "green" -- "green" (беги) или "red" (замри)
local phaseTimer = 0
local GREEN_TIME = 3
local RED_TIME = 2.5
__rbxl_show_text("Зелёный — беги! Красный — замри!", 3)
local loseSound = Instance.new("Sound", workspace)
loseSound.SoundId = "lose"; loseSound.Volume = 1
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
-- Находим светофор и сразу красим в зелёный
local light = workspace:FindFirstChild("Светофор")
if light then light.Color = Color3.fromRGB(34, 221, 85) end
__rbxl_show_text("ЗЕЛЁНЫЙ — беги!", 1.2)
-- Каждый кадр считаем таймер фазы и проверяем движение
local prevX, prevZ = nil, nil
RunService.Heartbeat:Connect(function(dt)
if won then return end
dt = dt or 0.016
-- Переключение фаз
phaseTimer = phaseTimer + dt
if phase == "green" and phaseTimer >= GREEN_TIME then
phaseTimer = 0
phase = "red"
if light then light.Color = Color3.fromRGB(226, 59, 59) end
__rbxl_show_text("КРАСНЫЙ — замри!", 1.2)
elseif phase == "red" and phaseTimer >= RED_TIME then
phaseTimer = 0
phase = "green"
if light then light.Color = Color3.fromRGB(34, 221, 85) end
__rbxl_show_text("ЗЕЛЁНЫЙ — беги!", 1.2)
end
-- Если красный и игрок шевелится — респаун
local px = __rbxl_player_x()
local pz = __rbxl_player_z()
if prevX and phase == "red" then
local dx = px - prevX
local dz = pz - prevZ
local moved = math.sqrt(dx*dx + dz*dz)
if moved / dt > 0.8 then
player:LoadCharacter()
loseSound:Play()
__rbxl_show_text("Двинулся на красный! На старт.", 2)
end
end
prevX, prevZ = px, pz
end)
-- Финиш-зона шлёт BindableEvent
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)`,
g9_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)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 10 — «Прыжки на пружинах»
// ═══════════════════════════════════════════════════════════════
'spring-jump': (function() {
const overrides = {
g10_main: `-- === ИГРА «ПРЫЖОК-ПРУЖИНА» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local won = false
__rbxl_show_text("Прыгай по батутам всё выше!", 3)
local loseSound = Instance.new("Sound", workspace)
loseSound.SoundId = "lose"; loseSound.Volume = 1
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
-- Каждый кадр проверяем: упал вниз — на старт
RunService.Heartbeat:Connect(function()
if won then return end
local py = __rbxl_player_y()
if py < -3 then
player:LoadCharacter()
loseSound:Play()
end
end)
-- Финиш-зона шлёт BindableEvent
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)`,
g10_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)`,
};
// Скрипт каждого батута — одинаковый код
const trampScript = `-- === Скрипт батута (Lua) ===
-- Игрок встал на батут — мощный подброс вверх.
local part = script.Parent
local jumpSound = Instance.new("Sound", part)
jumpSound.SoundId = "jump"; jumpSound.Volume = 0.7
local lastBoost = 0
part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
-- Не зацикливаем подброс — минимум 0.5с между активациями
local now = tick()
if now - lastBoost < 0.5 then return end
lastBoost = now
__rbxl_boost_jump(3.2) -- 3.2 = втрое выше обычного прыжка
jumpSound:Play()
end)`;
// Батуты в JS-builder имеют id 4, 5, 6 (после трёх этажей)
for (const tid of [4, 5, 6]) {
overrides['g10_tramp_' + tid] = trampScript;
}
return overrides;
})(),
// ═══════════════════════════════════════════════════════════════
// ИГРА 11 — «Эхо» (нажми кнопку → звук)
// ═══════════════════════════════════════════════════════════════
'echo-room': (function() {
// Звуки и цвета для 6 плиток — должны совпадать с JS-builder
const tiles = [
{ sound: 'coin', color: '#e23b3b' }, // 1
{ sound: 'jump', color: '#f59e0b' }, // 2
{ sound: 'pickup', color: '#facc15' }, // 3
{ sound: 'click', color: '#22c55e' }, // 4
{ sound: 'hit', color: '#3b82f6' }, // 5
{ sound: 'coin', color: '#a855f7' }, // 6
];
const TOTAL = tiles.length;
const overrides = {
g11_main: `-- === ИГРА «ЭХО-КОМНАТА» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local stepped = 0
local TOTAL = ${TOTAL}
local won = false
__rbxl_show_text("Наступи на все цветные плитки!", 3)
-- Счётчик в правом верхнем углу
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
local label = Instance.new("TextLabel", screenGui)
label.Size = UDim2.new(0, 240, 0, 50)
label.Position = UDim2.new(1, -260, 0, 20)
label.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
label.BackgroundTransparency = 0.4
label.TextColor3 = Color3.fromRGB(255, 255, 255)
label.TextScaled = true
label.Font = Enum.Font.SourceSansBold
label.Text = "Плитки: 0 / " .. TOTAL
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
-- Плитка впервые засчитана
local stepEvent = getEvent("EchoStep")
stepEvent.Event:Connect(function()
stepped = stepped + 1
label.Text = "Плитки: " .. stepped .. " / " .. TOTAL
if stepped >= TOTAL then
__rbxl_show_text("Все плитки звучали! Иди на финиш.", 3)
end
end)
-- Игрок встал на финиш
local finishEvent = getEvent("EchoFinish")
finishEvent.Event:Connect(function()
if won then return end
if stepped < TOTAL then
__rbxl_show_text("Сначала пройди все " .. TOTAL .. " плиток!", 2)
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)`,
g11_finish: `-- === Скрипт финиша (Lua) ===
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local part = script.Parent
part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
local ev = ReplicatedStorage:FindFirstChild("EchoFinish")
if ev then ev:Fire() end
end)`,
};
// Скрипт каждой звуковой плитки — со своим звуком и цветом
for (let i = 0; i < TOTAL; i++) {
const t = tiles[i];
overrides['g11_tile_' + (i + 1)] = `-- === Скрипт звуковой плитки (Lua) ===
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local part = script.Parent
local used = false
local lastSound = 0
local tileSound = Instance.new("Sound", part)
tileSound.SoundId = "${t.sound}"; tileSound.Volume = 0.8
part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
-- Звук эхом — каждый раз, но не чаще 0.4с
local now = tick()
if now - lastSound > 0.4 then
lastSound = now
tileSound:Play()
-- Вспышка частиц над плиткой
local pos = part.Position
__rbxl_spawn_particles("sparks", pos.X, pos.Y + 1, pos.Z, 0.6, 1)
end
-- Засчитываем плитку только в первый раз
if not used then
used = true
local ev = ReplicatedStorage:FindFirstChild("EchoStep")
if ev then ev:Fire() end
end
end)`;
}
return overrides;
})(),
// ═══════════════════════════════════════════════════════════════
// ИГРА 12 — «Кодовая дверь»
// ═══════════════════════════════════════════════════════════════
'code-door': {
g12_main: `-- === ИГРА «КОДОВАЯ ДВЕРЬ» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local correctCode = "1234"
local currentInput = ""
print("Введи код 1234 (касайся кнопок по порядку)")
local ev = getEvent("CodeButton")
ev.Event:Connect(function(digit)
currentInput = currentInput .. tostring(digit)
print("Ввод: " .. currentInput)
if #currentInput == 4 then
if currentInput == correctCode then
print("Верно! Дверь открывается")
local doorEv = getEvent("DoorOpen")
doorEv:Fire()
else
print("Неверный код, попробуй ещё")
end
currentInput = ""
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 13 — «Торговец»
// ═══════════════════════════════════════════════════════════════
'trader': {
g13_main: `-- === ИГРА «ТОРГОВЕЦ» (Lua) ===
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
local stats = Instance.new("Folder", player); stats.Name = "leaderstats"
local coins = Instance.new("IntValue", stats); coins.Name = "Монеты"; coins.Value = 10
end)
for _, p in ipairs(Players:GetPlayers()) do
if not p:FindFirstChild("leaderstats") then
local stats = Instance.new("Folder", p); stats.Name = "leaderstats"
local coins = Instance.new("IntValue", stats); coins.Name = "Монеты"; coins.Value = 10
end
end
print("У тебя 10 монет. Купи зелье у торговца!")`,
g13_npc: `-- === Скрипт торговца (Lua) ===
local Players = game:GetService("Players")
local part = script.Parent
part.Touched:Connect(function(hit)
local player = Players:GetPlayerFromCharacter(hit.Parent)
if not player then return end
local stats = player:FindFirstChild("leaderstats")
if not stats then return end
if stats['Монеты'].Value >= 5 then
stats['Монеты'].Value = stats['Монеты'].Value - 5
local h = hit.Parent:FindFirstChild("Humanoid")
if h then h.Health = math.min(h.MaxHealth, h.Health + 50) end
print("Купил зелье! +50 HP. Осталось монет: " .. stats['Монеты'].Value)
else
print("Не хватает монет! Нужно 5")
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 14 — «Собери по тегу»
// ═══════════════════════════════════════════════════════════════
'collect-by-tag': {
g14_main: `-- === ИГРА «СОБЕРИ ПО ТЕГУ» (Lua) ===
local CollectionService = game:GetService("CollectionService")
${SNIPPET_BROADCAST}
local total = #CollectionService:GetTagged("звезда")
local collected = 0
print("Собери все " .. total .. " звёзд!")
local ev = getEvent("StarCollected")
ev.Event:Connect(function()
collected = collected + 1
print("Собрано: " .. collected .. "/" .. total)
if collected >= total then
print("ПОБЕДА! Все звёзды собраны!")
end
end)`,
g14_star: `-- === Скрипт звезды (Lua) ===
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local part = script.Parent
CollectionService:AddTag(part, "звезда")
part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
local ev = ReplicatedStorage:FindFirstChild("StarCollected")
if ev then ev:Fire() end
part:Destroy()
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 15 — «Тир»
// ═══════════════════════════════════════════════════════════════
'shooting-range': {
g15_main: `-- === ИГРА «ТИР» (Lua) ===
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
${SNIPPET_BROADCAST}
local score = 0
print("Стреляй ЛКМ по красным шарам!")
local ev = getEvent("TargetHit")
ev.Event:Connect(function()
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()
end
end)`,
g15_target: `-- === Скрипт мишени (Lua) ===
local part = script.Parent
part:SetAttribute("IsTarget", true)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 16 — «Лавовый пол»
// ═══════════════════════════════════════════════════════════════
'lava-floor': {
g16_main: `-- === ИГРА «ЛАВОВЫЙ ПОЛ» (Lua) ===
print("Прыгай по островкам, не упади в лаву!")`,
g16_lava: `-- === Скрипт лавы (Lua) ===
local part = script.Parent
part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if h then h.Health = 0 end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 17 — «Ключ от сундука»
// ═══════════════════════════════════════════════════════════════
'key-chest': {
g17_main: `-- === ИГРА «КЛЮЧ ОТ СУНДУКА» (Lua) ===
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
local stats = Instance.new("Folder", player); stats.Name = "leaderstats"
local key = Instance.new("BoolValue", stats); key.Name = "Ключ"
end)
for _, p in ipairs(Players:GetPlayers()) do
if not p:FindFirstChild("leaderstats") then
local stats = Instance.new("Folder", p); stats.Name = "leaderstats"
local key = Instance.new("BoolValue", stats); key.Name = "Ключ"
end
end
print("Найди ключ и открой сундук!")`,
g17_key: `-- === Скрипт ключа (Lua) ===
local Players = game:GetService("Players")
local part = script.Parent
part.Touched:Connect(function(hit)
local player = Players:GetPlayerFromCharacter(hit.Parent)
if not player then return end
local stats = player:FindFirstChild("leaderstats")
if stats and stats:FindFirstChild("Ключ") then
stats['Ключ'].Value = true
print("Подобрал ключ!")
part:Destroy()
end
end)`,
g17_chest: `-- === Скрипт сундука (Lua) ===
local Players = game:GetService("Players")
local part = script.Parent
part.Touched:Connect(function(hit)
local player = Players:GetPlayerFromCharacter(hit.Parent)
if not player then return end
local stats = player:FindFirstChild("leaderstats")
if stats and stats['Ключ'] and stats['Ключ'].Value then
print("Сундук открыт! ПОБЕДА!")
part.Color = Color3.fromRGB(255, 215, 0)
else
print("Нужен ключ!")
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 18 — «Качели»
// ═══════════════════════════════════════════════════════════════
'swing': {
g18_main: `-- === ИГРА «КАЧЕЛИ» (Lua) ===
local TweenService = game:GetService("TweenService")
local swing = workspace:WaitForChild("Качели")
local startPos = swing.Position
-- Качаем туда-сюда бесконечно
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()
end
end)
print("Запрыгни на качающуюся платформу!")`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 19 — «Лифт»
// ═══════════════════════════════════════════════════════════════
'elevator': {
g19_main: `-- === ИГРА «ЛИФТ» (Lua) ===
local TweenService = game:GetService("TweenService")
local elevator = workspace:WaitForChild("Лифт")
local startPos = elevator.Position
local topPos = startPos + Vector3.new(0, 10, 0)
local goingUp = true
elevator.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
local goal = { Position = goingUp and topPos or startPos }
TweenService:Create(elevator, TweenInfo.new(3), goal):Play()
goingUp = not goingUp
end)
print("Встань на лифт — он повезёт тебя наверх!")`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 20 — «Имена врагов»
// ═══════════════════════════════════════════════════════════════
'enemy-names': {
g20_main: `-- === ИГРА «ИМЕНА ВРАГОВ» (Lua) ===
local function addLabel(part, text, color)
local bb = Instance.new("BillboardGui", part)
bb.Size = UDim2.new(4, 0, 1, 0)
bb.StudsOffset = Vector3.new(0, 2.5, 0)
bb.AlwaysOnTop = true
local label = Instance.new("TextLabel", bb)
label.Size = UDim2.new(1, 0, 1, 0)
label.BackgroundTransparency = 1
label.Text = text
label.TextColor3 = color or Color3.new(1, 1, 1)
label.TextScaled = true
end
for _, child in ipairs(workspace:GetChildren()) do
if child:IsA("BasePart") and child.Name:match("^Враг") then
addLabel(child, child.Name, Color3.fromRGB(255, 80, 80))
end
end
print("Над врагами появились имена")`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 21 — «Догонялки»
// ═══════════════════════════════════════════════════════════════
'chaser': {
g21_main: `-- === ИГРА «ДОГОНЯЛКИ» (Lua) ===
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local enemy = workspace:WaitForChild("Догонщик")
RunService.Heartbeat:Connect(function(dt)
local player = Players:GetPlayers()[1]
if not player or not player.Character then return end
local target = player.Character:FindFirstChild("HumanoidRootPart")
if not target then return end
-- Двигаемся в сторону игрока со скоростью 5
local dir = (target.Position - enemy.Position)
if dir.Magnitude > 1 then
enemy.Position = enemy.Position + dir.Unit * 5 * dt
else
-- Поймал
local h = player.Character:FindFirstChild("Humanoid")
if h then h:TakeDamage(10) end
end
end)
print("Убегай от догонщика!")`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 22 — «Опасная зона»
// ═══════════════════════════════════════════════════════════════
'danger-zone': {
g22_main: `-- === ИГРА «ОПАСНАЯ ЗОНА» (Lua) ===
print("Не стой в красной зоне!")`,
g22_zone: `-- === Скрипт опасной зоны (Lua) ===
local part = script.Parent
local insiders = {}
part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if h then insiders[h] = true end
end)
part.TouchEnded:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if h then insiders[h] = nil end
end)
-- Урон каждые 0.5 сек пока стоят
while true do
task.wait(0.5)
for h in pairs(insiders) do
if h.Parent then h:TakeDamage(5) end
end
end`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 23 — «3 переключателя»
// ═══════════════════════════════════════════════════════════════
'switches': {
g23_main: `-- === ИГРА «3 ПЕРЕКЛЮЧАТЕЛЯ» (Lua) ===
${SNIPPET_BROADCAST}
local activated = {false, false, false}
print("Активируй все 3 переключателя!")
local ev = getEvent("SwitchToggled")
ev.Event:Connect(function(idx)
activated[idx] = true
print("Переключатель " .. idx .. " активирован")
if activated[1] and activated[2] and activated[3] then
print("ПОБЕДА! Все 3 активированы!")
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 24 — «Падающий мост»
// ═══════════════════════════════════════════════════════════════
'falling-bridge': {
g24_main: `-- === ИГРА «ПАДАЮЩИЙ МОСТ» (Lua) ===
print("Беги по мосту — плиты падают!")`,
g24_plate: `-- === Скрипт падающей плиты (Lua) ===
local part = script.Parent
local fell = false
part.Touched:Connect(function(hit)
if fell then return end
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
fell = true
task.delay(0.5, function()
part.Anchored = false
part.CanCollide = false
game:GetService("Debris"):AddItem(part, 3)
end)
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 25 — «Облёт камеры»
// ═══════════════════════════════════════════════════════════════
'flyby-camera': {
g25_main: `-- === ИГРА «ОБЛЁТ КАМЕРЫ» (Lua) ===
local TweenService = game:GetService("TweenService")
local camera = workspace.CurrentCamera
camera.CameraType = Enum.CameraType.Scriptable
local points = {
CFrame.new(Vector3.new(0, 20, -30), Vector3.new(0, 5, 0)),
CFrame.new(Vector3.new(20, 15, 0), Vector3.new(0, 5, 0)),
CFrame.new(Vector3.new(0, 25, 30), Vector3.new(0, 5, 0)),
}
for _, cf in ipairs(points) do
local tween = TweenService:Create(camera, TweenInfo.new(2), { CFrame = cf })
tween:Play(); tween.Completed:Wait()
end
camera.CameraType = Enum.CameraType.Custom
print("Облёт окончен — теперь играй!")`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 26 — «Магнит монет»
// ═══════════════════════════════════════════════════════════════
'coin-magnet': {
g26_main: `-- === ИГРА «МАГНИТ МОНЕТ» (Lua) ===
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local CollectionService = game:GetService("CollectionService")
${SNIPPET_BROADCAST}
local score = 0
local ev = getEvent("CoinCollected")
ev.Event:Connect(function()
score = score + 1
print("Собрано: " .. score)
end)
RunService.Heartbeat:Connect(function(dt)
local player = Players:GetPlayers()[1]
if not player or not player.Character then return end
local hrp = player.Character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
for _, coin in ipairs(CollectionService:GetTagged("magnetcoin")) do
local dist = (coin.Position - hrp.Position).Magnitude
if dist < 8 then
coin.Position = coin.Position + (hrp.Position - coin.Position).Unit * 20 * dt
if dist < 1 then
ev:Fire()
coin:Destroy()
end
end
end
end)
print("Монетки сами летят к тебе!")`,
g26_coin: `-- === Скрипт магнит-монетки (Lua) ===
local CollectionService = game:GetService("CollectionService")
CollectionService:AddTag(script.Parent, "magnetcoin")`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 27 — «Двойной прыжок»
// ═══════════════════════════════════════════════════════════════
'double-jump': {
g27_main: `-- === ИГРА «ДВОЙНОЙ ПРЫЖОК» (Lua) ===
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local function setupDoubleJump(player)
local jumpsLeft = 2
local char = player.Character or player.CharacterAdded:Wait()
local h = char:WaitForChild("Humanoid")
-- Восстанавливаем прыжки при касании земли
h.StateChanged:Connect(function(_, newState)
if newState == Enum.HumanoidStateType.Landed then
jumpsLeft = 2
end
end)
UserInputService.InputBegan:Connect(function(input, gp)
if gp then return end
if input.KeyCode == Enum.KeyCode.Space and jumpsLeft > 0 then
jumpsLeft = jumpsLeft - 1
if jumpsLeft == 1 then
local hrp = char:FindFirstChild("HumanoidRootPart")
if hrp then
hrp.Velocity = Vector3.new(hrp.Velocity.X, 50, hrp.Velocity.Z)
end
end
end
end)
end
Players.PlayerAdded:Connect(setupDoubleJump)
for _, p in ipairs(Players:GetPlayers()) do setupDoubleJump(p) end
print("Жми Space дважды — двойной прыжок!")`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 28 — «Призрачные стены»
// ═══════════════════════════════════════════════════════════════
'ghost-walls': {
g28_main: `-- === ИГРА «ПРИЗРАЧНЫЕ СТЕНЫ» (Lua) ===
print("Некоторые стены — призрачные. Найди проход!")`,
g28_ghost: `-- === Скрипт призрачной стены (Lua) ===
local part = script.Parent
part.CanCollide = false
part.Transparency = 0.5`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 29 — «Магазин»
// ═══════════════════════════════════════════════════════════════
'shop': {
g29_main: `-- === ИГРА «МАГАЗИН» (Lua) ===
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
local stats = Instance.new("Folder", player); stats.Name = "leaderstats"
local coins = Instance.new("IntValue", stats); coins.Name = "Монеты"; coins.Value = 20
end)
for _, p in ipairs(Players:GetPlayers()) do
if not p:FindFirstChild("leaderstats") then
local stats = Instance.new("Folder", p); stats.Name = "leaderstats"
local coins = Instance.new("IntValue", stats); coins.Name = "Монеты"; coins.Value = 20
end
end
print("У тебя 20 монет — купи что-нибудь!")`,
g29_item: `-- === Скрипт товара (Lua) ===
local Players = game:GetService("Players")
local part = script.Parent
local price = part:GetAttribute("Price") or 5
local bought = false
part.Touched:Connect(function(hit)
if bought then return end
local player = Players:GetPlayerFromCharacter(hit.Parent)
if not player then return end
local stats = player:FindFirstChild("leaderstats")
if not stats then return end
if stats['Монеты'].Value >= price then
stats['Монеты'].Value = stats['Монеты'].Value - price
bought = true
print("Куплено! Цена: " .. price)
part.Transparency = 0.7
else
print("Не хватает! Нужно " .. price .. " монет")
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 30 — «Квесты»
// ═══════════════════════════════════════════════════════════════
'quest-tasks': {
g30_main: `-- === ИГРА «КВЕСТЫ» (Lua) ===
${SNIPPET_BROADCAST}
local quests = {
{ name = "Собери 5 ягод", goal = 5, current = 0 },
{ name = "Победи врага", goal = 1, current = 0 },
{ name = "Дойди до башни", goal = 1, current = 0 },
}
print("Квесты:")
for i, q in ipairs(quests) do print(" " .. i .. ". " .. q.name) end
local ev = getEvent("QuestProgress")
ev.Event:Connect(function(idx, amount)
quests[idx].current = quests[idx].current + (amount or 1)
local q = quests[idx]
print(q.name .. ": " .. q.current .. "/" .. q.goal)
if q.current >= q.goal then
print("Квест выполнен: " .. q.name)
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 31-50: упрощённые версии (главные скрипты)
// ═══════════════════════════════════════════════════════════════
'base-defense': { g31_main: simpleMain("Защити базу от волн врагов!") },
'lap-race': { g32_main: simpleMain("Проедь все круги первым!") },
'boss-platformer': { g33_main: simpleMain("Победи босса прыжками на голову!") },
'harvest': { g34_main: simpleMain("Собирай урожай, продавай в магазин!") },
'hide-from-npc': { g35_main: simpleMain("Прячься от NPC — не попадайся!") },
'box-puzzle': { g36_main: simpleMain("Двигай ящики на места!") },
'obstacle-course': { g37_main: simpleMain("Пройди полосу препятствий!") },
'music-game': { g38_main: simpleMain("Жми клавиши в ритм музыки!") },
'tower-build': { g39_main: simpleMain("Построй самую высокую башню!") },
'wave-survival': { g40_main: simpleMain("Выживай в волнах врагов!") },
'adventure-platformer': { g41_main: simpleMain("Приключение — собирай артефакты!") },
'rpg-village': { g42_main: simpleMain("Бегай по деревне, выполняй квесты!") },
'obstacle-race': { g43_main: simpleMain("Гонка с препятствиями — финишируй!") },
'tower-defense': { g44_main: simpleMain("Расставь башни — не пускай врагов!") },
'arena-shooter': { g45_main: simpleMain("Стреляй по противникам на арене!") },
'clicker': { g46_main: simpleClicker() },
'escape-quest': { g47_main: simpleMain("Найди подсказки и выберись!") },
'mp-tag': { g48_main: simpleMain("Поймай других игроков (мультиплеер)!") },
'mp-race': { g49_main: simpleMain("Гонка на нескольких игроков!") },
'make-your-own': { g50_main: simpleMain("Это твоя пустая площадка — твори!") },
};
// ══════════════════════════════════════════════════════════════════
// Хелперы для генерации часто повторяющихся скриптов
// ══════════════════════════════════════════════════════════════════
/** Возвращает Lua-код скрипта монетки. */
function makeCoinScript() {
return `-- === Скрипт монетки (Lua) ===
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local part = script.Parent
part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
local ev = ReplicatedStorage:FindFirstChild("CoinCollected")
if ev then ev:Fire() end
part:Destroy()
end)`;
}
/** Простой главный скрипт со стартовой подсказкой. */
function simpleMain(message) {
return `-- === Главный скрипт (Lua) ===
print("${message.replace(/"/g, '\\"')}")
-- TODO: эта игра-урок ещё не имеет полной Lua-реализации.
-- Переключи язык на JS в редакторе, чтобы увидеть рабочую механику.`;
}
/** Кликер. */
function simpleClicker() {
return `-- === КЛИКЕР (Lua) ===
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
Players.PlayerAdded:Connect(function(player)
local stats = Instance.new("Folder", player); stats.Name = "leaderstats"
local cnt = Instance.new("IntValue", stats); cnt.Name = "Клики"; cnt.Value = 0
end)
for _, p in ipairs(Players:GetPlayers()) do
if not p:FindFirstChild("leaderstats") then
local stats = Instance.new("Folder", p); stats.Name = "leaderstats"
local cnt = Instance.new("IntValue", stats); cnt.Name = "Клики"; cnt.Value = 0
end
end
local function onClick(player)
local stats = player:FindFirstChild("leaderstats")
if stats and stats:FindFirstChild("Клики") then
stats['Клики'].Value = stats['Клики'].Value + 1
end
end
UserInputService.InputBegan:Connect(function(input, gp)
if gp then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 then
onClick(Players.LocalPlayer)
end
end)
print("Кликай ЛКМ — копи клики!")`;
}