BodyVelocity not destroying

I’ve been working on a knockback system for a game and whenever I attempt destroy a body velocity, the output always says “BV Found and destroyed” while the BodyVelocity instance remains and is only destroyed later by DebrisService. Is this a Roblox bug, or an error with my script?

local function removeBV(root)
	if not root or not root.GetChildren or type(root.GetChildren) ~= "function" then
		warn("Invalid root object provided")
		return
	end

	local children = root:GetChildren()
	if not children or #children == 0 then
		warn("No children found under the root object")
		return
	end

	for _, child in ipairs(children) do
		if child:IsA("BodyVelocity") then
			local success, errorMsg = pcall(function()
				child.Parent = nil
				print("BV Found and destroyed")
			end)

			if not success then
				warn("Failed to destroy BodyVelocity: " .. errorMsg)
			end
		end
	end
end

Where did you place the bodyvelocity before being destroyed?

use : Destroy() also why do you need pcall functions

The function really doesn’t need to be this advanced. You don’t need to use pcalls for something like this. Try and remove that kind of stuff from the function, and rescript it as needed from there.

This needs to be changed to child:Destroy().

You aren’t supposed to use BodyVelocity… as it’s become deprecated. Instead, swap to LinearVelocity. It’s essentially the same thing, with property name changes.

Also, why do you use a pcall function here?

I used :Destroy() and it didn’t work either, so I tried that

How would I convert it to linearvelocity?

Take it out of a pcall function, and try it again… if it doesn’t work… there is a script that’s keeping the body velocity in the player.

The best way to do this, is just by messing around with LinearVelocity separately. After a little bit of tweaking, you’ll understand what’s been changed, and how to use it correctly. As I said earlier, it’s essentially BodyVelocity… with minor changes/tweaks.

I’d have to see the script you’re using that changes the properties of the BodyVelocity to update it properly.

I took out the pcall function but the same issue remains, still outputting the same thing

1 Like

What I’m running:


After Running:

Your code works fine. Something else must not be.

1 Like

What kind of code would be preventing it from being destroyed?

The code that put it there in the first place could do it again. Code could be saying if not root:FindFirstChild(“BodyVelocity”) then -create bv- end

1 Like

This is the code that creates the bodyvelocity. I run the function alone whenever I queue a velocity to be created so that pre-existing BV’s get removed.

local function airComboBV(root)
	removeBV(root)
	
	local bodyVelocity = Instance.new("BodyVelocity")
	bodyVelocity.Name = "AirComboBV"
	bodyVelocity.Velocity = Vector3.new(0, 0, 0)
	bodyVelocity.MaxForce = Vector3.new(0, math.huge, 0)

	bodyVelocity.Parent = root

	game.Debris:AddItem(bodyVelocity,0.5)
end

looks like your function will remove existing BV’s and then create one that lasts for 0.5 seconds.

I call the removeBV() function when I want to manually remove body velocity, usually when I create custom body velocities. The function I provided is working as intended

None of the code you have provided is causing your problem as far as I can tell. You gotta give us something more than that.

This is the whole script for the code I’m using

-- ServerScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local combat = require(game.ReplicatedStorage.Modules.Combat.CombatModule)
local util = require(game.ReplicatedStorage.Modules.Util)

local AttackEvent = game.ReplicatedStorage.Events.M1

local Animations = game.ReplicatedStorage.Animations
local Hitboxes = game.ServerStorage.Hitboxes
local BaseInputAnimations = Animations.BaseInputs

local maxAttacks = 5
local attackCooldown = 0.4
local resetCooldown = 1.2
local lastAttackTime = {}
local attackCount = {}
local inAirCombo = {}
local cooldown = {}

local function adjustJumpPower(player)
	local character = player.Character
	if character then
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		if humanoid then
			humanoid.JumpPower = attackCount[player] and attackCount[player] > 0 and 0 or 50
		end
	end
end

local function addAirCombo(character)
	local airCombo = Instance.new("BoolValue")
	airCombo.Name = "AirCombo"
	airCombo.Parent = character
	game.Debris:AddItem(airCombo,1.5)
end

local function checkAirCombo(character)
	local airCombo = character:FindFirstChild("AirCombo")
	if airCombo and airCombo:IsA("BoolValue") then
		print('true')
		return true
	else
		print('false')
		return false
	end
end

local function removeBV(root)
	if not root or not root.GetChildren or type(root.GetChildren) ~= "function" then
		warn("Invalid root object provided")
		return
	end

	local children = root:GetChildren()
	if not children or #children == 0 then
		warn("No children found under the root object")
		return
	end

	for _, child in ipairs(children) do
		if child:IsA("BodyVelocity") then
			child:Destroy()
			print("BV Found and destroyed")
		end
	end
end

local function airComboBV(root)
	removeBV(root)
	
	local bodyVelocity = Instance.new("BodyVelocity")
	bodyVelocity.Name = "AirComboBV"
	bodyVelocity.Velocity = Vector3.new(0, 0, 0)
	bodyVelocity.MaxForce = Vector3.new(0, math.huge, 0)

	bodyVelocity.Parent = root

	game.Debris:AddItem(bodyVelocity,0.5)
end

local function characterIsOnFloor(character, root)
	if character then
		local rayStart = root.Position
		local rayDirection = Vector3.new(0, -1, 0)
		local rayLength = 3.5
		
		local raycastParams = RaycastParams.new()
		raycastParams.FilterType = Enum.RaycastFilterType.Exclude
		raycastParams.FilterDescendantsInstances = {character,workspace.Combat,workspace.Living}

		local raycastResult = workspace:Raycast(rayStart, rayDirection * rayLength, raycastParams)

		if raycastResult then
			if raycastResult.Instance ~= nil then
				print("Touching ground")
				return true
			else
				print("Not touching ground")
			end
		end
	end
	
	return false
end

local function downslamBV(character,e_Root)
	local humanoid = character:FindFirstChildOfClass("Humanoid")
	local rootPart = character:FindFirstChild("HumanoidRootPart")

	coroutine.resume(coroutine.create(function()
		if humanoid and rootPart then
			local angle = math.rad(40)

			local direction = (e_Root.CFrame.lookVector * Vector3.new(1, 0, 1)).unit

			direction = Vector3.new(direction.x, -math.tan(angle), direction.z)

			local velocityMagnitude = 50
			local velocity = direction * velocityMagnitude

			local bodyVelocity = Instance.new("BodyVelocity")
			bodyVelocity.Velocity = velocity
			bodyVelocity.MaxForce = Vector3.new(30000, 30000, 30000)

			bodyVelocity.Parent = rootPart
			
			local start = humanoid.Animator:LoadAnimation(Animations.BaseInputs.DownslamEStart)
			local loop = humanoid.Animator:LoadAnimation(Animations.BaseInputs.DownslamELoop)
			local finish = humanoid.Animator:LoadAnimation(Animations.BaseInputs.DownslamEFinish)
			
			local downslamFinished = false
			
			coroutine.resume(coroutine.create(function()
				start:Play()
				
				task.wait(0.333)
				
				if downslamFinished == false then
					loop:Play()
				end
			end))

			local function checkGround()
				local connection
				connection = game:GetService("RunService").Heartbeat:Connect(function()
					if characterIsOnFloor(character, rootPart) then
						downslamFinished = true
						
						if start.IsPlaying then
							start:Stop()
						end 
						
						if loop.IsPlaying then
							loop:Stop()
						end
						
						finish:Play()
						
						bodyVelocity.Parent = nil
						connection:Disconnect()
					end
				end)
			end

			checkGround()
		end
	end))
end

local function hitbox(player, root, uptilt, final, aerial)
	local entities_hit = {}

	local hitbox = Hitboxes:FindFirstChild("LightHitbox"):Clone()
	if not hitbox or not hitbox:IsA("BasePart") then
		warn("Invalid hitbox found.")
		return
	end

	hitbox.Parent = workspace.Combat.CombatHitboxes
	hitbox.CFrame = root.CFrame * CFrame.new(0, 0, -3.5)

	local region = Region3.new(hitbox.Position - hitbox.Size / 2, hitbox.Position + hitbox.Size / 2)
	local parts = workspace:FindPartsInRegion3(region, nil, math.huge)

	game.Debris:AddItem(hitbox, 0.3)

	for _, part in pairs(parts) do
		if part:IsDescendantOf(workspace.Combat.EntityHitboxes) then
			local e_character = part:FindFirstChild("Owner").Value
			local e_Hum = e_character:FindFirstChild("Humanoid")
			local e_Root = e_character:FindFirstChild("HumanoidRootPart")

			if e_Hum and e_Root and not table.find(entities_hit, e_character) then
				if e_character ~= player.Character then
					local function particles()
						local particle = game.ReplicatedStorage.Effects.PunchHit.M1_Hit:Clone()
						particle.Parent = e_Root
						particle:Emit(1)

						game.Debris:AddItem(particle, 0.5)
					end

					print("Hitbox fired: " .. e_character.Name)
					table.insert(entities_hit, e_character)

					coroutine.resume(coroutine.create(function()
						if uptilt then
							-- uptilt (REWORK SOON)
							local function tweenUp(root)
								coroutine.resume(coroutine.create(function()
									root.Anchored = true
									TweenService:Create(root, TweenInfo.new(0.5, Enum.EasingStyle.Quart, Enum.EasingDirection.Out), {CFrame = root.CFrame * CFrame.new(0, 15, 0) }):Play()
									task.wait(0.5)
									root.Anchored = false

									airComboBV(root)
								end))
							end

							combat:Damage(e_character, player.Character, 3, false)
							combat:Disable(e_character, 1, true)
							combat:Stun(e_character, 1.5, true)
							combat:Disable(player.Character, 0.4, false)

							local items = game.SoundService.Sounds.PunchHit:GetChildren()
							local randomItem = items[math.random(1, #items)]

							util.PlaySound(randomItem, e_Root, 1)

							particles()

							tweenUp(root)
							tweenUp(e_Root)
							addAirCombo(player.Character)
						elseif final and checkAirCombo(player.Character) == false then
							-- kickaway
							combat:Damage(e_character,player.Character,3,false)
							combat:Disable(e_character,0.75,true)
							combat:Stun(e_character,0.75,true)
							--combat:Knockaway(player,player.Character,e_character,65,35,0.2)
							combat:Disable(player.Character,0.2,false)
							
							e_Root:ApplyImpulse(e_Root.CFrame.LookVector * workspace.Gravity * -65 * e_Root:GetMass())

							local items = game.SoundService.Sounds.PunchHit:GetChildren()
							local randomItem = items[math.random(1, #items)]

							util.PlaySound(randomItem, e_Root, 1)

							particles()
						elseif final and checkAirCombo(player.Character) == true and aerial == true then
							-- kickback
							removeBV(e_Root)
							removeBV(root)

							combat:Damage(e_character,player.Character,3,false)
							combat:Disable(e_character,0.75,true)
							combat:Stun(e_character,0.75,true)
							combat:Disable(player.Character,0.2,false)
							
							-- kickback knockback
							combat:Knockaway(player,player.Character,e_character,200,1,0.2)

							local items = game.SoundService.Sounds.PunchHit:GetChildren()
							local randomItem = items[math.random(1, #items)]

							util.PlaySound(randomItem, e_Root, 1)

							particles()
						elseif final and checkAirCombo(player.Character) == true and aerial == false then
							-- downslam
							removeBV(e_Root)
							removeBV(root)

							downslamBV(e_character,root)

							combat:Damage(e_character,player.Character,3,false)
							combat:Disable(e_character,0.75,true)
							combat:Stun(e_character,0.75,true)
							combat:Disable(player.Character,0.2,false)

							local items = game.SoundService.Sounds.PunchHit:GetChildren()
							local randomItem = items[math.random(1, #items)]

							util.PlaySound(randomItem, e_Root, 1)

							particles()
						elseif checkAirCombo(player.Character) == false then
							-- base m1 combo
							combat:Damage(e_character, player.Character, 3, false)
							combat:Disable(e_character, 0.75, true)
							combat:Stun(e_character, 0.75, true)
							combat:Knockaway(player, player.Character, e_character, 12, 0, 0.2)
							combat:Knockaway(player, player.Character, player.Character, 12, 0, 0.2)
							combat:Disable(player.Character, 0.2, false)

							local items = game.SoundService.Sounds.PunchHit:GetChildren()
							local randomItem = items[math.random(1, #items)]

							util.PlaySound(randomItem, e_Root, 1)

							particles()
						elseif checkAirCombo(player.Character) == true then
							-- aerial m1 combo (not uptilt)
							combat:Damage(e_character, player.Character, 3, false)
							combat:Disable(e_character, 0.75, true)
							combat:Stun(e_character, 0.75, true)
							combat:Disable(player.Character, 0.2, false)
							particles()
							
							addAirCombo(player.Character)

							local items = game.SoundService.Sounds.PunchHit:GetChildren()
							local randomItem = items[math.random(1, #items)]

							util.PlaySound(randomItem, e_Root, 1)
							
							removeBV(root)
							removeBV(e_Root)

							combat:Knockaway(player, player.Character, e_character, 12, 0, 0.5)
							combat:Knockaway(player, player.Character, player.Character, 12, 0, 0.5)
						end
					end))
				end
			end
		end
	end
end



local function performAttack(player, char, animator, animationToLoad, uptilt, finalHit)
	if animationToLoad then
		local anim = animator:LoadAnimation(animationToLoad)

		if not anim then
			warn("Failed to load animation:", animationToLoad.Name)
			cooldown[player] = false  -- Reset cooldown even if the animation fails to load
			return
		end

		anim:Play()

		cooldown[player] = true

		local cancelAttack = false
		local connection

		connection = RunService.Heartbeat:Connect(function()
			for _, v in pairs(char:GetChildren()) do
				if v.Name == "Disabled" and v:GetAttribute("CanCancel") == true then
					cancelAttack = true
					connection:Disconnect()
				end
			end
		end)

		wait(0.1666666667)

		if not cancelAttack then
			hitbox(player, char:FindFirstChild("HumanoidRootPart"), uptilt, finalHit)
			wait(0.2333333333)
			cooldown[player] = false
		else
			wait(0.2333333333)
			cooldown[player] = false
		end
	else
		warn('animation not found')
		cooldown[player] = false  -- Reset cooldown if the animation is not found
	end
end


local function lightAttack(player, char, animator, aerial)
	if attackCount[player] == 1 then
		print("lmb 1")
		local animationToLoad = BaseInputAnimations:FindFirstChild("Light1")
		performAttack(player, char, animator, animationToLoad, false, false, aerial)
	elseif attackCount[player] ~= 1 and attackCount[player] ~= 5 and not aerial then
		print("lmb (2-4, non-aerial)")
		local animationToLoad = BaseInputAnimations:FindFirstChild("Light" .. attackCount[player])
		performAttack(player, char, animator, animationToLoad, false, false, aerial)
	elseif attackCount[player] ~= 1 and attackCount[player] ~= 5 and checkAirCombo(char) == true and aerial == true then
		print("lmb (2-4, aerial)")
		local animationToLoad = BaseInputAnimations:FindFirstChild("Light" .. attackCount[player])
		performAttack(player, char, animator, animationToLoad, false, false, aerial)
	elseif attackCount[player] ~= 1 and attackCount[player] ~= 5 and checkAirCombo(char) == true and aerial == false then
		print("downtilt")
		local animationToLoad = BaseInputAnimations:FindFirstChild("Light" .. attackCount[player])
		performAttack(player, char, animator, animationToLoad, false, false, aerial)
	elseif attackCount[player] == 5 and checkAirCombo(player.Character) == false then
		print("lmb 5 (non-aerial)")
		local animationToLoad = BaseInputAnimations:FindFirstChild("Light5")
		performAttack(player, char, animator, animationToLoad, false, true, aerial)
	elseif attackCount[player] ~= 1 and attackCount[player] ~= 5 and checkAirCombo(char) == false and aerial then
		print("uptilt")
		local animationToLoad = BaseInputAnimations:FindFirstChild("Uptilt")
		performAttack(player, char, animator, animationToLoad, true, false, aerial)
	elseif attackCount[player] == 5 and checkAirCombo(player.Character) == true and aerial == false then
		print("downslam")
		local animationToLoad = BaseInputAnimations:FindFirstChild("Downslam")
		performAttack(player, char, animator, animationToLoad, false, true, aerial)
	elseif attackCount[player] == 5 and checkAirCombo(player.Character) == true and aerial == true then
		print("kickback")
		local animationToLoad = BaseInputAnimations:FindFirstChild("Kickback")
		performAttack(player, char, animator, animationToLoad, false, true, aerial)
	end
end

local function onPlayerAdded(player)
	player.CharacterAdded:Connect(function()
		lastAttackTime[player] = 0
		attackCount[player] = 0
		cooldown[player] = false
		adjustJumpPower(player)
	end)
end

Players.PlayerAdded:Connect(onPlayerAdded)

AttackEvent.OnServerEvent:Connect(function(player, aerial)
	if not cooldown[player] or cooldown[player] == false then
		local char = player.Character
		if char then
			local root = char:FindFirstChild("HumanoidRootPart")
			local hum = char:FindFirstChild("Humanoid")
			local animator = hum and hum:FindFirstChild("Animator")

			if root and hum and animator then
				combat:Stun(char, 0.4, false)

				if not lastAttackTime[player] then
					lastAttackTime[player] = 0
				end

				if not attackCount[player] then
					attackCount[player] = 0
					adjustJumpPower(player)
				end

				local currentTime = tick()
				local elapsedSinceLastAttack = currentTime - lastAttackTime[player]

				if currentTime - lastAttackTime[player] >= resetCooldown then
					attackCount[player] = 0
					adjustJumpPower(player)
				end

				if elapsedSinceLastAttack >= attackCooldown then
					attackCount[player] = attackCount[player] + 1
					adjustJumpPower(player)

					if attackCount[player] <= maxAttacks then
						lightAttack(player, char, animator, aerial)
						lastAttackTime[player] = currentTime
					end
				end
			end
		end
	end
end)
local function airComboBV(root)
	removeBV(root)

	local bodyVelocity = Instance.new("BodyVelocity")
	bodyVelocity.Name = "AirComboBV"
	bodyVelocity.Velocity = Vector3.new(0, 0, 0)
	bodyVelocity.MaxForce = Vector3.new(0, math.huge, 0)

	bodyVelocity.Parent = root

	game.Debris:AddItem(bodyVelocity,0.5)
end

You’re readding, as you’re removing the BodyVelocity. The system is working correctly as you wrote it. If you want to just remove it, you simply need to call the removeBV function and remove it fully… else you’ll have to wait for the Debris to remove the item.

The way you wrote this part of the code is weird.

			local function checkGround()
				local connection
				connection = game:GetService("RunService").Heartbeat:Connect(function()
					if characterIsOnFloor(character, rootPart) then
						downslamFinished = true
						
						if start.IsPlaying then
							start:Stop()
						end 
						
						if loop.IsPlaying then
							loop:Stop()
						end
						
						finish:Play()
						
						bodyVelocity.Parent = nil
						connection:Disconnect()
					end
				end)
			end

			checkGround()
		end

You could’ve just made a do statement instead of a local function and then call:

do
	-- stuff
end

Don’t forget to dc this event: