-
What do you want to achieve? Keep it simple and clear!
I want to achieve a smooth knockback for both dummies and players for later use in an anime game. -
What is the issue?
The issue is that YouTube videos and old forum topics use either BodyVelocity (which is deprecated now) or showcase excessive/crazy knockback.
My current knockback implemented with AssemblyLinearVelocity is not smooth at all (on both client and server). I already tried ApplyImpulse, but I feel there are too many parameters to manage, like mass. In an anime game, this is a bit excessive because I just want everybody to get knocked back the exact same distance. Also, sometimes the character would just fall down on the ground before getting back up, which is extremely annoying (even though I don’t encounter this specific issue anymore). -
What solutions have you tried so far?
First, I tried this script where I fire a RemoteEvent for players, and handle dummies on the server using Heartbeat to manually set their velocity and calculate the distance.
local look = attackerRoot.CFrame.LookVector
local dir = Vector3.new(look.X, 0, look.Z)
if dir.Magnitude < 0.01 then return end
dir = dir.Unit
local speed = KNOCKBACK_STUDS / KNOCKBACK_TIME
local targetChar = targetHumanoid.Parent :: Model
local targetPlayer = Players:GetPlayerFromCharacter(targetChar)
if targetPlayer then
KnockbackRemote:FireClient(targetPlayer, {
dir = dir,
speed = speed,
up = KNOCKBACK_UP,
distance = KNOCKBACK_STUDS,
duration = KNOCKBACK_TIME,
})
else
targetRoot:SetNetworkOwner(nil)
local startFlat = Vector3.new(targetRoot.Position.X, 0, targetRoot.Position.Z)
local elapsed = 0
local upApplied = false
local conn: RBXScriptConnection
conn = RunService.Heartbeat:Connect(function(dt)
elapsed += dt
local p = Vector3.new(targetRoot.Position.X, 0, targetRoot.Position.Z)
local travelled = (p - startFlat).Magnitude
if travelled >= KNOCKBACK_STUDS or elapsed >= KNOCKBACK_TIME or targetRoot.Parent == nil then
conn:Disconnect()
if targetHumanoid.Parent and targetHumanoid.Health > 0 then
--targetHumanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
end
return
end
--targetHumanoid:ChangeState(Enum.HumanoidStateType.Physics)
local v = targetRoot.AssemblyLinearVelocity
local vy = v.Y
if not upApplied then
vy = KNOCKBACK_UP
upApplied = true
end
targetRoot.AssemblyLinearVelocity = Vector3.new(dir.X * speed * 1.1, vy, dir.Z * speed * 1.1)
end)
end
Even with the network owner of the dummy set to nil, manually setting AssemblyLinearVelocity in Heartbeat is super stuttery at the start.
I also tried setting PlatformStanding to true on the humanoid during the knockback, but it feels too excessive and just makes the dummy fall over immediately. I tried changing states using Humanoid:ChangeState(Enum.HumanoidStateType.Physics) instead, but it didn’t really change much and the overall applied effect was still worse than PlatformStanding.
After that, I tried switching to the new LinearVelocity constraint with this script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")
local knockbackEvent = ReplicatedStorage:WaitForChild("KnockbackEvent")
local dummy = workspace:WaitForChild("Dummy")
local dummyHRP = dummy:WaitForChild("HumanoidRootPart")
knockbackEvent.OnServerEvent:Connect(function(player)
if dummyHRP:FindFirstChild("KnockbackAttachment") then return end
local playerHRP = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if not playerHRP then return end
local direction = (dummyHRP.Position - playerHRP.Position).Unit
local power = 80
local attachment = Instance.new("Attachment")
attachment.Name = "KnockbackAttachment"
attachment.Parent = dummyHRP
local lv = Instance.new("LinearVelocity")
lv.Name = "KnockbackVelocity"
lv.ForceLimitsEnabled = true
lv.ForceLimitMode = Enum.ForceLimitMode.PerAxis
lv.MaxAxesForce = Vector3.new(math.huge, 0, math.huge)
lv.VectorVelocity = Vector3.new(direction.X, 0, direction.Z).Unit * power
lv.Attachment0 = attachment
lv.Parent = dummyHRP
Debris:AddItem(lv, 0.25)
Debris:AddItem(attachment, 0.25)
end)
This actually works and looks incredibly smooth! But there is a huge catch: whenever the dummy collides with a wall during the knockback, it either gets violently launched into the air (I assume the physics solver is trying to resolve the collision and panics), or it doesn’t fly up but instead starts glitching and moving uncontrollably in all directions.
How can I keep this smooth LinearVelocity knockback but prevent the dummy from flying into orbit or glitching whenever it hits a wall? Any help is highly appreciated!
