studio/src/community/docsGamesBuildersLua.js
min 901c770fdc feat(lua-games): полный паритет для игры 2 «Прыгай по платформам»
JS-версия имела:
- ui.showText('Допрыгай до зелёной площадки!', 3)
- onTick: y<-3 → respawn + 'Упал!' + sound 'lose'
- broadcast 'finish' → 'Победа!' + sound 'win' + конфетти
- finish-зона: onTouch → broadcast 'finish'

Lua-версия (паритет):
- ScreenGui подсказка 'Допрыгай до зелёной площадки!' на 3с
- RunService.Heartbeat: hrp.Y < -3 → player:LoadCharacter() + Sound
  'lose' + красный TextLabel 'Упал! Пробуй снова.' на 1.5с
- BindableEvent FinishReached в ReplicatedStorage
- g2_finish: Touched на финиш-зоне → ev:Fire (только 1 раз через fired-флаг)
- g2_main: FinishReached → Sound 'win' + зелёный 'Победа! Ты дошёл до финиша!'

Юзер: открой копию ЗАНОВО на Lua — старый проект 2908 был со старым
кодом (только print), новая копия получит обновлённые скрипты.
2026-06-09 10:47:56 +03:00

1103 lines
52 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
-- Подсказка по центру (на 3 секунды)
local hintGui = Instance.new("ScreenGui", player.PlayerGui)
hintGui.Name = "Hint"
local hint = Instance.new("TextLabel", hintGui)
hint.Size = UDim2.new(0, 480, 0, 60)
hint.Position = UDim2.new(0.5, -240, 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.Font = Enum.Font.SourceSansBold
hint.Text = "Допрыгай до зелёной площадки!"
task.delay(3, function() hintGui:Destroy() end)
-- Звуки
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()
local fallGui = Instance.new("ScreenGui", player.PlayerGui)
local fallLabel = Instance.new("TextLabel", fallGui)
fallLabel.Size = UDim2.new(0, 400, 0, 60)
fallLabel.Position = UDim2.new(0.5, -200, 0.35, 0)
fallLabel.BackgroundColor3 = Color3.fromRGB(120, 0, 0)
fallLabel.BackgroundTransparency = 0.3
fallLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
fallLabel.TextScaled = true
fallLabel.Font = Enum.Font.SourceSansBold
fallLabel.Text = "Упал! Пробуй снова."
task.delay(1.5, function() fallGui:Destroy() end)
end
end)
-- Финиш-зона шлёт BindableEvent
local finishEvent = getEvent("FinishReached")
finishEvent.Event:Connect(function()
if won then return end
won = true
winSound:Play()
local winGui = Instance.new("ScreenGui", player.PlayerGui)
local winLabel = Instance.new("TextLabel", winGui)
winLabel.Size = UDim2.new(0, 540, 0, 80)
winLabel.Position = UDim2.new(0.5, -270, 0.4, 0)
winLabel.BackgroundColor3 = Color3.fromRGB(0, 120, 0)
winLabel.BackgroundTransparency = 0.2
winLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
winLabel.TextScaled = true
winLabel.Font = Enum.Font.SourceSansBold
winLabel.Text = "Победа! Ты дошёл до финиша!"
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': {
g3_main: `-- === ИГРА «НЕ УПАДИ» — главный скрипт (Lua) ===
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
print("Удержись на платформе как можно дольше!")
local startTime = tick()
local alive = true
RunService.Heartbeat:Connect(function()
if not alive then return end
for _, player in ipairs(Players:GetPlayers()) do
local char = player.Character
if char then
local hrp = char:FindFirstChild("HumanoidRootPart")
if hrp and hrp.Position.Y < -5 then
alive = false
local elapsed = math.floor(tick() - startTime)
print("Ты упал! Продержался: " .. elapsed .. " сек")
task.delay(2, function()
player:LoadCharacter()
startTime = tick()
alive = true
end)
end
end
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 4 — «Кнопка и дверь»
// ═══════════════════════════════════════════════════════════════
'button-door': {
g4_main: `-- === ИГРА «КНОПКА И ДВЕРЬ» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
print("Найди кнопку и открой дверь!")
-- Глобальный канал для оповещения двери
getEvent("DoorOpen")`,
g4_button: `-- === Скрипт кнопки (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("DoorOpen")
if ev then ev:Fire() end
print("Кнопка нажата!")
part.Color = Color3.fromRGB(100, 255, 100) -- зелёная
end)`,
g4_door: `-- === Скрипт двери (Lua) ===
local TweenService = game:GetService("TweenService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local door = script.Parent
local startPos = door.Position
local ev = ReplicatedStorage:WaitForChild("DoorOpen")
ev.Event:Connect(function()
-- Поднимаем дверь вверх
local goal = { Position = startPos + Vector3.new(0, 5, 0) }
TweenService:Create(door, TweenInfo.new(1), goal):Play()
door.CanCollide = false
print("Дверь открыта!")
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 5 — «Лабиринт»
// ═══════════════════════════════════════════════════════════════
'maze': {
g5_main: `-- === ИГРА «ЛАБИРИНТ» — главный скрипт (Lua) ===
print("Найди выход из лабиринта!")`,
g5_finish: `-- === Финиш лабиринта (Lua) ===
local part = script.Parent
part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
print("ПОБЕДА! Ты нашёл выход!")
h.WalkSpeed = 0
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 6 — «Угадай цвет»
// ═══════════════════════════════════════════════════════════════
'color-tiles': {
g6_main: `-- === ИГРА «УГАДАЙ ЦВЕТ» — главный скрипт (Lua) ===
${SNIPPET_BROADCAST}
local colors = { "red", "green", "blue", "yellow" }
local target = colors[math.random(1, #colors)]
print("Встань на плитку цвета: " .. target)
local ev = getEvent("TileStepped")
ev.Event:Connect(function(color)
if color == target then
print("Верно! +1 очко")
target = colors[math.random(1, #colors)]
print("Теперь встань на: " .. target)
else
print("Неверно! Нужен " .. target)
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 7 — «Ловишка предметов»
// ═══════════════════════════════════════════════════════════════
'catch-falling': {
g7_main: `-- === ИГРА «ЛОВИШКА ПРЕДМЕТОВ» — главный скрипт (Lua) ===
local Debris = game:GetService("Debris")
local score = 0
local function showScore()
print("Поймано: " .. score)
end
showScore()
-- Каждую секунду создаём падающий предмет
task.spawn(function()
while true do
task.wait(1)
local ball = Instance.new("Part")
ball.Shape = Enum.PartType.Ball
ball.Size = Vector3.new(1, 1, 1)
ball.Position = Vector3.new(math.random(-8, 8), 20, math.random(-8, 8))
ball.Color = Color3.fromRGB(255, 215, 0)
ball.Material = Enum.Material.Neon
ball.Anchored = false
ball.Parent = workspace
Debris:AddItem(ball, 10)
-- Скрипт на ловлю
ball.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if h and ball.Parent then
score = score + 1
showScore()
ball:Destroy()
end
end)
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 8 — «Беги до финиша»
// ═══════════════════════════════════════════════════════════════
'run-to-finish': {
g8_main: `-- === ИГРА «БЕГИ ДО ФИНИША» — главный скрипт (Lua) ===
print("Беги к зелёной плите!")`,
g8_finish: `-- === Финишная плита (Lua) ===
local part = script.Parent
local won = false
part.Touched:Connect(function(hit)
if won then return end
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
won = true
print("ПОБЕДА! Ты добежал!")
h.WalkSpeed = 0
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 9 — «Светофор»
// ═══════════════════════════════════════════════════════════════
'traffic-light': {
g9_main: `-- === ИГРА «СВЕТОФОР» — главный скрипт (Lua) ===
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local isGreen = true
print("ЗЕЛЁНЫЙ — беги!")
-- Каждые 3-5 сек переключаем свет
task.spawn(function()
while true do
task.wait(math.random(3, 5))
isGreen = not isGreen
if isGreen then
print("ЗЕЛЁНЫЙ — беги!")
else
print("КРАСНЫЙ — стой!")
end
end
end)
-- Следим за движением игрока во время красного
local lastPos = {}
RunService.Heartbeat:Connect(function()
if isGreen then return end
for _, player in ipairs(Players:GetPlayers()) do
local char = player.Character
local hrp = char and char:FindFirstChild("HumanoidRootPart")
if hrp then
local prev = lastPos[player]
if prev and (hrp.Position - prev).Magnitude > 0.5 then
print(player.Name .. " двигался на красный! Респаун")
player:LoadCharacter()
end
lastPos[player] = hrp.Position
end
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 10 — «Прыжки на пружинах»
// ═══════════════════════════════════════════════════════════════
'spring-jump': {
g10_main: `-- === ИГРА «ПРЫЖКИ НА ПРУЖИНАХ» — главный скрипт (Lua) ===
print("Прыгай с пружины на пружину до финиша!")`,
g10_spring: `-- === Скрипт пружины (Lua) ===
local part = script.Parent
part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
local hrp = hit.Parent and hit.Parent:FindFirstChild("HumanoidRootPart")
if h and hrp then
-- Подбрасываем игрока вверх
hrp.Velocity = Vector3.new(hrp.Velocity.X, 80, hrp.Velocity.Z)
end
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 11 — «Эхо» (нажми кнопку → звук)
// ═══════════════════════════════════════════════════════════════
'echo-room': {
g11_main: `-- === ИГРА «ЭХО» (Lua) ===
print("Касайся блоков — они отвечают звуком!")`,
g11_block: `-- === Скрипт звукового блока (Lua) ===
local part = script.Parent
local lastTouch = 0
part.Touched:Connect(function(hit)
local now = tick()
if now - lastTouch < 0.5 then return end
lastTouch = now
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end
print("Блок " .. part.Name .. " звенит!")
part.Color = Color3.fromRGB(math.random(0,255), math.random(0,255), math.random(0,255))
end)`,
},
// ═══════════════════════════════════════════════════════════════
// ИГРА 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("Кликай ЛКМ — копи клики!")`;
}