Задание от NPC: соберите 5 кристаллов
NPC выдаёт задание, считает находки и награждает монетами.
NPC запускает личное задание игрока. Каждый кристалл засчитывается один раз; за пять кристаллов выдаётся 30 монет. Другие игроки могут собирать те же кристаллы.
1. Подготовьте объект
Где разместить: Обычный Script в ServerScriptService
В Workspace создайте Folder QuestCrystals и поместите туда пять или более отдельных Part. Установите Anchored = true, CanTouch = true и CanCollide = false.
Создайте модель NPC с Humanoid и Head (через Rig Builder), назовите её QuestNPC.
В ServerScriptService создайте Script QuestCrystalsServer, а в StarterPlayer → StarterPlayerScripts создайте LocalScript QuestCrystalsClient. Вставьте каждый блок кода в соответствующий файл.
Добавьте одну систему leaderstats.Coins (например, из практики сохранения монет).
В Play поговорите с NPC через E, коснитесь пяти разных кристаллов и вернитесь. Сообщения появятся на экране игрока.
Это пути для скриптов из блоков кода ниже. Остальные объекты создайте по инструкции.
├── ServerScriptService
│ └── QuestCrystalsServer (Script)
└── StarterPlayer
└── StarterPlayerScripts
└── QuestCrystalsClient (LocalScript)2. Вставьте код
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local crystals = workspace:WaitForChild("QuestCrystals")
local npc = workspace:WaitForChild("QuestNPC")
local head = npc:WaitForChild("Head")
local prompt = head:FindFirstChildOfClass("ProximityPrompt") or Instance.new("ProximityPrompt")
prompt.ActionText = "Взять / сдать задание"
prompt.ObjectText = "Хранитель кристаллов"
prompt.MaxActivationDistance = 10
prompt.Parent = head
local event = ReplicatedStorage:FindFirstChild("IgroQuestNotice") or Instance.new("RemoteEvent")
event.Name = "IgroQuestNotice"
event.Parent = ReplicatedStorage
local TARGET, REWARD = 5, 30
local states = {}
local function stateFor(player)
if not states[player] then states[player] = {active = false, count = 0, seen = {}} end
return states[player]
end
local function notice(player, message)
event:FireClient(player, message)
end
prompt.Triggered:Connect(function(player)
local state = stateFor(player)
if not state.active then
state.active, state.count, state.seen = true, 0, {}
notice(player, "Задание: соберите " .. TARGET .. " разных кристаллов!")
elseif state.count >= TARGET then
local stats = player:FindFirstChild("leaderstats")
local coins = stats and stats:FindFirstChild("Coins")
if not coins then
notice(player, "Задание выполнено, но для награды нужен leaderstats.Coins. Вернитесь позже!")
return -- Сохраняем выполненное задание, пока нет Coins.
end
coins.Value += REWARD
state.active, state.count, state.seen = false, 0, {}
notice(player, "Отлично! Вы получили " .. REWARD .. " монет!")
else
notice(player, "Собрано: " .. state.count .. " из " .. TARGET)
end
end)
local function connectCrystal(part)
if not part:IsA("BasePart") then return end
part.Touched:Connect(function(hit)
local character = hit:FindFirstAncestorOfClass("Model")
local player = character and Players:GetPlayerFromCharacter(character)
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not player or not humanoid or humanoid.Health <= 0 then return end
local state = stateFor(player)
if not state.active or state.seen[part] or state.count >= TARGET then return end
state.seen[part] = true
state.count += 1
notice(player, "Кристаллы: " .. state.count .. "/" .. TARGET)
end)
end
for _, child in ipairs(crystals:GetChildren()) do connectCrystal(child) end
crystals.ChildAdded:Connect(connectCrystal)
Players.PlayerRemoving:Connect(function(player) states[player] = nil end)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local event = ReplicatedStorage:WaitForChild("IgroQuestNotice")
local gui = Instance.new("ScreenGui")
gui.Name = "IgroQuestMessages"
gui.ResetOnSpawn = false
gui.Parent = player:WaitForChild("PlayerGui")
local label = Instance.new("TextLabel")
label.Size = UDim2.fromScale(0.75, 0.13)
label.Position = UDim2.fromScale(0.125, 0.18)
label.BackgroundColor3 = Color3.fromRGB(24, 45, 65)
label.TextColor3 = Color3.fromRGB(255, 255, 255)
label.TextScaled = true
label.TextWrapped = true
label.Visible = false
label.Parent = gui
local serial = 0
event.OnClientEvent:Connect(function(message)
serial += 1
local current = serial
label.Text = tostring(message)
label.Visible = true
task.delay(4, function()
if current == serial then label.Visible = false end
end)
end)3. Проверьте в игре
Нажмите Play в Roblox Studio и проверьте действие механики. Если механика не работает, откройте окно Output и проверьте тип скрипта, его расположение и названия объектов.
Когда проверите механику в Roblox Studio, отметьте практику как выполненную. Отметка хранится только в этом браузере, не в личном кабинете.
Добавляйте механики по одной и проверяйте окно Output. Не создавайте несколько одинаковых систем монет или интерфейсов; скрипты, меняющие WalkSpeed, прыжок или освещение, могут влиять друг на друга.
Измените цель TARGET с 5 на 3 и награду REWARD с 30 на 50.
Добавьте ещё пять кристаллов и разместите их на разных высотах.
Придумайте три зоны поиска с разной сложностью и наградами.
4. Проверьте себя
Почему прогресс сбора кристаллов нужно хранить отдельно для каждого игрока?
В Workspace должны быть QuestNPC с Head и папка QuestCrystals с деталями. Для монет необходим урок «Сохранение монет». Сообщения показываются в Output, а не в игровом интерфейсе.