Menu
CoddyTech

Kombination

Lektion 11 von 20 im Kurs Roblox-Spiel: Schlachtfelder von Coddy.

Drei Schläge hintereinander, jeweils innerhalb von Settings.ComboWindow nach dem vorherigen, bilden eine Kombo: 10, 10 und dann ein Ausfallschritt für 25 (Settings.ComboDamage). Eine Pause setzt die Reihe zurück.

Der Server speichert für jeden Spieler, wie viele Schläge in der Reihe sind und wann der letzte erfolgt ist:

if c and now - c.last <= Settings.ComboWindow then
	c.count = c.count % 3 + 1
else
	c = { count = 1 }
	combo[player] = c
end

c.count % 3 + 1 ergibt 1, 2, 3, 1, 2, 3: Nach dem Ausfallschritt beginnt eine neue Kombo. Der dritte Treffer spielt Roblox' Ausfallschritt-Animation ab, rbxassetid://522638767.

challenge icon

Aufgabe

Mittel
  1. Füge local combo = {} und die Animation lunge (ID rbxassetid://522638767) hinzu.
  2. Zähle in swing nach der Abklingzeitprüfung den Schlag: Liegt der letzte Schlag höchstens Settings.ComboWindow zurück, folgt der nächste Zählerstand (1, 2, 3, dann wieder 1); andernfalls beginnt eine neue Kombo bei 1.
  3. Spiele beim dritten Treffer den Ausfallschritt ab (ansonsten den Schwerthieb) und füge mit Settings.ComboDamage[c.count] Schaden zu.

Drücke Play und schlage im Rhythmus zu. Dann Check.

Probier es selbst

local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Settings = require(game.ReplicatedStorage.Settings)

local remotes = game.ReplicatedStorage.Remotes
local lastSwing = {} -- player -> Zeitpunkt des letzten Schwertschwungs

-- Roblox' eigene Schwertanimationen
local slash = Instance.new("Animation")
slash.AnimationId = "rbxassetid://522635514"

print("Swords deal " .. Settings.SwordDamage .. " damage")

-- Jeder Treffer im Spiel läuft hierüber
local function hurt(humanoid, amount)
	if humanoid.Health <= 0 then
		return
	end
	local character = humanoid.Parent
	-- Ein Block fängt den Großteil des Treffers ab
	if character:GetAttribute("Blocking") then
		amount *= Settings.BlockMultiplier
	end
	humanoid:TakeDamage(amount)
end

-- Ein Schwertschwung: die Animation, dann wird jeder im Bereich vor dir getroffen
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
	character.Humanoid.Animator:LoadAnimation(slash):Play()
	-- der Bereich vor dir, niemals dein eigener Körper
	local params = OverlapParams.new()
	params.FilterDescendantsInstances = { character }
	local box = root.CFrame * CFrame.new(0, 0, -3)
	local hit = {} -- jeder humanoid nur einmal pro Schwertschwung
	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.SwordDamage)
		end
	end
end

-- Die Fähigkeiten nach Namen: was jede einzelne bewirkt
local abilities = {}

function abilities.Dash(player, character, root)
	root.AssemblyLinearVelocity = root.CFrame.LookVector * Settings.DashSpeed + Vector3.new(0, 15, 0)
end

-- Alle um dich herum werden getroffen und von dir weggeschleudert
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

-- Der Client fordert eine Fähigkeit anhand ihres Namens an. Der Server prüft: eine gültige
-- Fähigkeit, einen lebenden Spieler und ob ihre Abklingzeit abgelaufen ist. Wann sie wieder bereit ist,
-- ist als Attribut des Spielers gespeichert, damit es auf seinem Bildschirm angezeigt werden kann.
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)

-- Jeder Spieler erhält Kills auf der Bestenliste und bei jedem neuen Leben ein Schwert
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)

-- Die Trainingspuppe: Ihre Lebensanzeige zeigt ihre Gesundheit an, und eine besiegte
-- Puppe erscheint nach kurzer Zeit als neue Kopie am selben Ort wieder
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 iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Roblox-Spiel: Schlachtfelder