Roblox · Дополнительное
Открыл сундук — крышка откидывается, +50 монет. Следующий раз — только через 5 минут: на надписи идёт обратный отсчёт, у каждого игрока свой. Перезаход отсчёт не сбрасывает.
Синим — что нужно создать.
Workspace └─ Chests (Folder) — все сундуки └─ Chest1 (Model) — имя у каждого сундука своё ├─ Base (Part) — короб; внутри Sound «Open» и ProximityPrompt ├─ Lid (Part) — крышка ├─ Hinge (Part) — невидимая петля у заднего края крышки ├─ Configuration (Configuration) — Reward, Cooldown (секунд) └─ ChestServer (Script) StarterPlayer → StarterPlayerScripts └─ ChestLocal (LocalScript) — отсчёт на надписи
Где: Workspace → Chests → Chest1 · Script
Зачем: Награда, таймер и крышка.
-- плавное движение
local TS = game:GetService("TweenService")
-- все игроки
local Players = game:GetService("Players")
-- модуль монет (раздел «Системы»)
local Coins = require(game:GetService("ServerScriptService"):WaitForChild("Coins"))
-- сундук
local model = script.Parent
-- короб
local base = model:WaitForChild("Base")
-- крышка
local lid = model:WaitForChild("Lid")
-- петля крышки (невидимая деталь у заднего края)
local hinge = model:WaitForChild("Hinge")
-- «Открыть»
local prompt = base:WaitForChild("ProximityPrompt")
-- Reward, Cooldown
local config = model:WaitForChild("Configuration")
-- имя атрибута игрока для этого сундука
local key = "ChestReady_" .. model.Name
-- когда сундук снова откроется для игрока (по номеру — переживает перезаход)
local readyAt = {}
-- крышка закрыта
local closedCF = lid.CFrame
-- крышка откинута на петле
local openCF = hinge.CFrame * CFrame.Angles(math.rad(-100), 0, 0) * hinge.CFrame:ToObjectSpace(lid.CFrame)
-- игрок зашёл (или вернулся)
Players.PlayerAdded:Connect(function(player)
-- показать ему его таймер
player:SetAttribute(key, readyAt[player.UserId])
-- конец обработчика
end)
-- нажал «Открыть»
prompt.Triggered:Connect(function(player)
-- время сервера
local now = workspace:GetServerTimeNow()
-- ещё рано
if now < (readyAt[player.UserId] or 0) then return end
-- следующее открытие
readyAt[player.UserId] = now + config.Cooldown.Value
-- клиент покажет обратный отсчёт
player:SetAttribute(key, readyAt[player.UserId])
-- награда
Coins.Add(player, config.Reward.Value)
-- звук
local sound = base:FindFirstChild("Open")
-- скрип
if sound then sound:Play() end
-- крышка открывается
TS:Create(lid, TweenInfo.new(0.4, Enum.EasingStyle.Back), {CFrame = openCF}):Play()
-- через полторы секунды
task.delay(1.5, function()
-- закрывается
TS:Create(lid, TweenInfo.new(0.4), {CFrame = closedCF}):Play()
-- конец отложенной функции
end)
-- конец обработчика
end)Где: StarterPlayer → StarterPlayerScripts · LocalScript
Зачем: Обратный отсчёт на надписи.
-- этот игрок
local player = game.Players.LocalPlayer
-- все сундуки
local chests = workspace:WaitForChild("Chests")
-- постоянно
while true do
-- два раза в секунду
task.wait(0.5)
-- каждый сундук
for _, chest in ipairs(chests:GetChildren()) do
-- его надпись
local prompt = chest:FindFirstChild("Base") and chest.Base:FindFirstChild("ProximityPrompt")
-- есть
if prompt then
-- сколько ждать
local left = (player:GetAttribute("ChestReady_" .. chest.Name) or 0) - workspace:GetServerTimeNow()
-- ещё рано
if left > 0 then
-- целые секунды
local secs = math.ceil(left)
-- обратный отсчёт — только у этого игрока
prompt.ActionText = string.format("Через %d:%02d", secs // 60, secs % 60)
-- можно
else
-- надпись
prompt.ActionText = "Открыть"
-- конец проверки
end
-- конец проверки
end
-- конец перебора
end
-- конец цикла
endЗапусти Play (или Run) и убедись: