Dash system is very inconsistent during playtests

I made a dash system for my battlegrounds game but it becomes very wonky and inconsistent during playtests.

(I had good ping in playtests)

Comparison:

Not playtesting:

External Media

Play testing:

External Media

My Code:

function dashHandler (player : Player, bool : boolean)
	--Server Script
	
	if not player then return end
	
	local char = player.Character
	if not char then return end
	
	local hum = char:FindFirstChildWhichIsA("Humanoid")
	local hrp = hum.RootPart
	
	if not hum or not hrp then return end
	
	char:SetAttribute("Stunned", true)
	hum.WalkSpeed = 0
	
	
	EffectsHandler.DisableHandTrails(player)
	EffectsHandler.EnableTorsoTrail(player)
	
	
	hrp:SetNetworkOwner()
	
	local lv = Instance.new("LinearVelocity")
	lv.Parent = hrp
	lv.ForceLimitMode = Enum.ForceLimitMode.PerAxis
	lv.VelocityConstraintMode = Enum.VelocityConstraintMode.Vector
	lv.RelativeTo = Enum.ActuatorRelativeTo.Attachment0
	lv.Attachment0 = hrp.RootAttachment
	lv.MaxAxesForce = Vector3.new(100000, 0, 100000)

	local params = RaycastParams.new()
	params.FilterDescendantsInstances = {workspace:FindFirstChild("Players"), workspace:FindFirstChild("Dummies")}
	params.FilterType = Enum.RaycastFilterType.Include

	local track = getTrack(player, Animations.ForwardDash)
	track:Play()


	local endedEarly = false

	local conn = track.DidLoop:Connect(function()
		endedEarly = true
	end)

	for i = 101.65, 0, -0.721 do
		local raycast = workspace:Raycast(hrp.Position, hrp.CFrame.LookVector , params)

		if raycast then
			endedEarly = true
			break
		end

		if endedEarly then
			break
		end

		local vector = hrp.CFrame.LookVector * i
		lv.VectorVelocity = Vector3.new(0, 0, -i)
		RunService.PreSimulation:Wait()
		
		
	end
	
	hrp:SetNetworkOwner(player)
	EffectsHandler.EnableTorsoTrail(player)
	EffectsHandler.DisableTorsoTrail(player)

	conn:Disconnect()
	conn = nil

	print("Hit")


	track:Stop()
	track:Destroy()
	Events.ReplicateAnimationEnding:FireAllClients(hum.Animator)
	lv:Destroy()
	

	task.wait(0.01)
	
	local track2 = getTrack(player, Animations.ForwardDashHit)
	track2:Play()
	
	task.spawn(function()
		task.wait(0.4)
		track2:Stop()
		track2:Destroy()
	end)
	
	dashHit(player, endedEarly)
	char:SetAttribute("Stunned", false)
	

	Events.ReplicateAnimationEnding:FireAllClients(hum.Animator)
	hum.WalkSpeed = require(game.ServerStorage.Constants.Constants).RunSpeed
end

What I have tried:

  • Setting Network Ownership
  • Moving HRP on client
  • Using LinearVelocity on client
  • Using LinearVelocity on server
  • Using BodyVelocity on both server and client
  • Limiting MaxForce/MaxMagnitude to something less than infinity

please help me

How long are you waiting after you hit ‘play’ to test the dash system?
Physics seems to be one of the last items loaded in when testing, so anything dealing with physics may seem stuck if you try them right away.
Test, but wait about 10 seconds to use the dash to see if it makes a difference.

Alright, I’ll try that. aaaaaaaaaaaaaaaaa

Have you searched for other posts about dash effects?
I seem to recall other issues in similar posts that used LinearVelocity which resulted in different dash speeds while jumping vs being on a surface. I think it had to do with the Friction between the player and the floor but don’t quote me on that.

2 Likes

What is the exact issue with the code? If it’s a difference in velocity from both roblox and roblox studio then it is most likely a bug with roblox. Don’t worry im also getting the same issue and I saw a forum post which someone else had the same issue.

2 Likes

yes i’ve searched A LOT of posts but they don’t seem to be helping

1 Like

I don’t know if it’s a Roblox bug or it’s an issue with my code I think it is an issue with Roblox bug though because it works in studio. Can you give me the link to said forum post so I can look at it?

2 Likes

Sorry for not replying sooner but if your code consists of having a task.wait() then i’d recommend switching to just use a wait since I’m pretty sure the hearbeat system in both studio and roblox can be a little scuffed. If this doesn’t work please provide your code.

positions & velocity of characters are client-owned, make your dash on the client and it should work fine

with the actual dash behavior, i tend to stick to AssemblyReferenceHere:ApplyImpulse() (for additions), AssemblyReferenceHere.AssemblyLinearVelocity = (for setting), or LinearVelocity objects set up like so (for constant force):
image
(just mess with it until it works if you don’t know how they work xpx)

and maybe set the humanoidstate to FreeFall just because states get weird sometimes

Humanoid:ChangeState(Enum.HumanoidStateType.Freefall)
1 Like

I’m using the RunService events
I tried task.wait too.

What I have tried:

* Setting Network Ownership
* Moving HRP on client
* Using LinearVelocity on client
* Using LinearVelocity on server
* Using BodyVelocity on both server and client
* Limiting MaxForce/MaxMagnitude to something less than infinity

I tried all of those things and they also didn’t work

This is probably an issue with the for loop and not LinearVelocity itself.
The time it takes for the loop to finish varies from 0.5 to 1.5 seconds which is a huge difference

	local LoopStart = tick()
	
	--increasing the value 60 will make the dash last longer and decreasing it will make the dash shorter
	for i = 70, 47.5, -0.5 do

		local raycast = workspace:Raycast(hrp.Position, hrp.CFrame.LookVector , params)

		if raycast then
			endedEarly = true
			break
		end

		--if endedEarly then
		--	break
		--end


		local vector = -(hrp.CFrame.LookVector * i).Z
		

		stpSwitch(function() --- stpSwitch is a function that (I made) switches to serial mode then after the function is completed then switches to parallel.
			lv.VectorVelocity = Vector3.new(0, 0, -i)
		end)
		

		warn("Completed loop iteration.")
		task.wait(deltaTime)

	end
	
	local TimeTaken = tick() - LoopStart
	
	warn("Time taken to complete loop: ", TimeTaken)


Logs2

Here’s what my client knockback code looks like for one of my games (admittedly pretty old and could be written better)

--[[
 //API
 
 	VelocityManager:ApplyConstantForce(
 			targetAssembly:BasePart|Model, -- NOTE: If a model is provided, it gets the primary part of the model
 			velocity:Vector3,
 			duration:number?,
 			clearMomentum:boolean?
			relativeTo?:Enum.ActuatorRelativeTo?
			resetVelocityAfterForce:boolean?)
 		Creates a constant force on an assembly for a duration. 
 		If no duration is given, it will default to 1 second.
 		If no clearMomentum argument is given, it will default to false.
 		If no relativeTo is given, it will default to Enum.ActuatorRelativeTo.World. (world relativity)
]]

local VelocityManager = {}

--logic
function SetState(targetAssembly)
	local humanoid = targetAssembly.Parent:FindFirstChild("Humanoid")
	if humanoid then
		humanoid:ChangeState(Enum.HumanoidStateType.Freefall)
	end
end

-- Creates a constant force on an assembly for a duration.
function VelocityManager:ApplyConstantForce(targetAssembly:BasePart|Model, velocity:Vector3, duration:number?, clearMomentum:boolean?, relativeTo:Enum.ActuatorRelativeTo?, resetVelocityAfterForce:boolean?)
	if targetAssembly:IsA("Model") then targetAssembly = targetAssembly.PrimaryPart end
	duration = duration or 1
	relativeTo = relativeTo or Enum.ActuatorRelativeTo.World
	
	-- validate root
	local assemblyRoot = targetAssembly.AssemblyRootPart
	if not assemblyRoot then warn("Constant force can't be applied to an assembly without a root") return end
	local VelocityAtCallTime = targetAssembly.AssemblyLinearVelocity
	
	-- validate velocity obj
	local velocityObject:LinearVelocity = assemblyRoot:FindFirstChild("LinearVelocity")
	if not velocityObject then warn("Constant force couldn't be applied: Target assembly root has no LinearVelocity prerequisite") return end
	
	-- set possible humanoid state to falling to prevent any friction/landing mishaps
	SetState(targetAssembly)
	
	-- set relative property
	velocityObject.RelativeTo = relativeTo
	
	 -- update the velocity iteration on the part
	local velocityIteration = velocityObject:GetAttribute("velocityIteration") or 0 -- Acts as a kind of weight, so velocity changes don't overwrite others
	local newIteration = velocityIteration + 1
	velocityObject:SetAttribute("velocityIteration",newIteration)
	
	-- apply the constant force by enabling and changing velocity of the constraint
	velocityObject.VectorVelocity = velocity--*assemblyRoot.AssemblyMass
	velocityObject.Enabled = true
	
	-- without yielding, clear the constant velocity if on the same velocity iteration
	task.delay(duration,function()
		if not velocityObject or velocityObject:GetAttribute("velocityIteration") ~= newIteration then
			-- a new velocity was applied since this was and has already been cleared
			return
		end
		velocityObject.Enabled = false
		if clearMomentum then
			targetAssembly.AssemblyLinearVelocity = Vector3.zero
			targetAssembly.AssemblyAngularVelocity = Vector3.zero
		end
		if resetVelocityAfterForce then
			targetAssembly.AssemblyLinearVelocity = VelocityAtCallTime
		end
	end)
end

return VelocityManager

I also have a relay that allows the server (which will be in a file below) to call this function but I’m not fond of that code. I can explain anything further if you need

here are the entire VelocityManager client & server scripts from my games; it won’t be usable without some adjustments on your game environment though. (server one is a .RBXM because it contains assets as well)
C_VelocityManager.lua (8.5 KB)
S_VelocityManager.rbxm (9.6 KB)

2 Likes

Sorry for the insanely long wait but I have found a solution! Just put a time limit on the loop and it should work fine.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.