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)
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.
--!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)
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).
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)