Menu
CoddyTech

Kovalayan Bir Bot

Coddy'nin Roblox Oyunu: Savaş Arenası kursunda ders 14 / 20.

Şimdi bir rakip. Bot, ServerStorage.Bot içinde bulunan ve bir Humanoid içeren, kırmızı platformun üzerine kopyalanmış bir modeldir. Zihni kendi iş parçacığında çalışan bir döngüdür: her çeyrek saniyede bir, görebildiği en yakın yaşayan oyuncuyu (Settings.BotSight menzili içinde) bulur ve ona doğru yürür: Humanoid:MoveTo.

while bot.Parent and humanoid.Health > 0 do
	local target = nearestCharacter(root.Position)
	if target then
		humanoid:MoveTo(target.HumanoidRootPart.Position)
	end
	task.wait(0.25)
end

En yakını bulmak klasik bir döngüdür: başlangıçta hedef yoktur ve en iyi mesafe olarak görüş menzili kullanılır; ardından daha yakında olan her oyuncu seçilir.

Roblox, yakındaki bir oyuncunun istemcisinin sabitlenmemiş bir modelin fiziğini çalıştırmasına izin verir; bu durumda model üzerinde sunucudan yapılan ApplyImpulse gibi bir çağrı hiçbir işe yaramaz. Darben sunucudan botları geri savurduğu için her botun fiziğini orada tut: bot çalışma alanına girdikten sonra bot.HumanoidRootPart:SetNetworkOwner(nil) çağır.

challenge icon

Görev

Zor
  1. Ekle: local bots = workspace.Bots.
  2. nearestCharacter(position) işlevini yaz: Settings.BotSight mesafesindeki en yakın yaşayan oyuncunun karakterini ve mesafesini (veya nil) döndürsün.
  3. runBot(bot) işlevini yaz: bot hayatta olduğu sürece en yakın karaktere doğru yürüsün veya hareketsiz dursun ve 0.25 saniye beklesin.
  4. spawnBot() işlevini yaz: Bot'u workspace.BotSpawn konumunun 3 stud üzerinde klonlasın, MaxHealth, Health ve WalkSpeed değerlerini Settings'ten ayarlasın, bots içine yerleştirsin, fiziğinin sunucuda çalışmasını sağlasın, sağlık çubuğunu sağlığına göre güncellesin ve runBot işlevini başlatsın. Bir tane oluştur.

Play'e bas ve kırmızı pede doğru yürü. 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 lastSwing = {} -- player -> en son ne zaman kılıç savurduğu
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")

-- İsabet alan kişinin üzerinde kısa bir süre beliren 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 isabet buradan geçer
local function hurt(humanoid, amount)
	if humanoid.Health <= 0 then
		return
	end
	local character = humanoid.Parent
	-- blok, hasarın büyük kısmını engeller
	if character:GetAttribute("Blocking") then
		amount *= Settings.BlockMultiplier
	end
	humanoid:TakeDamage(amount)
	damageNumber(character, amount)
end

-- Sersemletme, birini 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

-- Kılıç savurma: animasyon oynar, ardından önündeki alanın içindeki herkes isabet 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ıç savurma bir kombo oluşturur; üçüncüsü bir 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 alan; kendi vücudun asla dahil değil
	local params = OverlapParams.new()
	params.FilterDescendantsInstances = { character }
	local box = root.CFrame * CFrame.new(0, 0, -3)
	local hit = {} -- her humanoid, her kılıç savurmada yalnızca 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ş bekleme süresi. Yeteneğin yeniden ne zaman hazır olacağı
-- oyuncunun bir özelliğidir; böylece ekranda 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ı: sağlık çubuğu sağlık durumunu yansıtır 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)
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Roblox Oyunu: Savaş Arenası bölümündeki tüm dersler