Changing BodyForce in HumanoidRootPart resets Y velocity

Hello! I’m making a wall running mechanic in my game and I want it to be kind of similar to the one in this game: https://www.roblox.com/games/445664957/Parkour

When you press space and you’re next to a wall you start a wall run. If you’re falling you’ll keep your Y velocity.

I tried achieving this by setting game.Workspace.Gravity locally but figured it was cleaner if I used a BodyForce as “anti-gravity”. So now whenever a player starts a wallrun a BodyForce in their root part will be set to a Y force of 50, however, this resets the player’s Y velocity, causing them to stop falling mid-air

I’ve tried saving the player’s velocity before changing the BodyForce and then setting their velocity to that value after, but that didn’t seem to change anything.

What I want
What I have (White parts are raycast indicators)

(Excuse the links, I can’t upload video’s to the forum for some reason)

Any help would be appreciated, thank you!

2 Likes

Could I have a look at the code or a place file? That might make the problem more clear

2 Likes

You may, this script is stored in the player’s character, it’s a LocalScript

local UIS = game:GetService("UserInputService")

local RayCast = require(game.ReplicatedStorage:WaitForChild("Modules").RayCast)
local RayCastNoChar = require(game.ReplicatedStorage:WaitForChild("Modules").EZRayCast).RayCastNoChar
local EZC = require(game.ReplicatedStorage:WaitForChild("Modules").EZCFrame)

local LP = game.Players.LocalPlayer
local Char = LP.Character
local Hum = Char.Humanoid
local Root = Char.HumanoidRootPart

local BF = Root:WaitForChild("BodyForce")

-- Load anim tracks for wall run
local LeftRunTrack = Hum:LoadAnimation(script:WaitForChild("Left"))
local RightRunTrack = Hum:LoadAnimation(script:WaitForChild("Right"))

local Running = false
local PressedSpace = false
local NoFall = script.Parent.FallDamage.NoFall

local function StartBF()
    BF.Force = Vector3.new(0 ,50, 0)
end

local function StopBF()
    BF.Force = Vector3.new(0, 0, 0)
end

UIS.InputBegan:Connect(function(Key)
    if Running then
        PressedSpace = true
    else
        if Key.KeyCode == Enum.KeyCode.Space and Hum.FloorMaterial == Enum.Material.Air then
            local RootCF = Root.CFrame
            local CFRight = EZC.PosLookAt(Root.CFrame.Position, -RootCF.RightVector)
            local CFLeft = EZC.PosLookAt(Root.CFrame.Position, RootCF.RightVector)

            local HitRight,PosRight,NormRight = RayCastNoChar(CFRight, 3, Char)
            local HitLeft,PosLeft,NormLeft = RayCastNoChar(CFLeft, 3, Char)

            if HitLeft or HitRight then
                wait()
                StartBF()
                Running = true

                if HitLeft then
                    LeftRunTrack:Play()
                    while Running and Hum.FloorMaterial == Enum.Material.Air do
                        wait()
                        local RootCF = Root.CFrame
                        local CFLeft = EZC.PosLookAt(Root.CFrame.Position, RootCF.RightVector)
                        local HitLeft,PosLeft,NormLeft = RayCastNoChar(CFLeft, 3, Char)

                        if not HitLeft then
                            -- User isn't close enough to the wall
                            Running = false
                        end

                        if PressedSpace then
                            -- Do a little jump when a player presses space to get out of a wallrun and disable fall damage for a short time
                            PressedSpace = false
                            Root.Velocity = Hum.MoveDirection + Vector3.new(0, 50, 0)
                            Running = false
                            NoFall.Value = true
                            spawn(function()
                                wait(.15)
                                NoFall.Value = false
                            end)
                        end
                    end
                else
                    RightRunTrack:Play()
                    while Running and Hum.FloorMaterial == Enum.Material.Air do
                        wait()
                        local RootCF = Root.CFrame
                        local CFRight = EZC.PosLookAt(Root.CFrame.Position, -RootCF.RightVector)
                        local HitRight,PosRight,NormRight = RayCastNoChar(CFRight, 3, Char)

                        if not HitRight then
                            -- User got too far from the wall
                            Running = false
                            break
                        end

                        if PressedSpace then
                            -- Do a little jump when a player presses space to get out of a wallrun and disable fall damage for a short time
                            PressedSpace = false
                            Root.Velocity = Hum.MoveDirection + Vector3.new(0, 50, 0)
                            Running = false
                            NoFall.Value = true
                            spawn(function()
                                wait(.15)
                                NoFall.Value = false
                            end)
                            break
                        end
                    end
                end

                Running = false
                StopBF()
                RightRunTrack:Stop()
                LeftRunTrack:Stop()
            end
        end
    end
end)
1 Like

So do you want it to make it so you dont constantly run so fast down the wall?
if so change the bp force to this

local totalMass = 0
for _,v in pairs(char:GetChildren()) do
    if v:IsA("BasePart") then
        totalmass = totalmass+v
    end
end
bp.Force = Vector3.new(0, (totalmass*gravity)*0.8,0) --0.8 is so you dont run directly straight
1 Like

Okay I have fixed it by saving the player’s velocity, waiting .03 seconds and then starting the wall run loop and setting the velocity of the player back to the old one

local OldVelo = Root.Velocity
wait()
StartBF()
Root.Velocity = OldVelo

Feel free to reply with a better solution if you have one.

1 Like

I want it to maintain the Y velocity of the player when they start a wallrun, otherwise you’ll get a weird effect where it seems like they stop their fall mid-air.

Oh, wouldnt the best way then to do this


local endTime = tick() + 3

--start your loop

force = sin(endtime-tick())*fullForce

or whatever the formula would be lol