조준하기
Coddy의 Roblox 게임: 타워 디펜스 코스 레슨. 18개 중 7번째.
타워는 Range 안의 지면을 지킵니다. 각 타워는 별도의 스레드에서 자체 루프를 실행합니다. 범위 내에서 가장 가까운 살아 있는 적을 찾고, Head가 적을 향하도록 회전시킵니다.
가장 가까운 적을 찾는 것은 전형적인 루프입니다. 아무것도 찾지 못한 상태에서 시작하고, 범위를 최적 거리로 설정한 다음, 지금까지의 최적 거리보다 가까운 적이 있으면 그 적을 선택합니다.
local best, bestDistance = nil, range
for _, enemy in enemies:GetChildren() do
-- 지금까지 가장 가까운 대상보다 더 가까운가? 그렇다면 그 대상을 유지한다
end
return bestCFrame.lookAt(from, at)은 from 위치에 서서 at을 바라보는 CFrame이므로, 헤드를 움직이지 않고 회전시킵니다.
tower.Head.CFrame = CFrame.lookAt(tower.Head.Position, target.HumanoidRootPart.Position)무한히 실행되는 루프는 매번 반복할 때마다 기다려야 합니다. 그렇지 않으면 게임이 멈춥니다. 대상을 찾았는지 여부와 관계없이 0.1초를 기다립니다.
챌린지
중급nearestEnemy(position, range)를 작성합니다.HumanoidRootPart가 있고Health > 0인 살아 있는 적 중에서position에 가장 가까우며range이내에 있는 적을 찾고, 없으면 nil을 반환합니다.runTower(tower)를 작성합니다. 타워가 게임에 있는 동안, 타워의 머리에서Settings.Towers[tower.Name].Range이내에 있는 가장 가까운 적을 찾고, 머리가 적을 향하도록 돌린 다음task.wait(0.1)을 실행합니다.placeTower의 끝에서task.spawn(runTower, tower)로 실행합니다.
Play를 눌러 시작 지점 옆에 Archer를 짓고, 타워가 적을 추적하는 모습을 확인합니다. 그런 다음 Check를 누릅니다.
직접 해보기
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Settings = require(game.ReplicatedStorage.Settings)
local remotes = game.ReplicatedStorage.Remotes
local enemies = workspace.Enemies
local towers = workspace.Towers
print("The base can take " .. Settings.BaseHealth .. " hits")
-- 순서대로 정렬된 경유지들(이름은 1, 2, 3...)
local waypoints = workspace.Path.Waypoints:GetChildren()
table.sort(waypoints, function(a, b)
return tonumber(a.Name) < tonumber(b.Name)
end)
-- workspace의 속성으로 저장된 기지의 체력: 모든 클라이언트가 읽을 수 있음
workspace:SetAttribute("BaseHealth", Settings.BaseHealth)
-- 모든 플레이어는 리더보드에 Money를 받음
Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local money = Instance.new("IntValue")
money.Name = "Money"
money.Value = Settings.StartMoney
money.Parent = leaderstats
end)
-- 적이 기지에 도착함
local function damageBase(amount)
local health = math.max(0, workspace:GetAttribute("BaseHealth") - amount)
workspace:SetAttribute("BaseHealth", health)
end
-- 적을 경로를 따라 이동시킴. MoveTo는 8초가 지나면 포기하고 이를 알림
-- (MoveToFinished가 false를 반환함). 따라서 느린 적은 도착할 때까지 다시 이동 명령을 받음.
local function walkPath(enemy)
local humanoid = enemy.Humanoid
for i = 2, #waypoints do
repeat
humanoid:MoveTo(waypoints[i].Position)
until humanoid.MoveToFinished:Wait() or not enemy.Parent
if not enemy.Parent then
return
end
end
-- 적이 기지에 도착함
damageBase(Settings.Enemies[enemy.Name].Damage)
enemy:Destroy()
end
-- 입구에서 생성되어 경로를 따라 이동하는 새로운 적
local function spawnEnemy(kind)
local enemy = ServerStorage.Enemies[kind]:Clone()
-- 첫 번째 경유지 바로 위에 배치됨
enemy:PivotTo(waypoints[1].CFrame + Vector3.new(0, 5, 0))
local info = Settings.Enemies[kind]
enemy.Humanoid.MaxHealth = info.Health
enemy.Humanoid.Health = info.Health
enemy.Humanoid.WalkSpeed = info.Speed
enemy.Parent = enemies
task.spawn(walkPath, enemy)
return enemy
end
-- 발판 위에 타워를 건설함
local function placeTower(pad, kind)
local tower = ServerStorage.Towers[kind]:Clone()
tower:PivotTo(pad.CFrame + Vector3.new(0, pad.Size.Y / 2 + 1, 0))
tower.Parent = towers
end
-- 클라이언트가 발판 위에 타워를 건설해 달라고 요청함
remotes.Place.OnServerEvent:Connect(function(player, pad, kind)
placeTower(pad, kind)
end)
-- 한 웨이브: 적을 하나씩 생성한 뒤 모두 사라질 때까지 기다림
local function runWave(list)
for _, kind in list do
spawnEnemy(kind)
task.wait(Settings.SpawnGap)
end
while #enemies:GetChildren() > 0 do
task.wait(0.2)
end
end
-- 각 웨이브는 휴식 시간이 지난 뒤 시작
for i, list in Settings.Waves do
task.wait(Settings.WaveBreak)
runWave(list)
end
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.