feat: 50 игр на Lua + импорт Roblox для всех + поддержка Lua в плеере #39
@ -2607,26 +2607,129 @@ end)`;
|
|||||||
// ИГРА 30 — «Квесты»
|
// ИГРА 30 — «Квесты»
|
||||||
// ═══════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════
|
||||||
'quest-tasks': {
|
'quest-tasks': {
|
||||||
g30_main: `-- === ИГРА «КВЕСТЫ» (Lua) ===
|
g30_main: `-- === ИГРА «КВЕСТ С ЗАДАНИЯМИ» — главный скрипт (Lua) ===
|
||||||
${SNIPPET_BROADCAST}
|
${SNIPPET_BROADCAST}
|
||||||
|
|
||||||
local quests = {
|
local stage = 0 -- 0=не начат, 1=собрать монетку, 2=дойти до флага, 3=вернуться, 4=готово
|
||||||
{ name = "Собери 5 ягод", goal = 5, current = 0 },
|
|
||||||
{ name = "Победи врага", goal = 1, current = 0 },
|
|
||||||
{ name = "Дойди до башни", goal = 1, current = 0 },
|
|
||||||
}
|
|
||||||
|
|
||||||
print("Квесты:")
|
local function setObjective(text, color)
|
||||||
for i, q in ipairs(quests) do print(" " .. i .. ". " .. q.name) end
|
__rbxl_hud_set("objective", "ЦЕЛЬ: " .. text, 50, 8, color or "#ffe066", 24)
|
||||||
|
|
||||||
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
|
||||||
|
setObjective("подойди к квестодателю и нажми E")
|
||||||
|
|
||||||
|
-- Спавним NPC рядом с тумбой (NPC = квестодатель)
|
||||||
|
local npcRef = __rbxl_spawn_npc("character-a", 1.5, 1, 2, "Старейшина", 100, 0)
|
||||||
|
|
||||||
|
local coinSound = Instance.new("Sound", workspace)
|
||||||
|
coinSound.SoundId = "coin"; coinSound.Volume = 0.7
|
||||||
|
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
|
||||||
|
|
||||||
|
-- Поговорить с NPC
|
||||||
|
local talkEvent = getEvent("Talk")
|
||||||
|
talkEvent.Event:Connect(function()
|
||||||
|
if stage == 0 then
|
||||||
|
stage = 1
|
||||||
|
__rbxl_npc_say(npcRef, "Задание 1: найди жёлтую монетку!", 4)
|
||||||
|
setObjective("собери жёлтую монетку (слева)")
|
||||||
|
elseif stage == 3 then
|
||||||
|
stage = 4
|
||||||
|
__rbxl_npc_say(npcRef, "Молодец! Квест выполнен!", 4)
|
||||||
|
__rbxl_hud_set("objective", "КВЕСТ ПРОЙДЕН!", 50, 8, "#22dd55", 26)
|
||||||
|
__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)
|
||||||
|
elseif stage == 4 then
|
||||||
|
__rbxl_npc_say(npcRef, "Спасибо, герой!", 3)
|
||||||
|
elseif stage == 1 then
|
||||||
|
__rbxl_npc_say(npcRef, "Ты ещё не собрал монетку!", 3)
|
||||||
|
elseif stage == 2 then
|
||||||
|
__rbxl_npc_say(npcRef, "Сначала дойди до синего флага!", 3)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Монетка собрана
|
||||||
|
local coinEvent = getEvent("CoinDone")
|
||||||
|
coinEvent.Event:Connect(function()
|
||||||
|
if stage ~= 1 then return end
|
||||||
|
stage = 2
|
||||||
|
coinSound:Play()
|
||||||
|
__rbxl_npc_say(npcRef, "Отлично! Теперь дойди до синего флага.", 4)
|
||||||
|
__rbxl_show_text("Монетка собрана!", 2)
|
||||||
|
setObjective("дойди до синего флага (справа)")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Флаг достигнут
|
||||||
|
local flagEvent = getEvent("FlagDone")
|
||||||
|
flagEvent.Event:Connect(function()
|
||||||
|
if stage ~= 2 then return end
|
||||||
|
stage = 3
|
||||||
|
pickupSound:Play()
|
||||||
|
__rbxl_show_text("Флаг найден!", 2)
|
||||||
|
setObjective("вернись к квестодателю и нажми E")
|
||||||
|
end)`,
|
||||||
|
g30_npc: `-- === Скрипт квестодателя (Lua) ===
|
||||||
|
local UserInputService = game:GetService("UserInputService")
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local RunService = game:GetService("RunService")
|
||||||
|
local part = script.Parent
|
||||||
|
local hintVisible = false
|
||||||
|
|
||||||
|
RunService.Heartbeat:Connect(function()
|
||||||
|
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
|
||||||
|
if near then
|
||||||
|
__rbxl_hud_set("g30_npc_hint", "[E] Поговорить", 50, 75, "#ffe44a", 20)
|
||||||
|
else
|
||||||
|
__rbxl_hud_set("g30_npc_hint", nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
UserInputService.InputBegan:Connect(function(input, gp)
|
||||||
|
if gp then return end
|
||||||
|
if not hintVisible then return end
|
||||||
|
if input.KeyCode ~= Enum.KeyCode.E then return end
|
||||||
|
local ev = ReplicatedStorage:FindFirstChild("Talk")
|
||||||
|
if ev then ev:Fire() end
|
||||||
|
end)`,
|
||||||
|
g30_coin: `-- === Скрипт квест-монетки (Lua) ===
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local part = script.Parent
|
||||||
|
local taken = false
|
||||||
|
|
||||||
|
part.Touched:Connect(function(hit)
|
||||||
|
if taken then return end
|
||||||
|
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||||||
|
if not h then return end
|
||||||
|
taken = true
|
||||||
|
local ev = ReplicatedStorage:FindFirstChild("CoinDone")
|
||||||
|
if ev then ev:Fire() end
|
||||||
|
part:Destroy()
|
||||||
|
end)`,
|
||||||
|
g30_flag: `-- === Скрипт квест-флага (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("FlagDone")
|
||||||
|
if ev then ev:Fire() end
|
||||||
end)`,
|
end)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -4019,7 +4019,7 @@ game.self.onTouch(() => {
|
|||||||
продаёт ключ, открывает дверь.
|
продаёт ключ, открывает дверь.
|
||||||
</p>
|
</p>
|
||||||
<ScriptKind kind="global" />
|
<ScriptKind kind="global" />
|
||||||
<Code>{`// === ИГРА «МАГАЗИН» — главный скрипт ===
|
<CodeBoth game="shop" script="g29_main">{`// === ИГРА «МАГАЗИН» — главный скрипт ===
|
||||||
|
|
||||||
let coins = 0;
|
let coins = 0;
|
||||||
const PRICE = 5; // ключ стоит 5 монет
|
const PRICE = 5; // ключ стоит 5 монет
|
||||||
@ -4070,7 +4070,7 @@ game.onMessage('win', () => {
|
|||||||
const p = game.player.position;
|
const p = game.player.position;
|
||||||
game.scene.spawnParticles('confetti',
|
game.scene.spawnParticles('confetti',
|
||||||
{ x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 });
|
{ x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 });
|
||||||
});`}</Code>
|
});`}</CodeBoth>
|
||||||
<p>
|
<p>
|
||||||
Каждый объект магазина — монетка, прилавок, дверь, финиш —
|
Каждый объект магазина — монетка, прилавок, дверь, финиш —
|
||||||
работает в своей «песочнице» и не видит переменные
|
работает в своей «песочнице» и не видит переменные
|
||||||
@ -4100,23 +4100,23 @@ game.onMessage('win', () => {
|
|||||||
|
|
||||||
<h3 className="lessonH">Шаг 3. Скрипт монетки</h3>
|
<h3 className="lessonH">Шаг 3. Скрипт монетки</h3>
|
||||||
<ScriptKind kind="object" on="каждую монетку" />
|
<ScriptKind kind="object" on="каждую монетку" />
|
||||||
<Code>{`// === Скрипт монетки ===
|
<CodeBoth game="shop" script="g29_coin_1">{`// === Скрипт монетки ===
|
||||||
game.self.onTouch(() => {
|
game.self.onTouch(() => {
|
||||||
game.broadcast('coin');
|
game.broadcast('coin');
|
||||||
game.self.delete();
|
game.self.delete();
|
||||||
});`}</Code>
|
});`}</CodeBoth>
|
||||||
|
|
||||||
<h3 className="lessonH">Шаг 4. Скрипт прилавка и двери</h3>
|
<h3 className="lessonH">Шаг 4. Скрипт прилавка и двери</h3>
|
||||||
<ScriptKind kind="object" on="прилавок" />
|
<ScriptKind kind="object" on="прилавок" />
|
||||||
<Code>{`// === Скрипт прилавка ===
|
<CodeBoth game="shop" script="g29_shop">{`// === Скрипт прилавка ===
|
||||||
game.self.onInteract(() => {
|
game.self.onInteract(() => {
|
||||||
game.broadcast('buy');
|
game.broadcast('buy');
|
||||||
}, { text: 'Купить ключ (5 монет)', distance: 4 });`}</Code>
|
}, { text: 'Купить ключ (5 монет)', distance: 4 });`}</CodeBoth>
|
||||||
<ScriptKind kind="object" on="дверь" />
|
<ScriptKind kind="object" on="дверь" />
|
||||||
<Code>{`// === Скрипт двери ===
|
<CodeBoth game="shop" script="g29_door">{`// === Скрипт двери ===
|
||||||
game.self.onInteract(() => {
|
game.self.onInteract(() => {
|
||||||
game.broadcast('open-door');
|
game.broadcast('open-door');
|
||||||
}, { text: 'Открыть дверь', distance: 4 });`}</Code>
|
}, { text: 'Открыть дверь', distance: 4 });`}</CodeBoth>
|
||||||
<p>
|
<p>
|
||||||
И прилавок, и дверь — это объекты с взаимодействием по
|
И прилавок, и дверь — это объекты с взаимодействием по
|
||||||
<kbd className="kbd">E</kbd>. Подошёл к прилавку и нажал
|
<kbd className="kbd">E</kbd>. Подошёл к прилавку и нажал
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user