Étourdissement
Leçon 12 sur 20 du cours Jeu Roblox : Arènes de combat de Coddy.
La charge d’un combo étourdit : sa cible reste figée pendant Settings.StunTime. Un Humanoid avec une WalkSpeed de 0 ne peut pas marcher ; l’étourdissement mémorise sa vitesse et la lui rend.
Un attribut Stunned marque la cible étourdie. Les bots du chapitre 4 le lisent pour arrêter d’attaquer, et il empêche un deuxième étourdissement d’enregistrer 0 comme vitesse à rétablir :
if character:GetAttribute("Stunned") then
return
endDéfi
MoyenÉcris stun(humanoid) au-dessus de swing : retourne si son personnage est déjà Stunned ; sinon, marque-le, conserve sa WalkSpeed, définis-la sur 0, puis, après Settings.StunTime, rétablis la vitesse et efface la marque (si le personnage est toujours là). Étourdis la cible de la troisième frappe du combo.
Appuie sur Play, puis sur Check.
Essayez vous-même
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Settings = require(game.ReplicatedStorage.Settings)
local remotes = game.ReplicatedStorage.Remotes
local lastSwing = {} -- player -> moment de son dernier coup d'épée
local combo = {} -- player -> { coups consécutifs, moment où le dernier a touché }
-- Les animations d'épée propres à 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")
-- Tous les coups portés dans le jeu passent par ici
local function hurt(humanoid, amount)
if humanoid.Health <= 0 then
return
end
local character = humanoid.Parent
-- une parade absorbe la majeure partie du coup
if character:GetAttribute("Blocking") then
amount *= Settings.BlockMultiplier
end
humanoid:TakeDamage(amount)
end
-- Un coup d'épée : l'animation, puis tous ceux qui se trouvent dans la zone devant vous sont touchés
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
-- trois coups d'épée consécutifs forment un combo ; le troisième est une estocade
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()
-- la zone devant vous, jamais votre propre corps
local params = OverlapParams.new()
params.FilterDescendantsInstances = { character }
local box = root.CFrame * CFrame.new(0, 0, -3)
local hit = {} -- chaque humanoid une seule fois par coup d'épée
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])
end
end
end
-- Les capacités, par nom : ce que chacune fait
local abilities = {}
function abilities.Dash(player, character, root)
root.AssemblyLinearVelocity = root.CFrame.LookVector * Settings.DashSpeed + Vector3.new(0, 15, 0)
end
-- tous ceux qui vous entourent sont touchés et projetés loin de vous
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
-- Le client demande une capacité par son nom. Le serveur vérifie qu'il s'agit d'une véritable
-- capacité, un joueur en vie et un délai de récupération écoulé. Le moment où elle sera de nouveau prête
-- est un attribut du joueur, afin que son écran puisse l’afficher.
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)
-- Chaque joueur obtient Kills dans le classement et une épée à chaque réapparition
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)
-- Le mannequin d’entraînement : sa barre de vie suit ses points de vie, et un mannequin vaincu
-- réapparaît après un instant, sous forme d’une nouvelle copie au même endroit
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)
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.