Roblox · Pet Simulator · урок 6
Стена делит карту на две области. Подходишь — «Открыть область за 100 Coins?», «Да» — стена исчезает навсегда (и после перезахода). Публикуем игру.
Синим — что добавляем на этом уроке.
Workspace └─ Doors (Folder) └─ SecondArea (Part) — стена; имя = название области ├─ Price (NumberValue) — цена ├─ PriceGui (SurfaceGui) │ └─ PriceText (TextLabel) └─ Prompt (Part) — перед стеной: прозрачный, CanCollide выкл. └─ ProximityPrompt (ProximityPrompt) ReplicatedStorage → Events (Folder) ├─ BuyAreaEvent (RemoteEvent) └─ BuyAreaFunction (RemoteFunction) ServerScriptService → MainScript → PlayerInfo (Folder) └─ Areas (Folder) — купленные области StarterGui └─ BuyAreaGui (ScreenGui) — ResetOnSpawn выкл. └─ BuyFrame (Frame) — Visible выкл. ├─ Question (TextLabel) └─ YesButton, NoButton (TextButton) StarterPlayer → StarterPlayerScripts └─ MainLocal (LocalScript)
Где: ServerScriptService · Script
Зачем: + продажа областей.
-- все игроки
local Players = game:GetService("Players")
-- общее хранилище
local RS = game:GetService("ReplicatedStorage")
-- модуль питомцев
local pet = require(script.Pet)
-- модуль целей
local drop = require(script.Pet.Drop)
-- сохранение
local saveData = require(script.SaveData)
-- события
local events = RS:WaitForChild("Events")
-- надеть / снять питомца
local equipFunction = events:WaitForChild("EquipPetFunction")
-- показать окно покупки
local buyAreaEvent = events:WaitForChild("BuyAreaEvent")
-- купить область
local buyAreaFunction = events:WaitForChild("BuyAreaFunction")
-- образцы питомцев
local pets = RS:WaitForChild("Pets")
-- питомцы игроков на карте
local playerPets = workspace:WaitForChild("PlayerPets")
-- цели
local drops = workspace:WaitForChild("Drops")
-- стены областей
local doors = workspace:WaitForChild("Doors")
-- сколько питомцев можно взять с собой
local MAX_EQUIPPED = 3
-- игрок зашёл
Players.PlayerAdded:Connect(function(player)
-- папка для его питомцев
local folder = Instance.new("Folder")
-- имя = имя игрока
folder.Name = player.Name
-- в PlayerPets
folder.Parent = playerPets
-- папки из PlayerInfo
for _, info in ipairs(script.PlayerInfo:GetChildren()) do
-- копия — в игрока
info:Clone().Parent = player
-- конец перебора
end
-- загружаем монеты, питомцев, области
saveData.Load(player)
-- конец обработчика
end)
-- игрок вышел
Players.PlayerRemoving:Connect(function(player)
-- сохраняем
saveData.Save(player)
-- его папка
local folder = playerPets:FindFirstChild(player.Name)
-- убираем питомцев
if folder then folder:Destroy() end
-- конец обработчика
end)
-- сервер выключается — сохраняем всех и ждём
game:BindToClose(saveData.SaveAll)
-- подготовить цель
local function SetupDrop(dropObject)
-- полоска здоровья
drop.UpdateGui(dropObject)
-- клик по цели — подключаем ОДИН раз
dropObject.ClickDetector.MouseClick:Connect(function(player)
-- питомцы атакуют
pet.Attack(player, dropObject)
-- конец обработчика
end)
-- конец функции
end
-- цели, что уже стоят
for _, obj in ipairs(drops:GetDescendants()) do
-- это цель
if obj:IsA("Model") and obj:FindFirstChild("ClickDetector") then SetupDrop(obj) end
-- конец перебора
end
-- цель появилась снова
drops.DescendantAdded:Connect(function(obj)
-- подключаем и её
if obj:IsA("Model") and obj:FindFirstChild("ClickDetector") then SetupDrop(obj) end
-- конец обработчика
end)
-- отдельный поток
task.spawn(function()
-- каждую секунду
while task.wait(1) do
-- питомцы наносят урон
pet.Tick()
-- конец цикла
end
-- конец потока
end)
-- игрок нажал на иконку питомца
equipFunction.OnServerInvoke = function(player, petName, equip)
-- прислали не текст
if typeof(petName) ~= "string" then return false end
-- его питомцы на карте
local folder = playerPets:FindFirstChild(player.Name)
-- образец
local template = pets:FindFirstChild(petName)
-- нет папки или такого питомца
if not folder or not template then return false end
-- снять
if not equip then
-- этот питомец на карте
local active = folder:FindFirstChild(petName)
-- убираем
if active then active:Destroy() end
-- готово
return true
-- конец проверки
end
-- сколько таких есть и сколько уже надето
local owned, active = 0, 0
-- купленные питомцы
for _, value in ipairs(player.Pets:GetChildren()) do
-- считаем таких
if value.Name == petName then owned += 1 end
-- конец перебора
end
-- надетые
for _, petModel in ipairs(folder:GetChildren()) do
-- считаем таких
if petModel.Name == petName then active += 1 end
-- конец перебора
end
-- не свой или уже максимум
if active >= owned or #folder:GetChildren() >= MAX_EQUIPPED then return false end
-- питомец
local clone = template:Clone()
-- появляется у хозяина
if player.Character then clone:PivotTo(player.Character:GetPivot()) end
-- сразу к текущей цели
clone.Attack.Value = player.Values.Target.Value
-- на карту
clone.Parent = folder
-- надет
return true
-- конец функции
end
-- игрок нажал «Да»
buyAreaFunction.OnServerInvoke = function(player, door)
-- это не стена области
if typeof(door) ~= "Instance" or door.Parent ~= doors then return false end
-- уже куплено
if player.Areas:FindFirstChild(door.Name) then return false end
-- кошелёк
local coins = player.leaderstats.Coins
-- не хватает
if coins.Value < door.Price.Value then return false end
-- списываем
coins.Value -= door.Price.Value
-- отметка о покупке
local areaValue = Instance.new("StringValue")
-- имя области
areaValue.Name = door.Name
-- в папку Areas — клиент уберёт стену сам
areaValue.Parent = player.Areas
-- куплено
return true
-- конец функции
end
-- каждая стена
for _, door in ipairs(doors:GetChildren()) do
-- цена на стене
door.PriceGui.PriceText.Text = door.Price.Value .. " Coins"
-- игрок нажал E у стены
door.Prompt.ProximityPrompt.Triggered:Connect(function(player)
-- ещё не купил
if not player.Areas:FindFirstChild(door.Name) then
-- показываем ему окно покупки
buyAreaEvent:FireClient(player, door)
-- конец проверки
end
-- конец обработчика
end)
-- конец перебора
endГде: StarterPlayer → StarterPlayerScripts · LocalScript
Зачем: Окно покупки и исчезновение стен.
-- общее хранилище
local RS = game:GetService("ReplicatedStorage")
-- события
local events = RS:WaitForChild("Events")
-- сервер: покажи окно
local buyAreaEvent = events:WaitForChild("BuyAreaEvent")
-- купить
local buyAreaFunction = events:WaitForChild("BuyAreaFunction")
-- этот игрок
local player = game.Players.LocalPlayer
-- его купленные области
local areas = player:WaitForChild("Areas")
-- стены
local doors = workspace:WaitForChild("Doors")
-- окно покупки
local buyFrame = player:WaitForChild("PlayerGui"):WaitForChild("BuyAreaGui"):WaitForChild("BuyFrame")
-- вопрос
local question = buyFrame:WaitForChild("Question")
-- «Да»
local yesButton = buyFrame:WaitForChild("YesButton")
-- «Нет»
local noButton = buyFrame:WaitForChild("NoButton")
-- какую стену покупаем
local currentDoor = nil
-- убрать стену — только у этого игрока
local function RemoveDoor(name)
-- стена с именем области
local door = doors:FindFirstChild(name)
-- убираем
if door then door:Destroy() end
-- конец функции
end
-- уже купленные (после загрузки)
for _, area in ipairs(areas:GetChildren()) do RemoveDoor(area.Name) end
-- купил или данные загрузились позже
areas.ChildAdded:Connect(function(area) RemoveDoor(area.Name) end)
-- сервер просит показать окно
buyAreaEvent.OnClientEvent:Connect(function(door)
-- запоминаем стену
currentDoor = door
-- вопрос с ценой
question.Text = "Открыть " .. door.Name .. " за " .. door.Price.Value .. " Coins?"
-- показываем окно
buyFrame.Visible = true
-- конец обработчика
end)
-- «Да» — обработчик один на всю игру
yesButton.MouseButton1Click:Connect(function()
-- окно не для покупки
if not currentDoor then return end
-- стена
local door = currentDoor
-- сбрасываем
currentDoor = nil
-- сервер продал
if buyAreaFunction:InvokeServer(door) then
-- закрываем — стену уберёт ChildAdded
buyFrame.Visible = false
-- не продал
else
-- сообщаем
question.Text = "Не хватает монет"
-- полторы секунды
task.wait(1.5)
-- закрываем
buyFrame.Visible = false
-- конец проверки
end
-- конец обработчика
end)
-- «Нет»
noButton.MouseButton1Click:Connect(function()
-- ничего не покупаем
currentDoor = nil
-- закрываем
buyFrame.Visible = false
-- конец обработчика
end)Запусти Play (или Run) и убедись: