Hello, I am currently creating a combat system and well, it’s finally time to do the knockback however i’m running into issue when it come to making it responsive and smooth.
So, from the server I am firing all clients the knockback strength, which character should be knockback and the player who initiated the knockback.
So that mean the knockback calculation is done from the client.
Here what it looks :
On the right side (The player who get knockbacked) it’s really smooth because obviously, due to network ownership they are calculating their own physics. However on the attacker side (player who initiated the knockback) it look laggy.
Even tho I am firing all clients, I tried setting the network owner to the server but it was a really bad idea because it looked even more laggy, I tried doing knockback on the server but it still look laggy, I know this issue has been around here for a long time.
I also tried creating a welded part that is parented to each character rootpart then setting the network owner to the server and the knockback is applied to that part, but same result. So I came to the conclusion that this was useless since it’s calculating the whole character moving and not a single part.
But games like battlegrounds are able to achieve responsive and smooth knockback, thank you if you are able to help me.
local function Knockback(CharToKB, AttackerChar, KnockbackForce)
local VictimRootPart = CharToKB:FindFirstChild("HumanoidRootPart") or CharToKB:WaitForChild("HumanoidRootPart", 5) :: BasePart
local AttackerRootPart = AttackerChar:FindFirstChild("HumanoidRootPart") or AttackerChar:WaitForChild("HumanoidRootPart", 5)
if not AttackerRootPart or not VictimRootPart then
return
end
VictimRootPart:ApplyImpulse(AttackerRootPart.CFrame.LookVector * KnockbackForce * VictimRootPart.AssemblyMass)
end
Server side :
function Character.Knockback(self : Object, AttackerCharObj, KnockbackStrength)
local AttackerRootPart = AttackerCharObj.RootPart :: BasePart
local AttackerHumanoid = AttackerCharObj.Humanoid
if not KnockbackStrength or not AttackerRootPart or AttackerHumanoid.Health <= 0 or self.Humanoid.Health <= 0 then
return
end
-- define if it's a npc or not
local AttackerChar = AttackerCharObj.Character
local VictimChar = self.Character
if not AttackerChar or not VictimChar then
return
end
local Attacker = Players:GetPlayerFromCharacter(AttackerChar)
local Victim = Players:GetPlayerFromCharacter(VictimChar)
-- local PlayerToFire = Victim
if not Attacker then
-- incase the attacker is a NPC (example : Attacking dummies or smth)
AttackerCharObj.RootPart:SetNetworkOwner(Victim)
end
if not Victim then
-- make it so the NPC physics look smooth on the attacker client
-- Client will calculate all physics related to the NPC
-- Problem is that during the knockback, client can exploit the NPC
--PlayerToFire = Attacker
if self.Threads.Network then
task.cancel(self.Threads.Network)
self.Threads.Network = nil
end
self.RootPart:SetNetworkOwner(Attacker)
self.Threads.Network = task.delay(KnockbackStrength * 0.015, function()
-- revert the networkship back to default
self.RootPart:SetNetworkOwnershipAuto()
end)
end
--[[
print(PlayerToFire, AttackerChar, KnockbackStrength)
KnockbackRemote:FireClient(
PlayerToFire,
-- If it's a NPC we fire the attacker instead
-- Firing the player so it apply knockback on itself if it's not a NPC
VictimChar,
AttackerChar, -- Player who attacked
KnockbackStrength
)
]]
KnockbackRemote:FireAllClients(
-- If it's a NPC we fire the attacker instead
-- Firing the player so it apply knockback on itself if it's not a NPC
VictimChar,
AttackerChar, -- Player who attacked
KnockbackStrength
)
end
Drop this in a part with touch and run into it. Possibly you could adapt this to work for you.
local db=true
script.Parent.Touched:Connect(function(hit)
if db and hit.Parent:FindFirstChild("Humanoid") then db = false
local character = hit.Parent
local torso = character:FindFirstChild("LowerTorso") or
character:FindFirstChild("Torso")
if(torso)then
local bv = Instance.new("BodyVelocity")
bv.Parent = torso bv.MaxForce = Vector3.one * 100000
bv.Velocity = character.Head.CFrame.LookVector *
-80 + character.Head.CFrame.UpVector * 80
wait(0.033) bv:Destroy()
end task.wait(0.33)
db = true
end
end)
Not sure if this will work for you… but it will sure kick you back, with a nice little arc.
local function Knockback(CharToKB, AttackerChar, KnockbackForce)
local VictimRootPart = CharToKB:FindFirstChild("HumanoidRootPart") or CharToKB:WaitForChild("HumanoidRootPart", 5) :: BasePart
local AttackerRootPart = AttackerChar:FindFirstChild("HumanoidRootPart") or AttackerChar:WaitForChild("HumanoidRootPart", 5)
if not AttackerRootPart or not VictimRootPart then
return
end
local direction = AttackerRootPart.CFrame.LookVector
local vectorForce = Instance.new("VectorForce")
vectorForce.Force = direction * KnockbackForce * VictimRootPart.AssemblyMass
vectorForce.RelativeTo = Enum.ActuatorRelativeTo.World
vectorForce.ApplyAtCenterOfMass = true
vectorForce.Parent = VictimRootPart
game:GetService("Debris"):AddItem(vectorForce, 0.2)
end