LinearVelocity causing a "flick" effect with my character, unsure why

Hi,

I wrote a similar topic to this a bit ago but it didn’t really tackle the primary problem I had with the constraint. Whenever I go to dash, the character has a “flick” effect where it briefly changes it’s orientation before going back into place:

This can be problematic as it sometimes leads to the player being flung. I’m unsure why the constraint is doing this, so I was wondering if someone here was able to help point me in the right direction. Thank you in advance !!

--!strict

local ContextActionService = game:GetService("ContextActionService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer
-- Since this is a StarterCharacterScript the character will always be the correct one
local character = player.Character
local rootPart = character:FindFirstChild("HumanoidRootPart")
local humanoid = character:FindFirstChildOfClass("Humanoid")

assert(rootPart:IsA("BasePart"))
assert(humanoid)

-- Create the proper LinearVelocity
local attatchment0 = Instance.new("Attachment")
local attatchment1 = attatchment0:Clone()

attatchment0.Parent = rootPart
attatchment1.Parent = rootPart

local linearVelocity = Instance.new("LinearVelocity")
linearVelocity.Attachment0 = attatchment0
linearVelocity.Attachment1 = attatchment1
linearVelocity.MaxForce = math.huge
linearVelocity.RelativeTo = Enum.ActuatorRelativeTo.World
linearVelocity.Enabled = false -- Set to true only when performing a move!! If set to true then the player cannot move on their own accord!

linearVelocity.Parent = rootPart

-- Function definitions for moveset
local ACTION_DASH = "Dash"
local DASH_KEYBIND = Enum.KeyCode.LeftShift
local DASH_DISTANCE = 20
local DASH_TIME = 0.1
local DASH_COOLDOWN = 0.5

local dashVelocity = DASH_DISTANCE / DASH_TIME

local dashDebounce = false
local dashReset = true
local lastDash = 0

local function dash(_, InputState: Enum.UserInputState, InputObject: InputObject)
    -- is the debounce active?
    -- is the UIS the correct one?
    if dashDebounce 
    or InputState ~= Enum.UserInputState.Begin then 
        return 
    end

    -- cooldown
    local timeOfRequest = tick()
    local delta = timeOfRequest - lastDash
    if delta < DASH_COOLDOWN then
        return
    end

    -- if in the air, only dash once
    if humanoid.FloorMaterial == Enum.Material.Air then
        if not dashReset then
            return
        end

        dashReset = false
    end

    dashDebounce = true

    lastDash = tick()
    local oldVelocity = rootPart.AssemblyLinearVelocity

    local dashDirection = if humanoid.MoveDirection ~= Vector3.zero then humanoid.MoveDirection else rootPart.CFrame.LookVector
    dashDirection = Vector3.new(dashDirection.X, 0, dashDirection.Z).Unit

    linearVelocity.VectorVelocity = dashDirection * dashVelocity

    linearVelocity.Enabled = true

    task.wait(DASH_TIME)

    linearVelocity.Enabled = false
    
    -- No Y velocity so things like jumps aren't maintained
    rootPart.AssemblyLinearVelocity = Vector3.new(oldVelocity.X, 0, oldVelocity.Z)

    dashDebounce = false
end

-- Register base moveset (may be changed by other abilities)
ContextActionService:BindAction(ACTION_DASH, dash, true, DASH_KEYBIND)

-- Connections
humanoid.StateChanged:Connect(function(_, newState: Enum.HumanoidStateType)
    if newState == Enum.HumanoidStateType.Landed then
        -- reset any once-in-air abilities
        dashReset = true
    end
end)

-- Unregister base moveset on death to not clog up ContextActionService
humanoid.Died:Connect(function()
    ContextActionService:UnbindAction(ACTION_DASH)
end)
2 Likes

You could use a BodyVelocity instead.
It’s easier to use, though, it’s deprecated.

local bodyVelocity = Instance.new("BodyVelocity") 
bodyVelocity.MaxForce = (Vector3.one * math.huge)
bodyVelocity.Velocity = (dashDirection * dashVelocity) * 0.5
bodyVelocity.Parent = rootPart  
1 Like

Someone else fixed this issue by reducing the max force of the linear velocity.

Change that.

Yes, that was me who “fixed” it, but that then causes other issues (like the MaxForce not being enough to dash fast enough, so it just gets capped) and it’s incredibly inconsistent anyways.

I should not be forced to use a deprecated class just to make a functional dash

4 Likes

Hello @Joshument again. This time I would suggest the method from my previous post, plane constraint and line constraint.

--!strict

local ContextActionService = game:GetService("ContextActionService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer
-- Since this is a StarterCharacterScript the character will always be the correct one
local character = player.Character
local rootPart = character:FindFirstChild("HumanoidRootPart")
local humanoid = character:FindFirstChildOfClass("Humanoid")

assert(rootPart:IsA("BasePart"))
assert(humanoid)

-- Create the proper LinearVelocity
local attachment0 = Instance.new("Attachment")
attachment0.Parent = rootPart
attachment0.WorldPosition = rootPart.AssemblyCenterOfMass

local linearVelocity = Instance.new("LinearVelocity")
linearVelocity.Attachment0 = attachment0
linearVelocity.MaxForce = math.huge
linearVelocity.RelativeTo = Enum.ActuatorRelativeTo.World
linearVelocity.VelocityConstraintMode = Enum.VelocityConstraintMode.Plane
linearVelocity.Enabled = false -- Set to true only when performing a move!! If set to true then the player cannot move on their own accord!
linearVelocity.PrimaryTangentAxis = Vector3.new(1,0,0)
linearVelocity.SecondaryTangentAxis = Vector3.new(0,0,1)

linearVelocity.Parent = rootPart

local zeroYAxisLinearVelocity = Instance.new("LinearVelocity")
zeroYAxisLinearVelocity.VelocityConstraintMode = Enum.VelocityConstraintMode.Line
zeroYAxisLinearVelocity.Attachment0 = attachment0
zeroYAxisLinearVelocity.RelativeTo = Enum.ActuatorRelativeTo.World
zeroYAxisLinearVelocity.Enabled = false
zeroYAxisLinearVelocity.MaxForce = math.huge
zeroYAxisLinearVelocity.LineDirection = Vector3.yAxis

zeroYAxisLinearVelocity.Parent = rootPart

-- Function definitions for moveset
local ACTION_DASH = "Dash"
local DASH_KEYBIND = Enum.KeyCode.LeftShift
--local DASH_DISTANCE = 20
--local DASH_TIME = 0.1

--for testing purposess
local DASH_DISTANCE = 20
local DASH_TIME = 1

local DASH_COOLDOWN = 0.5

local dashVelocity = DASH_DISTANCE / DASH_TIME

local dashDebounce = false
local dashReset = true
local lastDash = 0
attachment0.Visible = true
print(attachment0)
local function dash(_, InputState: Enum.UserInputState, InputObject: InputObject)
	-- is the debounce active?
	-- is the UIS the correct one?
	if dashDebounce 
		or InputState ~= Enum.UserInputState.Begin then 
		return 
	end

	-- cooldown
	local timeOfRequest = tick()
	local delta = timeOfRequest - lastDash
	if delta < DASH_COOLDOWN then
		return
	end

	-- if in the air, only dash once
	if humanoid.FloorMaterial == Enum.Material.Air then
		if not dashReset then
			return
		end

		dashReset = false
	end

	dashDebounce = true

	lastDash = tick()
	local oldVelocity = rootPart.AssemblyLinearVelocity

	local dashDirection = if humanoid.MoveDirection ~= Vector3.zero then humanoid.MoveDirection else rootPart.CFrame.LookVector
	dashDirection = Vector3.new(dashDirection.X, 0, dashDirection.Z).Unit
	--linearVelocity.VectorVelocity = dashDirection * dashVelocity --Old method
	
	--Plane velocity method
	linearVelocity.PlaneVelocity = Vector2.new(dashDirection.X, dashDirection.Z).Unit*dashVelocity
	zeroYAxisLinearVelocity.LineVelocity = 0
	zeroYAxisLinearVelocity.Enabled = true
	linearVelocity.Enabled = true
	task.wait(DASH_TIME)
	zeroYAxisLinearVelocity.Enabled = false
	linearVelocity.Enabled = false

	-- No Y velocity so things like jumps aren't maintained
	rootPart.AssemblyLinearVelocity = Vector3.new(oldVelocity.X, 0, oldVelocity.Z)

	dashDebounce = false
end

-- Register base moveset (may be changed by other abilities)
ContextActionService:BindAction(ACTION_DASH, dash, true, DASH_KEYBIND)

-- Connections
humanoid.StateChanged:Connect(function(_, newState: Enum.HumanoidStateType)
	if newState == Enum.HumanoidStateType.Landed then
		-- reset any once-in-air abilities
		dashReset = true
	end
end)

-- Unregister base moveset on death to not clog up ContextActionService
humanoid.Died:Connect(function()
	ContextActionService:UnbindAction(ACTION_DASH)
end)
6 Likes

ahh, I didn’t know this is what you meant, lol. Strange why this works for some reason but 3 axis is wonky?

A bit late, but yeah as I explained in the previous post it is caused by the linear velocity VectorMode only constraints the attachment point velocity.

If you were to enable Platform stand during the dash with your old method you would notice that the character will actually spin, therefore it is the humanoid that is preventing the spinning and the linear velocity VectorMode is causing the spin.

In plane constraint every velocity point within the 2D “Plane” has the same velocity value therefore there should be no rotation (From my understanding).

1 Like

Is it just me or is this just changed recently? Cause right now I’m doing this with planevelocity but it is still rotating.

1 Like

sorry for bumping, but id like to know:

if you could dash in any arbitrary direction, how would the plane velocity be set up?

i know vector mode for linear velocity is almost a perfect solution for this, but i hate the flick it causes on characters

might be late. but id imagine you would use the look vector and maybe just multiply it by (1, 0, 0) for Primary and (0, 0, 1) for Secondary tangents. (i have not tried this and it oculd be completely wrong)