diff --git a/src/community/docsGamesBuildersLua.js b/src/community/docsGamesBuildersLua.js index 8ab55dc..e5b666c 100644 --- a/src/community/docsGamesBuildersLua.js +++ b/src/community/docsGamesBuildersLua.js @@ -2856,7 +2856,91 @@ end)`, }, // ═══════════════════════════════════════════════════════════════ - // ИГРЫ 32-50: явных Lua-версий пока нет. + // ИГРА 32 — «Гонка с кругами» + // ═══════════════════════════════════════════════════════════════ + 'lap-race': (function() { + const CP_COUNT = 4; + const overrides = { + g32_main: `-- === ИГРА «ГОНКА С КРУГАМИ» — главный скрипт (Lua) === +${SNIPPET_BROADCAST} + +local RunService = game:GetService("RunService") +local LAPS = 2 +local CP_COUNT = ${CP_COUNT} +local nextCp = 0 +local lap = 0 +local time = 0 +local won = false + +__rbxl_timer_set(0) +__rbxl_show_text("Проедь 2 круга через чекпоинты!", 3) + +local clickSound = Instance.new("Sound", workspace) +clickSound.SoundId = "click"; clickSound.Volume = 0.6 +local winSound = Instance.new("Sound", workspace) +winSound.SoundId = "win"; winSound.Volume = 1 + +local function updateProgress() + __rbxl_hud_set("race", + "Круг " .. (lap + 1) .. "/" .. LAPS .. " • чекпоинт " .. (nextCp + 1) .. "/" .. CP_COUNT, + 50, 8, "#ffe066", 22) +end +updateProgress() + +-- Таймер каждый кадр +RunService.Heartbeat:Connect(function(dt) + if won then return end + time = time + dt + __rbxl_timer_set(time) +end) + +-- Чекпоинты шлют CheckpointReached:Fire(num) +local cpEvent = getEvent("CheckpointReached") +cpEvent.Event:Connect(function(num) + if won then return end + if num - 1 ~= nextCp then return end + clickSound:Play() + nextCp = nextCp + 1 + if nextCp >= CP_COUNT then + nextCp = 0 + lap = lap + 1 + if lap >= LAPS then + won = true + local t = math.floor(time * 10) / 10 + __rbxl_hud_set("race", "ФИНИШ! " .. t .. " сек", 50, 8, "#22dd55", 24) + __rbxl_show_text("Финиш! Круги пройдены за " .. t .. " сек", 6) + 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) + else + __rbxl_show_text("Круг " .. lap .. " из " .. LAPS .. "!", 2) + updateProgress() + end + else + updateProgress() + end +end)`, + }; + // 4 чекпоинта — Touched → CheckpointReached:Fire(num) + for (let i = 1; i <= CP_COUNT; i++) { + overrides['g32_cp_' + i] = `-- === Скрипт чекпоинта ${i} (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("CheckpointReached") + if ev then ev:Fire(${i}) end +end)`; + } + return overrides; + })(), + + // ═══════════════════════════════════════════════════════════════ + // ИГРЫ 33-50: явных Lua-версий пока нет. // buildGameProject в docsGamesBuilders.js использует generateFallbackLua // (главный скрипт → показ подсказки + слушает FinishReached → // победа+конфетти; скрипт на финиш-примитиве → шлёт FinishReached; diff --git a/src/community/docsLessons.jsx b/src/community/docsLessons.jsx index bdb1036..6437176 100644 --- a/src/community/docsLessons.jsx +++ b/src/community/docsLessons.jsx @@ -4355,7 +4355,7 @@ game.self.onTouch(() => {
Это большой скрипт — разберём его по частям.
{`// === ИГРА «ЗАЩИТА БАЗЫ» — главный скрипт ===
+ {`// === ИГРА «ЗАЩИТА БАЗЫ» — главный скрипт ===
let killed = 0; // сколько врагов уничтожено
let leaked = 0; // сколько врагов дошло до базы
@@ -4417,7 +4417,7 @@ game.every(2, () => {
}
}
});
-});`}
+});`}
Как появляются волны врагов:
game.every(2, ...) — каждые 2 секунды
diff --git a/src/editor/engine/lua/RobloxShim.js b/src/editor/engine/lua/RobloxShim.js
index 9ed5698..3e11c13 100644
--- a/src/editor/engine/lua/RobloxShim.js
+++ b/src/editor/engine/lua/RobloxShim.js
@@ -1979,6 +1979,19 @@ export function registerRobloxShim(lua, opts) {
const text = value == null ? null : ('Очки: ' + value);
send('ui.set', { id: '__score', text });
});
+ // Таймер — паритет с JS game.ui.timer = seconds. Формат mm:ss.
+ global.set('__rbxl_timer_set', (seconds) => {
+ if (seconds == null) {
+ send('ui.set', { id: '__timer', text: null });
+ return;
+ }
+ const n = Number(seconds);
+ if (!Number.isFinite(n)) return;
+ const mm = Math.floor(Math.max(0, n) / 60);
+ const ss = Math.floor(Math.max(0, n) % 60);
+ const txt = (mm < 10 ? '0' : '') + mm + ':' + (ss < 10 ? '0' : '') + ss;
+ send('ui.set', { id: '__timer', text: txt });
+ });
// Двойной прыжок — паритет с JS game.player.setDoubleJump(bool).
global.set('__rbxl_set_double_jump', (enabled) => {
send('player.setDoubleJump', { enabled: !!enabled });