docs(39) + feat(g40): «Выживание от волн»
g39 docs: CodeBoth main+spot_1.
g40 паритет:
- WAVES=3, count=wave+2 (3,4,5 врагов)
- Враги по кругу radius=10 (cos/sin), npc.follow('player')
- BindableEvent EnemyClicked(ref)
- __rbxl_npc_on_click(ref, fn) — каждый враг шлёт ref в общий event
- Главный проверяет dist<5, npc.remove + explosion + aliveInWave--
- 0 живых → task.delay 2 startWave (forward-decl)
- 3 волны → 'Победа!' + confetti
This commit is contained in:
parent
f7b296f43b
commit
cce9d2e293
@ -3604,7 +3604,88 @@ end)`;
|
||||
})(),
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// ИГРЫ 40-50: явных Lua-версий пока нет.
|
||||
// ИГРА 40 — «Выживание от волн»
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
'wave-survival': {
|
||||
g40_main: `-- === ИГРА «ВЫЖИВАНИЕ ОТ ВОЛН» — главный скрипт (Lua) ===
|
||||
${SNIPPET_BROADCAST}
|
||||
|
||||
local WAVES = 3
|
||||
local wave = 0
|
||||
local won = false
|
||||
|
||||
__rbxl_show_text("Отбей 3 волны врагов! Кликай по ним", 3)
|
||||
|
||||
local hitSound = Instance.new("Sound", workspace)
|
||||
hitSound.SoundId = "hit"; hitSound.Volume = 0.6
|
||||
local winSound = Instance.new("Sound", workspace)
|
||||
winSound.SoundId = "win"; winSound.Volume = 1
|
||||
|
||||
-- Текущие живые враги в волне: { ref → true }
|
||||
local aliveInWave = 0
|
||||
|
||||
-- Каждый враг при клике шлёт EnemyClicked:Fire(ref).
|
||||
-- Главный скрипт проверяет dist<5 и наносит урон.
|
||||
local clickEvent = getEvent("EnemyClicked")
|
||||
local enemiesRefs = {} -- ref → true (живые)
|
||||
clickEvent.Event:Connect(function(localRef)
|
||||
if won then return end
|
||||
if not enemiesRefs[localRef] then return end
|
||||
local px = __rbxl_player_x()
|
||||
local pz = __rbxl_player_z()
|
||||
local ex = __rbxl_npc_x(localRef)
|
||||
local ez = __rbxl_npc_z(localRef)
|
||||
if ex == 0 and ez == 0 then return end
|
||||
local dx = px - ex
|
||||
local dz = pz - ez
|
||||
local dist = math.sqrt(dx*dx + dz*dz)
|
||||
if dist < 5 then
|
||||
enemiesRefs[localRef] = nil
|
||||
__rbxl_spawn_particles("explosion", ex, 2, ez, 0.4, 1)
|
||||
__rbxl_npc_remove(localRef)
|
||||
hitSound:Play()
|
||||
aliveInWave = aliveInWave - 1
|
||||
if aliveInWave <= 0 then
|
||||
if wave >= WAVES then
|
||||
won = true
|
||||
__rbxl_show_text("Победа! Все волны отбиты!", 5)
|
||||
winSound:Play()
|
||||
__rbxl_spawn_particles("confetti", px, 3, pz, 3, 3)
|
||||
else
|
||||
task.delay(2, startWave)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function startWave()
|
||||
if won then return end
|
||||
wave = wave + 1
|
||||
__rbxl_show_text("Волна " .. wave .. " из " .. WAVES .. "!", 3)
|
||||
hitSound:Play()
|
||||
local count = wave + 2
|
||||
aliveInWave = count
|
||||
for i = 1, count do
|
||||
local angle = (i - 1) / count * math.pi * 2
|
||||
local ex = math.cos(angle) * 10
|
||||
local ez = math.sin(angle) * 10
|
||||
local ref = __rbxl_spawn_npc("character-b", ex, 1, ez, "Враг", 40, 2)
|
||||
enemiesRefs[ref] = true
|
||||
task.delay(0.3, function()
|
||||
__rbxl_npc_follow(ref, "player")
|
||||
end)
|
||||
__rbxl_npc_on_click(ref, function()
|
||||
local ev = game:GetService("ReplicatedStorage"):FindFirstChild("EnemyClicked")
|
||||
if ev then ev:Fire(ref) end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
task.delay(2, startWave)`,
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// ИГРЫ 41-50: явных Lua-версий пока нет.
|
||||
// buildGameProject в docsGamesBuilders.js использует generateFallbackLua
|
||||
// (главный скрипт → показ подсказки + слушает FinishReached →
|
||||
// победа+конфетти; скрипт на финиш-примитиве → шлёт FinishReached;
|
||||
|
||||
@ -5550,7 +5550,7 @@ game.self.onInteract(() => {
|
||||
|
||||
<h3 className="lessonH">Шаг 2. Главный скрипт</h3>
|
||||
<ScriptKind kind="global" />
|
||||
<Code>{`// === ИГРА «БАШНЯ — СТРОЙКА» — главный скрипт ===
|
||||
<CodeBoth game="tower-build" script="g39_main">{`// === ИГРА «БАШНЯ — СТРОЙКА» — главный скрипт ===
|
||||
|
||||
const STEPS = 8;
|
||||
let placed = 0; // сколько блоков поставлено
|
||||
@ -5580,7 +5580,7 @@ game.onMessage('place', (d) => {
|
||||
} else {
|
||||
game.ui.showText('Блок ' + placed + ' из ' + STEPS, 1.5);
|
||||
}
|
||||
});`}</Code>
|
||||
});`}</CodeBoth>
|
||||
<p>Разберём:</p>
|
||||
<ul>
|
||||
<li><code>placed</code> — сколько блоков уже стоит;</li>
|
||||
@ -5599,7 +5599,7 @@ game.onMessage('place', (d) => {
|
||||
у остальных поменяй число в <code>place</code>.
|
||||
</p>
|
||||
<ScriptKind kind="object" on="каждое место-призрак" />
|
||||
<Code>{`// === Скрипт места под блок 1 ===
|
||||
<CodeBoth game="tower-build" script="g39_spot_1">{`// === Скрипт места под блок 1 ===
|
||||
let built = false;
|
||||
game.self.onInteract(() => {
|
||||
if (built) return;
|
||||
@ -5610,7 +5610,7 @@ game.self.onInteract(() => {
|
||||
game.scene.setCollide(game.self.ref, true);
|
||||
built = true;
|
||||
game.broadcast('place', { n: 1 });
|
||||
}, { text: 'Поставить блок', distance: 4 });`}</Code>
|
||||
}, { text: 'Поставить блок', distance: 4 });`}</CodeBoth>
|
||||
<p>Что происходит при нажатии:</p>
|
||||
<ul>
|
||||
<li><code>passThrough(ref, false)</code> — сквозь блок
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user