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
|
// buildGameProject в docsGamesBuilders.js использует generateFallbackLua
|
||||||
// (главный скрипт → показ подсказки + слушает FinishReached →
|
// (главный скрипт → показ подсказки + слушает FinishReached →
|
||||||
// победа+конфетти; скрипт на финиш-примитиве → шлёт FinishReached;
|
// победа+конфетти; скрипт на финиш-примитиве → шлёт FinishReached;
|
||||||
|
|||||||
@ -5550,7 +5550,7 @@ game.self.onInteract(() => {
|
|||||||
|
|
||||||
<h3 className="lessonH">Шаг 2. Главный скрипт</h3>
|
<h3 className="lessonH">Шаг 2. Главный скрипт</h3>
|
||||||
<ScriptKind kind="global" />
|
<ScriptKind kind="global" />
|
||||||
<Code>{`// === ИГРА «БАШНЯ — СТРОЙКА» — главный скрипт ===
|
<CodeBoth game="tower-build" script="g39_main">{`// === ИГРА «БАШНЯ — СТРОЙКА» — главный скрипт ===
|
||||||
|
|
||||||
const STEPS = 8;
|
const STEPS = 8;
|
||||||
let placed = 0; // сколько блоков поставлено
|
let placed = 0; // сколько блоков поставлено
|
||||||
@ -5580,7 +5580,7 @@ game.onMessage('place', (d) => {
|
|||||||
} else {
|
} else {
|
||||||
game.ui.showText('Блок ' + placed + ' из ' + STEPS, 1.5);
|
game.ui.showText('Блок ' + placed + ' из ' + STEPS, 1.5);
|
||||||
}
|
}
|
||||||
});`}</Code>
|
});`}</CodeBoth>
|
||||||
<p>Разберём:</p>
|
<p>Разберём:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>placed</code> — сколько блоков уже стоит;</li>
|
<li><code>placed</code> — сколько блоков уже стоит;</li>
|
||||||
@ -5599,7 +5599,7 @@ game.onMessage('place', (d) => {
|
|||||||
у остальных поменяй число в <code>place</code>.
|
у остальных поменяй число в <code>place</code>.
|
||||||
</p>
|
</p>
|
||||||
<ScriptKind kind="object" on="каждое место-призрак" />
|
<ScriptKind kind="object" on="каждое место-призрак" />
|
||||||
<Code>{`// === Скрипт места под блок 1 ===
|
<CodeBoth game="tower-build" script="g39_spot_1">{`// === Скрипт места под блок 1 ===
|
||||||
let built = false;
|
let built = false;
|
||||||
game.self.onInteract(() => {
|
game.self.onInteract(() => {
|
||||||
if (built) return;
|
if (built) return;
|
||||||
@ -5610,7 +5610,7 @@ game.self.onInteract(() => {
|
|||||||
game.scene.setCollide(game.self.ref, true);
|
game.scene.setCollide(game.self.ref, true);
|
||||||
built = true;
|
built = true;
|
||||||
game.broadcast('place', { n: 1 });
|
game.broadcast('place', { n: 1 });
|
||||||
}, { text: 'Поставить блок', distance: 4 });`}</Code>
|
}, { text: 'Поставить блок', distance: 4 });`}</CodeBoth>
|
||||||
<p>Что происходит при нажатии:</p>
|
<p>Что происходит при нажатии:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>passThrough(ref, false)</code> — сквозь блок
|
<li><code>passThrough(ref, false)</code> — сквозь блок
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user