Panel de torre
Lección 13 de 22 del curso Juego de Roblox: Defensa de torres de Coddy.
Una torre se vuelve más fuerte con los niveles. El nivel es un atributo del modelo de la torre, Level, que empieza en 1. Cada mejora cuesta una parte del precio de la torre, Settings.UpgradeCost, multiplicada por el nivel actual, y math.floor la redondea hacia abajo. La próxima mejora de una torre Frost de nivel 2 cuesta:
math.floor(90 * 0.75 * 2) --> 135Al hacer clic en una torre, se abre el Panel del HUD con su nombre, nivel y precio. El clic alcanza una de las partes de la torre, así que target:FindFirstAncestorOfClass("Model") encuentra la torre a la que pertenece.
Desafío
IntermedioHaz clic en una torre para abrir su panel.
- En
placeTower, establece el atributoLevelde la torre en 1. - En
DefenseClient, escribeshowPanel(): para la torrechosen, los textosArcher level 1enhud.Panel.TitleyUpgrade $45enhud.Panel.Upgrade; muestra el panel. - En
Button1Down, un clic en una torre deworkspace.Towersla selecciona.
Pulsa «Jugar» y haz clic en un Archer que hayas construido: se abre su panel. Después, «Comprobar».
Pruébalo tú mismo
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Debris = game:GetService("Debris")
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")
-- Los puntos de ruta, en orden (se llaman 1, 2, 3...)
local waypoints = workspace.Path.Waypoints:GetChildren()
table.sort(waypoints, function(a, b)
return tonumber(a.Name) < tonumber(b.Name)
end)
-- La salud de la base, como atributo de workspace: todos los clientes pueden leerla
workspace:SetAttribute("BaseHealth", Settings.BaseHealth)
-- Todos los jugadores reciben Money en la tabla de clasificación
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)
-- Un enemigo llegó a la base
local function damageBase(amount)
local health = math.max(0, workspace:GetAttribute("BaseHealth") - amount)
workspace:SetAttribute("BaseHealth", health)
print("Base: " .. health)
end
-- Haz que un enemigo recorra el camino. MoveTo desiste después de 8 segundos y lo indica
-- (MoveToFinished con false), así que se vuelve a enviar al enemigo lento hasta que llega.
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
-- llegó a la base
damageBase(Settings.Enemies[enemy.Name].Damage)
enemy:Destroy()
end
-- Un nuevo enemigo en la entrada, recorriendo el camino
local function spawnEnemy(kind)
local enemy = ServerStorage.Enemies[kind]:Clone()
-- colocado justo encima del primer punto de ruta
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
enemy.Humanoid.Died:Connect(function()
-- todos los jugadores obtienen la recompensa
for _, player in Players:GetPlayers() do
player.leaderstats.Money.Value += info.Reward
end
enemy:Destroy()
end)
task.spawn(walkPath, enemy)
return enemy
end
-- El enemigo vivo más cercano dentro del alcance de un punto, o nil
local function nearestEnemy(position, range)
local best, bestDistance = nil, range
for _, enemy in enemies:GetChildren() do
local root = enemy:FindFirstChild("HumanoidRootPart")
if root and enemy.Humanoid.Health > 0 then
local distance = (root.Position - position).Magnitude
if distance <= bestDistance then
best, bestDistance = enemy, distance
end
end
end
return best
end
-- Un destello de luz desde una torre hasta su objetivo
local function beam(from, to)
local ray = Instance.new("Part")
ray.Anchored = true
ray.CanCollide = false
ray.CanTouch = false
ray.Material = Enum.Material.Neon
ray.Color = Color3.fromRGB(255, 240, 150)
ray.Size = Vector3.new(0.2, 0.2, (to - from).Magnitude)
ray.CFrame = CFrame.lookAt((from + to) / 2, to)
ray.Parent = workspace
Debris:AddItem(ray, 0.1)
end
-- Un disparo: daña al objetivo
local function shoot(tower, target, info)
local damage = info.Damage
local at = target.HumanoidRootPart.Position
target.Humanoid:TakeDamage(damage)
beam(tower.Head.Position, at)
end
-- La rutina de una torre: apunta al enemigo más cercano dentro de su alcance, dispara y espera a que termine su tiempo de recarga
local function runTower(tower)
local info = Settings.Towers[tower.Name]
while tower.Parent do
local target = nearestEnemy(tower.Head.Position, info.Range)
if target then
tower.Head.CFrame = CFrame.lookAt(tower.Head.Position, target.HumanoidRootPart.Position)
shoot(tower, target, info)
task.wait(info.Cooldown)
else
task.wait(0.1)
end
end
end
-- Construye una torre en una plataforma
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
pad:SetAttribute("Used", true)
task.spawn(runTower, tower)
end
-- El cliente solicita colocar una torre en una plataforma. Comprueba todo: que la plataforma exista y esté libre,
-- que la torre exista y que haya dinero para pagarla.
remotes.Place.OnServerEvent:Connect(function(player, pad, kind)
if typeof(pad) ~= "Instance" or pad.Parent ~= workspace.Pads or pad:GetAttribute("Used") then
return
end
local info = typeof(kind) == "string" and Settings.Towers[kind]
if not info then
return
end
local money = player.leaderstats.Money
if money.Value < info.Price then
return
end
money.Value -= info.Price
placeTower(pad, kind)
end)
-- Una oleada: aparecen sus enemigos uno a uno; luego espera hasta que desaparezcan todos
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
-- Las oleadas, cada una después de una pausa
for i, list in Settings.Waves do
task.wait(Settings.WaveBreak)
runWave(list)
end
Todas las lecciones de Juego de Roblox: Defensa de torres
Practica por tu cuenta: Playground de Roblox