Roblox · Pet Simulator · урок 4
Кнопка «Питомцы» открывает окно со всеми купленными питомцами. Нажал на иконку — питомец с тобой (иконка зелёная), ещё раз — убрал. С собой — не больше трёх.
Синим — что добавляем на этом уроке.
ReplicatedStorage → Events (Folder) └─ EquipPetFunction (RemoteFunction) — клиент просит — сервер отвечает да/нет StarterGui └─ PetInventoryGui (ScreenGui) — ResetOnSpawn выкл. ├─ OpenCloseButton (ImageButton / TextButton) │ └─ OpenCloseScript (LocalScript) └─ PetFrame (Frame) — Visible выкл. ├─ Title (TextLabel) ├─ ScrollingFrame (ScrollingFrame) — AutomaticCanvasSize = Y │ ├─ UIGridLayout, UIPadding — иконки сеткой │ └─ Sample (ViewportFrame) — шаблон иконки, Visible выкл. │ └─ Button (TextButton) — во весь Sample, прозрачная └─ PetInventoryLocal (LocalScript)
Где: StarterGui → PetInventoryGui → OpenCloseButton · LocalScript
Зачем: Открывает и закрывает инвентарь.
-- кнопка «Питомцы»
local button = script.Parent
-- окно инвентаря
local frame = button.Parent:WaitForChild("PetFrame")
-- нажали
button.MouseButton1Click:Connect(function()
-- открыто — закрываем, закрыто — открываем
frame.Visible = not frame.Visible
-- конец обработчика
end)Где: StarterGui → PetInventoryGui → PetFrame · LocalScript
Зачем: Иконки питомцев и надевание по клику.
-- общее хранилище
local RS = game:GetService("ReplicatedStorage")
-- образцы питомцев
local pets = RS:WaitForChild("Pets")
-- надеть / снять
local equipFunction = RS:WaitForChild("Events"):WaitForChild("EquipPetFunction")
-- этот игрок
local player = game.Players.LocalPlayer
-- его купленные питомцы
local ownedPets = player:WaitForChild("Pets")
-- окно инвентаря
local frame = script.Parent
-- шаблон иконки
local sample = frame:WaitForChild("ScrollingFrame"):WaitForChild("Sample")
-- цвет: не надет
local OFF = Color3.fromRGB(80, 200, 255)
-- цвет: надет
local ON = Color3.fromRGB(90, 230, 120)
-- иконка одного питомца
local function AddIcon(petValue)
-- его образец
local template = pets:FindFirstChild(petValue.Name)
-- нет такого
if not template then return end
-- копия шаблона
local icon = sample:Clone()
-- имя
icon.Name = petValue.Name
-- показываем
icon.Visible = true
-- не надет
icon.BackgroundColor3 = OFF
-- в список
icon.Parent = sample.Parent
-- питомец для картинки
local petModel = template:Clone()
-- мордой к камере
petModel:PivotTo(CFrame.Angles(0, math.rad(180), 0))
-- в окошко иконки
petModel.Parent = icon
-- камера иконки
local camera = Instance.new("Camera")
-- отходим под размер питомца
camera.CFrame = CFrame.new(0, 0, petModel:GetExtentsSize().Magnitude * 1.2)
-- в иконку
camera.Parent = icon
-- иконка смотрит через неё
icon.CurrentCamera = camera
-- надет ли этот питомец
local equipped = false
-- нажали на иконку
icon.Button.MouseButton1Click:Connect(function()
-- сервер согласился
if equipFunction:InvokeServer(petValue.Name, not equipped) then
-- меняем состояние
equipped = not equipped
-- и цвет
icon.BackgroundColor3 = equipped and ON or OFF
-- конец проверки
end
-- конец обработчика
end)
-- питомца не стало
petValue.AncestryChanged:Connect(function()
-- убираем иконку
if not petValue.Parent then icon:Destroy() end
-- конец обработчика
end)
-- конец функции
end
-- питомцы, что уже есть
for _, petValue in ipairs(ownedPets:GetChildren()) do AddIcon(petValue) end
-- новый питомец
ownedPets.ChildAdded:Connect(function(petValue)
-- иконка — после анимации яйца
task.wait(4)
-- добавляем
AddIcon(petValue)
-- конец обработчика
end)Где: ServerScriptService · Script
Зачем: + надеть/снять питомца с проверками.
-- все игроки
local Players = game:GetService("Players")
-- общее хранилище
local RS = game:GetService("ReplicatedStorage")
-- модуль питомцев
local pet = require(script.Pet)
-- модуль целей
local drop = require(script.Pet.Drop)
-- события
local events = RS:WaitForChild("Events")
-- надеть / снять питомца
local equipFunction = events:WaitForChild("EquipPetFunction")
-- образцы питомцев
local pets = RS:WaitForChild("Pets")
-- питомцы игроков на карте
local playerPets = workspace:WaitForChild("PlayerPets")
-- цели
local drops = workspace:WaitForChild("Drops")
-- сколько питомцев можно взять с собой
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
-- конец обработчика
end)
-- игрок вышел
Players.PlayerRemoving:Connect(function(player)
-- его папка
local folder = playerPets:FindFirstChild(player.Name)
-- убираем питомцев
if folder then folder:Destroy() end
-- конец обработчика
end)
-- подготовить цель
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Запусти Play (или Run) и убедись: