Sebuah Bot Muncul
Pelajaran 16 dari 25 dalam kursus Game Roblox: Battlegrounds di Coddy.
Sekarang, lawan. Bot adalah model di ServerStorage.Bot dengan Humanoid, yang disalin ke atas bantalan merah, dengan angka-angkanya dari Settings dan bilah kesehatan seperti milik dummy.
Roblox memungkinkan client pemain terdekat menjalankan fisika model yang tidak di-anchor, lalu panggilan server seperti ApplyImpulse pada model itu tidak melakukan apa pun. Hantamanmu menjatuhkan bot ke belakang dari server, jadi pertahankan fisika setiap bot di sana setelah bot berada di workspace:
crate.Parent = workspace
crate:SetNetworkOwner(nil)Tantangan
SulitTempatkan bot di arena.
- Tambahkan
local bots = workspace.Bots. TulisspawnBot(): kloningServerStorage.Bot3 stud di atasworkspace.BotSpawn; atur MaxHealth dan Health keSettings.BotHealth, serta WalkSpeed keSettings.BotSpeed. - Jadikan
botssebagai induknya, lalu jalankanbot.HumanoidRootPart:SetNetworkOwner(nil). - Atur ukuran
bot.HealthBar.Back.Fillsaat HealthChanged, seperti pada dummy. PanggilspawnBot().
Tekan tombol “Main”: bot merah berdiri di atas landasan merah. Lalu tekan tombol “Periksa”.
Coba sendiri
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 lastSwing = {} -- player -> waktu terakhir mereka mengayun pedang
local combo = {} -- player -> { jumlah pukulan beruntun, waktu pukulan terakhir mengenai sasaran }
-- Animasi pedang bawaan Roblox
local slash = Instance.new("Animation")
slash.AnimationId = "rbxassetid://522635514"
local lunge = Instance.new("Animation")
lunge.AnimationId = "rbxassetid://522638767"
print("Swords deal " .. Settings.SwordDamage .. " damage")
-- Angka yang melayang sesaat di atas karakter yang terkena pukulan
local function damageNumber(character, amount)
local root = character:FindFirstChild("HumanoidRootPart")
if not root then
return
end
local tag = Instance.new("BillboardGui")
tag.Name = "Damage"
tag.Size = UDim2.fromOffset(60, 30)
tag.StudsOffset = Vector3.new(0, 4.5, 0)
tag.Adornee = root
local text = Instance.new("TextLabel")
text.Size = UDim2.fromScale(1, 1)
text.BackgroundTransparency = 1
text.TextColor3 = Color3.fromRGB(255, 220, 80)
text.TextScaled = true
text.Text = "-" .. math.round(amount)
text.Parent = tag
tag.Parent = character
Debris:AddItem(tag, 0.8)
end
-- Setiap pukulan dalam permainan diproses di sini
local function hurt(humanoid, amount)
if humanoid.Health <= 0 then
return
end
local character = humanoid.Parent
-- Menangkis mengurangi sebagian besar dampak pukulan
if character:GetAttribute("Blocking") then
amount *= Settings.BlockMultiplier
end
humanoid:TakeDamage(amount)
damageNumber(character, amount)
end
-- Efek stun membuat seseorang tidak bisa bergerak sesaat
local function stun(humanoid)
local character = humanoid.Parent
if character:GetAttribute("Stunned") then
return
end
character:SetAttribute("Stunned", true)
print(character.Name .. " is stunned")
local speed = humanoid.WalkSpeed
humanoid.WalkSpeed = 0
task.delay(Settings.StunTime, function()
if character.Parent then
humanoid.WalkSpeed = speed
character:SetAttribute("Stunned", nil)
end
end)
end
-- Satu ayunan: animasi dimainkan, lalu semua yang berada dalam kotak di depanmu terkena pukulan
local function swing(player)
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if not root or character.Humanoid.Health <= 0 then
return
end
local now = time()
if lastSwing[player] and now - lastSwing[player] < Settings.SwingCooldown then
return
end
lastSwing[player] = now
-- Tiga ayunan beruntun membentuk kombo; ayunan ketiga adalah terjangan
local c = combo[player]
if c and now - c.last <= Settings.ComboWindow then
c.count = c.count % 3 + 1
else
c = { count = 1 }
combo[player] = c
end
c.last = now
local finisher = c.count == 3
character.Humanoid.Animator:LoadAnimation(finisher and lunge or slash):Play()
-- Kotak di depanmu, tidak pernah mencakup tubuhmu sendiri
local params = OverlapParams.new()
params.FilterDescendantsInstances = { character }
local box = root.CFrame * CFrame.new(0, 0, -3)
local hit = {} -- Setiap humanoid hanya sekali per ayunan
for _, part in workspace:GetPartBoundsInBox(box, Settings.HitboxSize, params) do
local humanoid = part.Parent:FindFirstChildOfClass("Humanoid")
if humanoid and not hit[humanoid] then
hit[humanoid] = true
hurt(humanoid, Settings.ComboDamage[c.count])
if finisher then
stun(humanoid)
end
end
end
end
-- Kemampuan berdasarkan nama: apa yang dilakukan masing-masing
local abilities = {}
-- Perangkat pemain menggerakkan karakternya sendiri, jadi dash terjadi di sana
function abilities.Dash(player)
remotes.Ability:FireClient(player, "Dash")
end
-- Semua orang di sekitarmu terkena serangan dan terpental menjauh darimu
function abilities.Slam(player, character, root)
local params = OverlapParams.new()
params.FilterDescendantsInstances = { character }
local hit = {}
for _, part in workspace:GetPartBoundsInRadius(root.Position, Settings.SlamRadius, params) do
local humanoid = part.Parent:FindFirstChildOfClass("Humanoid")
local theirRoot = part.Parent:FindFirstChild("HumanoidRootPart")
if humanoid and theirRoot and not hit[humanoid] then
hit[humanoid] = true
hurt(humanoid, Settings.SlamDamage)
local away = (theirRoot.Position - root.Position) * Vector3.new(1, 0, 1)
if away.Magnitude > 0 then
away = away.Unit
end
theirRoot:ApplyImpulse((away * Settings.SlamKnockback + Vector3.new(0, 40, 0)) * theirRoot.AssemblyMass)
end
end
end
function abilities.Block(player, character)
character:SetAttribute("Blocking", true)
task.delay(Settings.BlockTime, function()
if character.Parent then
character:SetAttribute("Blocking", nil)
end
end)
end
-- client meminta kemampuan berdasarkan namanya. server memeriksa apakah kemampuan itu ada,
-- pemain masih hidup, dan waktu tunggunya sudah selesai. Waktu kemampuan siap lagi
-- disimpan sebagai atribut pemain, agar layarnya bisa menampilkannya.
remotes.Ability.OnServerEvent:Connect(function(player, name)
if typeof(name) ~= "string" or not abilities[name] then
return
end
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if not root or character.Humanoid.Health <= 0 then
return
end
local now = workspace:GetServerTimeNow()
if now < (player:GetAttribute(name .. "ReadyAt") or 0) then
return
end
player:SetAttribute(name .. "ReadyAt", now + Settings.Cooldowns[name])
abilities[name](player, character, root)
end)
-- Setiap pemain mendapat pedang setiap kali hidup
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function()
local sword = ServerStorage.Sword:Clone()
sword.Parent = player.Backpack
sword.Activated:Connect(function()
swing(player)
end)
end)
end)
-- Boneka latihan: bilah kesehatannya mengikuti kesehatannya, dan boneka yang dikalahkan
-- muncul kembali setelah beberapa saat sebagai salinan baru di tempat yang sama
local function setupDummy(dummy)
local humanoid = dummy.Humanoid
humanoid.HealthChanged:Connect(function(health)
dummy.HealthBar.Back.Fill.Size = UDim2.fromScale(health / humanoid.MaxHealth, 1)
end)
humanoid.Died:Connect(function()
local spot = dummy:GetPivot()
task.wait(0.5)
dummy:Destroy()
task.wait(Settings.DummyRespawn)
local fresh = ServerStorage.Dummy:Clone()
fresh:PivotTo(spot)
fresh.Parent = workspace
setupDummy(fresh)
end)
end
setupDummy(workspace.Dummy)
-- Pelajaran 16: A Bot Appears dimulai di sini
Semua pelajaran di Game Roblox: Battlegrounds
Latihan sendiri: Playground Roblox