Roblox · 2D Раннер · урок 4
Монеты на трассе пополняют кошелёк игрока. За монеты в меню улучшений покупаются ускорение, высокий прыжок и щит от препятствий на 10 секунд.
Синим — что добавляем на этом уроке.
Workspace └─ Coins (Folder) └─ Coin (Part) — монета — одна деталь, Anchored, CanCollide выкл. ReplicatedStorage └─ Events (Folder) └─ BoostEvent (RemoteEvent) ServerScriptService ├─ Killbrick (Script) — дополняем ├─ CoinsServer (Script) └─ BoostServer (Script) StarterGui ├─ CoinsGui (ScreenGui) │ └─ CoinsValue (TextLabel) │ └─ CoinsLocal (LocalScript) └─ BoostGui (ScreenGui) └─ Frame (Frame) ├─ Speed, Jump, Shield (ImageButton) — имя кнопки = название улучшения ├─ SpeedPrice, JumpPrice, ShieldPrice (TextLabel) — цены └─ BoostLocal (LocalScript)
Где: ServerScriptService · Script
Зачем: Кошелёк каждого игрока и подбор монет.
-- папка со всеми монетами
local coinsFolder = workspace:WaitForChild("Coins")
-- через сколько секунд монета возвращается
local RESPAWN = 10
-- игрок зашёл
game.Players.PlayerAdded:Connect(function(player)
-- его кошелёк
local coins = Instance.new("IntValue")
-- имя
coins.Name = "Coins"
-- в таблицу очков (её создаёт ScoreServer)
coins.Parent = player:WaitForChild("leaderstats")
-- конец обработчика
end)
-- каждая монета
for _, coin in pairs(coinsFolder:GetChildren()) do
-- это деталь
if coin:IsA("BasePart") then
-- монеты что-то коснулось
coin.Touched:Connect(function(otherPart)
-- её уже подобрали в этот же момент
if not coin.CanTouch then return end
-- чей это персонаж
local player = game.Players:GetPlayerFromCharacter(otherPart.Parent)
-- не игрок
if not player then return end
-- его кошелёк
local coins = player.leaderstats:FindFirstChild("Coins")
-- ещё не создан
if not coins then return end
-- больше не подбирается
coin.CanTouch = false
-- и не видна
coin.Transparency = 1
-- плюс монета
coins.Value += 1
-- ждём
task.wait(RESPAWN)
-- монета снова видна
coin.Transparency = 0
-- и снова подбирается
coin.CanTouch = true
-- конец обработчика
end)
-- конец проверки
end
-- конец перебора
endГде: StarterGui → CoinsGui → CoinsValue · LocalScript
Зачем: Показывает, сколько монет в кошельке.
-- игрок на этом компьютере
local player = game.Players.LocalPlayer
-- его кошелёк
local coins = player:WaitForChild("leaderstats"):WaitForChild("Coins")
-- надпись с монетами
local text = script.Parent
-- обновить надпись
local function Update()
-- сколько монет
text.Text = coins.Value .. " $"
-- конец функции
end
-- показываем сразу
Update()
-- монет стало больше или меньше — обновляем
coins.Changed:Connect(Update)Где: StarterGui → BoostGui → Frame · LocalScript
Зачем: Отправляет серверу название нажатого улучшения.
-- рамка с кнопками
local frame = script.Parent
-- событие «купить улучшение»
local BoostEvent = game.ReplicatedStorage:WaitForChild("Events"):WaitForChild("BoostEvent")
-- всё внутри рамки
for _, button in pairs(frame:GetChildren()) do
-- это кнопка
if button:IsA("ImageButton") then
-- на неё нажали
button.MouseButton1Click:Connect(function()
-- просим сервер продать улучшение с именем кнопки
BoostEvent:FireServer(button.Name)
-- конец обработчика
end)
-- конец проверки
end
-- конец перебора
endГде: ServerScriptService · Script
Зачем: Продаёт улучшения и включает их на 10 секунд.
-- просьбы купить улучшение
local BoostEvent = game.ReplicatedStorage:WaitForChild("Events"):WaitForChild("BoostEvent")
-- цена каждого улучшения; другие названия не продаём
local PRICES = {Speed = 50, Jump = 100, Shield = 150}
-- сколько секунд действует улучшение
local DURATION = 10
-- включить (on = true) или выключить улучшение
local function Apply(character, boost, on)
-- персонаж
local humanoid = character:FindFirstChildOfClass("Humanoid")
-- персонажа уже нет
if not humanoid then return end
-- скорость
if boost == "Speed" then
-- 30 с улучшением, 16 — обычная
humanoid.WalkSpeed = on and 30 or 16
-- прыжок
elseif boost == "Jump" then
-- 12 с улучшением, 7.2 — обычная высота
humanoid.JumpHeight = on and 12 or 7.2
-- щиту ничего менять не нужно — его проверяет Killbrick
end
-- метка на персонаже: SpeedOn, JumpOn, ShieldOn
character:SetAttribute(boost .. "On", on or nil)
-- конец функции
end
-- игрок нажал кнопку
BoostEvent.OnServerEvent:Connect(function(player, boost)
-- цена этого улучшения
local price = PRICES[boost]
-- такого улучшения нет
if not price then return end
-- его персонаж
local character = player.Character
-- персонажа нет
if not character then return end
-- это улучшение уже действует
if character:GetAttribute(boost .. "On") then return end
-- его кошелёк
local coins = player.leaderstats.Coins
-- не хватает монет
if coins.Value < price then return end
-- списываем монеты
coins.Value -= price
-- включаем
Apply(character, boost, true)
-- ждём
task.wait(DURATION)
-- выключаем
Apply(character, boost, false)
-- конец обработчика
end)Где: ServerScriptService · Script
Зачем: Как раньше, но персонажа со щитом не трогает.
-- папка со всеми опасными препятствиями
local killFolder = workspace:WaitForChild("Kill")
-- все детали, в том числе внутри моделей
for _, part in pairs(killFolder:GetDescendants()) do
-- это деталь, а не папка или модель
if part:IsA("BasePart") then
-- детали что-то коснулось
part.Touched:Connect(function(otherPart)
-- модель, в которой коснувшаяся деталь
local character = otherPart.Parent
-- это персонаж?
local humanoid = character:FindFirstChildOfClass("Humanoid")
-- нет — пропускаем
if not humanoid then return end
-- куплен щит — препятствие не убивает
if character:GetAttribute("ShieldOn") then return end
-- персонаж погибает
humanoid.Health = 0
-- конец обработчика
end)
-- конец проверки
end
-- конец перебора
endЗапусти Play (или Run) и убедись: