Roblox · Аркада · урок 3
Враги появляются волнами и бегут к ближайшему игроку. Убил — +10 очков. Каждая волна больше и быстрее. Вверху — номер волны и очки.
Синим — что добавляем на этом уроке.
Workspace ├─ Arena → EnemySpawns (Folder) — невидимые точки по углам └─ Enemies (Folder) — живые враги ServerStorage └─ Enemy (Model) — R15-риг (Avatar → Rig Builder), без Animate ServerScriptService └─ EnemyServer (Script) StarterGui └─ ScoreGui (ScreenGui) — Info (TextLabel); ScoreLocal
Где: ServerScriptService · Script
Зачем: Волны, погоня, очки.
-- игроки
local Players = game:GetService("Players")
-- атрибут волны
local RS = game:GetService("ReplicatedStorage")
-- образец врага
local SS = game:GetService("ServerStorage")
-- враг (R15-риг)
local sample = SS:WaitForChild("Enemy")
-- точки появления
local spawns = workspace:WaitForChild("Arena"):WaitForChild("EnemySpawns")
-- живые враги
local folder = workspace:WaitForChild("Enemies")
-- очков за врага
local REWARD = 10
-- урон при касании
local TOUCH_DAMAGE = 10
-- номер волны
local wave = 0
-- очки игрока
local function Score(player)
-- таблица справа
local stats = player:FindFirstChild("leaderstats") or Instance.new("Folder")
-- имя
stats.Name = "leaderstats"
-- в игрока
stats.Parent = player
-- очки
local score = stats:FindFirstChild("Score") or Instance.new("IntValue")
-- имя
score.Name = "Score"
-- в таблицу
score.Parent = stats
-- отдаём
return score
-- конец функции
end
-- новые игроки
Players.PlayerAdded:Connect(Score)
-- кто зашёл раньше скрипта
for _, player in ipairs(Players:GetPlayers()) do Score(player) end
-- ближайший живой игрок
local function Nearest(position)
-- пока никого
local best, bestDistance = nil, math.huge
-- все игроки
for _, player in ipairs(Players:GetPlayers()) do
-- персонаж
local character = player.Character
-- центр
local root = character and character:FindFirstChild("HumanoidRootPart")
-- Humanoid
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
-- жив и ближе
if root and humanoid and humanoid.Health > 0 and (root.Position - position).Magnitude < bestDistance then
-- запоминаем
best, bestDistance = humanoid, (root.Position - position).Magnitude
-- конец проверки
end
-- конец перебора
end
-- Humanoid цели и расстояние
return best, bestDistance
-- конец функции
end
-- один враг
local function Spawn()
-- точки
local points = spawns:GetChildren()
-- копия
local enemy = sample:Clone()
-- Humanoid
local humanoid = enemy:FindFirstChildOfClass("Humanoid")
-- центр
local root = enemy:FindFirstChild("HumanoidRootPart")
-- на случайную точку
enemy:PivotTo(points[math.random(1, #points)].CFrame + Vector3.new(0, 3, 0))
-- с каждой волной быстрее
humanoid.WalkSpeed = 10 + wave
-- в мир
enemy.Parent = folder
-- движение считает сервер
root:SetNetworkOwner(nil)
-- убит
humanoid.Died:Connect(function()
-- кто добил
local player = Players:GetPlayerByUserId(humanoid:GetAttribute("LastHit") or 0)
-- +10 очков
if player then Score(player).Value += REWARD end
-- тело исчезает
task.delay(1, function() enemy:Destroy() end)
-- конец функции
end)
-- мозг врага
task.spawn(function()
-- время прошлого удара
local lastHit = 0
-- пока жив
while enemy.Parent and humanoid.Health > 0 do
-- к кому бежать
local target, distance = Nearest(root.Position)
-- есть
if target then
-- бежит к игроку
humanoid:MoveTo(target.Parent.HumanoidRootPart.Position)
-- рядом и удар готов
if distance < 4 and os.clock() - lastHit > 1 then
-- запоминаем
lastHit = os.clock()
-- урон
target:TakeDamage(TOUCH_DAMAGE)
-- конец проверки
end
-- конец проверки
end
-- думает 3 раза в секунду
task.wait(0.3)
-- конец цикла
end
-- конец функции
end)
-- конец функции
end
-- волна за волной
while true do
-- ждём игроков
repeat task.wait(1) until #Players:GetPlayers() > 0
-- следующая волна
wave += 1
-- интерфейс покажет номер
RS:SetAttribute("Wave", wave)
-- врагов всё больше
for i = 1, 2 + wave * 2 do
-- враг
Spawn()
-- не все сразу
task.wait(0.4)
-- конец цикла
end
-- ждём, пока всех убьют
repeat task.wait(1) until #folder:GetChildren() == 0
-- передышка
task.wait(4)
-- конец цикла
endГде: StarterGui → ScoreGui · LocalScript
Зачем: Волна и очки.
-- игроки
local Players = game:GetService("Players")
-- номер волны
local RS = game:GetService("ReplicatedStorage")
-- этот игрок
local player = Players.LocalPlayer
-- надпись вверху
local label = script.Parent:WaitForChild("Info")
-- постоянно
while true do
-- таблица
local stats = player:FindFirstChild("leaderstats")
-- очки
local score = stats and stats:FindFirstChild("Score")
-- текст
label.Text = "Волна " .. (RS:GetAttribute("Wave") or 0) .. " · Очки " .. (score and score.Value or 0)
-- 4 раза в секунду
task.wait(0.25)
-- конец цикла
endЗапусти Play (или Run) и убедись: