Bot Durumları
Coddy'nin Roblox Oyunu: Savaş Arenası kursunda ders 16 / 20.
Botun zihni karışıyor. Oyun yapay zekâsı genellikle durumlar olarak yazılır: her tikte botun hangi durumda olduğuna karar ver, sonra o durumun gereğini yap. Bu botun beş durumu var:
Stunned: kombon onu sersemletti. Hiçbir şey yapmaz.Retreat: canıSettings.RetreatAtdeğerinin altındaysa senden kaçar.Idle: görüş alanında kimse yok.Attack: menzildesin.Chase: görüş alanındasın.
Kontrollerin sırası, botun önceliklerini belirler. Durum, botun State adlı bir özelliğidir; böylece ne düşündüğünü görebilirsin.
Görev
ZorrunBot döngüsünün içini durumlar olarak yeniden yaz. state değerini yukarıdaki sıraya göre belirle ve botun State özniteliğini ayarla; ardından Chase hedefe doğru yürür, Attack olduğu yerde durup vurur (önceden olduğu gibi), Retreat hedeften tam ters yöne doğru 12 stud yürür, diğer durumlarda ise hareketsiz durur.
Play'e, ardından Check'e bas.
Kendin dene
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 bots = workspace.Bots
local lastSwing = {} -- player -> en son ne zaman kılıç salladığı
local combo = {} -- player -> { art arda isabet sayısı, son isabetin ne zaman gerçekleştiği }
-- Roblox'un kendi kılıç animasyonları
local slash = Instance.new("Animation")
slash.AnimationId = "rbxassetid://522635514"
local lunge = Instance.new("Animation")
lunge.AnimationId = "rbxassetid://522638767"
print("Swords deal " .. Settings.SwordDamage .. " damage")
-- Vurulan kişinin üzerinde kısa süreliğine beliren bir sayı
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
-- Oyundaki her vuruş buradan geçer
local function hurt(humanoid, amount)
if humanoid.Health <= 0 then
return
end
local character = humanoid.Parent
-- blok, darbenin büyük bölümünü engeller
if character:GetAttribute("Blocking") then
amount *= Settings.BlockMultiplier
end
humanoid:TakeDamage(amount)
damageNumber(character, amount)
end
-- Sersemletme, kişiyi kısa süreliğine hareketsiz bırakır
local function stun(humanoid)
local character = humanoid.Parent
if character:GetAttribute("Stunned") then
return
end
character:SetAttribute("Stunned", true)
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
-- Bir kılıç savuruşu: önce animasyon oynar, ardından önündeki kutunun içindeki herkes darbe alır
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
-- art arda üç kılıç savuruşu bir kombo oluşturur; üçüncüsü ileri atılma hamlesidir
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()
-- önündeki kutu, asla kendi karakterin değil
local params = OverlapParams.new()
params.FilterDescendantsInstances = { character }
local box = root.CFrame * CFrame.new(0, 0, -3)
local hit = {} -- her humanoid, kılıç savuruşu başına bir kez
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
-- Yetenekler, adlarına göre: her birinin yaptığı şey
local abilities = {}
function abilities.Dash(player, character, root)
root.AssemblyLinearVelocity = root.CFrame.LookVector * Settings.DashSpeed + Vector3.new(0, 15, 0)
end
-- Etrafındaki herkes darbe alır ve senden uzağa savrulur
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
-- İstemci, bir yeteneği adıyla kullanmak ister. Sunucu şunları kontrol eder: geçerli bir
-- yetenek, hayatta olan bir oyuncu ve dolmuş bir bekleme süresi. Yeteneğin yeniden ne zaman hazır olacağı
-- oyuncunun bir özniteliğidir; böylece oyuncunun ekranında gösterilebilir.
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)
-- Her oyuncunun liderlik tablosunda Kills değeri olur ve her yeniden doğuşunda bir kılıç alır
Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local kills = Instance.new("IntValue")
kills.Name = "Kills"
kills.Parent = leaderstats
player.CharacterAdded:Connect(function()
local sword = ServerStorage.Sword:Clone()
sword.Parent = player.Backpack
sword.Activated:Connect(function()
swing(player)
end)
end)
end)
-- Antrenman kuklası: can çubuğu can miktarına göre değişir ve yenilen
-- kukla kısa bir süre sonra aynı yerde yeni bir kopya olarak geri gelir
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)
-- Bir botun görebildiği, hayatta olan en yakın oyuncu karakteri ve ona olan uzaklığı
local function nearestCharacter(position)
local best, bestDistance = nil, Settings.BotSight
for _, player in Players:GetPlayers() do
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if root and character.Humanoid.Health > 0 then
local distance = (root.Position - position).Magnitude
if distance < bestDistance then
best, bestDistance = character, distance
end
end
end
return best, bestDistance
end
-- Bir botun zihni: her çeyrek saniyede bir etrafına bakar ve karar verir
local function runBot(bot)
local humanoid = bot.Humanoid
local root = bot.HumanoidRootPart
local lastAttack = 0
while bot.Parent and humanoid.Health > 0 do
local target, distance = nearestCharacter(root.Position)
if target and distance <= Settings.BotRange then
-- yeterince yakın: dur ve her BotAttackCooldown süresinde bir vur
humanoid:MoveTo(root.Position)
if time() - lastAttack >= Settings.BotAttackCooldown then
lastAttack = time()
humanoid.Animator:LoadAnimation(slash):Play()
hurt(target.Humanoid, Settings.BotDamage)
end
elseif target then
humanoid:MoveTo(target.HumanoidRootPart.Position)
else
humanoid:MoveTo(root.Position)
end
task.wait(0.25)
end
end
-- Kırmızı platformda, değerleri ve can çubuğuyla yeni bir bot
local function spawnBot()
local bot = ServerStorage.Bot:Clone()
bot:PivotTo(workspace.BotSpawn.CFrame + Vector3.new(0, 3, 0))
bot.Humanoid.MaxHealth = Settings.BotHealth
bot.Humanoid.Health = Settings.BotHealth
bot.Humanoid.WalkSpeed = Settings.BotSpeed
bot.Parent = bots
-- botun fizik işlemlerini sunucuda tut ki Slam yeteneğinin savurma etkisi onu hareket ettirsin
bot.HumanoidRootPart:SetNetworkOwner(nil)
bot.Humanoid.HealthChanged:Connect(function(health)
bot.HealthBar.Back.Fill.Size = UDim2.fromScale(health / bot.Humanoid.MaxHealth, 1)
end)
task.spawn(runBot, bot)
end
spawnBot()
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.