Locking the player's position on the Y axis

  1. What do you want to achieve?
    I have a Dash function, that when fired, launches the player in a certain direction for a period of time, while also disabling collision. I would like to lock the player’s Y position while doing so, which is where the problem stems from.

  2. What is the issue?
    No variations of locking the Y axis have worked. Also, I’ve seen people do this via quite literally just setting the position every heartbeat, but that doesn’t sound very good, reliable or performant.

Here’s the function in question:

local function Dash()
	RootPart.Velocity = Vector3.zero
	
	local DashVelocity = Instance.new("BodyVelocity")
	DashVelocity.Velocity = (RootPart.CFrame.LookVector * 80)
	DashVelocity.MaxForce = Vector3.new(math.huge, 0, math.huge)
	DashVelocity.P = math.huge
	DashVelocity.Parent = RootPart
	
	Debris:AddItem(DashVelocity, 0.1)

	local GhostedCharacterParts = {}
	for _, Part in ipairs(Character:GetDescendants()) do
		if not Part:IsA("BasePart") or Part.Transparency > 0.75 then continue end
		
		GhostedCharacterParts[Part] = Part.Transparency
		Part.Transparency = 0.75
		Part.CollisionGroup = "Dashing"
	end
	
	task.wait(0.1)

	for Part, Transparency in pairs(GhostedCharacterParts) do
		Part.Transparency = Transparency
		Part.CollisionGroup = "Default"
	end
end
  1. What solutions have you tried so far?
    The obvious one seen here is setting the velocity directly, then preventing the BodyVelocity from ever impacting the Y axis. This method is obviously flawed (and doesn’t work), though I’ve never seen any alternative to this, aside from the aforementioned brute-force method, which I’d like to avoid.

I know you just said setting the Y axis every frame sounds performance heavy, but it really isn’t. Set a variable for the player’s current Y position, and throughout the dash, continue to set their position to that.

While I did list performance as a concern, it generally also seems like a fairly hacky solution. I would like to know if there are any well functioning alternatives before having to resort to that.

Then just have it set on serverside every task.wait()

I’m assuming this means there aren’t any real alternatives to that method (as this is essentially a repeat of the previous one). In that case, I’ll mark your initial answer as the solution. Thank you for your time.

Never-mind. Doing so apparently leads to a bunch of bizarre effects, that occur even after the loop/heartbeat function is broken/unbound.

(Ignore the sound, I forgot to disable my microphone)


It also doesn’t seem to function for some reason?

local function Dash()
	if not CanDash or HasDashed then return end
	RootPart.Velocity = Vector3.zero
	HasDashed = true
	
	local DashVelocity = Instance.new("BodyVelocity")
	DashVelocity.Velocity = (RootPart.CFrame.LookVector * 50)
	DashVelocity.MaxForce = Vector3.new(math.huge, 0, math.huge)
	DashVelocity.P = math.huge
	DashVelocity.Parent = RootPart
	
	Debris:AddItem(DashVelocity, 0.1)

	local GhostedCharacterParts = {}
	for _, Part in ipairs(Character:GetDescendants()) do
		if not Part:IsA("BasePart") then continue end
		
		GhostedCharacterParts[Part] = Part.Transparency
		Part.Transparency = (Part.Transparency > 0.75 and Part.Transparency or 0.75)
		Part.CollisionGroup = "Dashing"
	end
	
	local AxisLock = RootPart.Position.Y
	local TimePassedInLoop = 0
	while TimePassedInLoop < 0.1 do
		RootPart.Position = Vector3.new(RootPart.Position.X, AxisLock, RootPart.Position.Z)
		
		local TimePassed = task.wait()
		TimePassedInLoop += TimePassed
	end
	
	Character:MoveTo(RootPart.Position)

	for Part, Transparency in pairs(GhostedCharacterParts) do
		Part.Transparency = Transparency
		Part.CollisionGroup = "Default"
	end
end
1 Like

Yeesh idk what’s wrong. Not sure how to fix that.