Can't find a good movement solution

i’m trying to make the character sort of zip to a point without too high of a velocity. here is what is happening right now:


and here is the code (part of it anyways cause its a really long script):

			brick.Touched:Connect(function(hit)
				local touchingParts = brick:GetTouchingParts()
				for i, v in pairs(touchingParts) do
			--		print(i, ": ", v.Name, " Parent: ", v.Parent)
					if v.Parent == wallsFolder or v.Parent == zipPointsFolder or v.Parent == powerUpsFolder then
						spawn(function()
							if v.Parent == zipPointsFolder or v.Parent == powerUpsFolder then
								
								brick.Position = v.Position

								-- Manipulate rope constraints directly
								rope1.Length = 0  -- Set rope length to 0 to ensure the player is instantly pulled in
								rope1.Visible = true  -- Make sure the rope is visible

								-- Adjust other parameters if necessary
								rope1.WinchTarget = 0
								rope1.WinchResponsiveness = 1000
								rope1.WinchSpeed = 1000
								rope1.WinchForce = 5000
								rope1.Restitution = 0

								forceRetractDistance = 10
							elseif v.Parent == powerUpsFolder then
								-- Calculate direction and distance to the power-up
								local direction = (v.Position - char.HumanoidRootPart.Position).unit
								local distance = (v.Position - char.HumanoidRootPart.Position).magnitude

								-- Set up a BodyForce to pull the character towards the power-up
								local bodyForce = Instance.new("BodyForce")
								bodyForce.Force = direction * (workspace.Gravity * char:GetMass())
								bodyForce.Parent = char.HumanoidRootPart

								hitPowerUp = v
							end
							rope1.Enabled = true
							repeat
								wait()
								springConstraintEffect.Coils -= 0.2
								springConstraintEffect.Radius -= 0.1
							until springConstraintEffect.Coils <= 0 and springConstraintEffect.Radius <= 0
							wait(0.1)
							springConstraintEffect:Destroy()
							rope1.Visible = true
						end)

						local soundsClone = hitSounds:Clone()
						soundsClone.Parent = brick

						local hitSound = {}
						for i, v in pairs(soundsClone:GetChildren()) do
							if v:IsA("Sound") then
								table.insert(hitSound, v)
							end
						end

						local randomHitSound = hitSound[math.random(1, #hitSound)]
						if not hitSoundPlayed then
							hitSoundPlayed = true
							randomHitSound:Play()
						end

						antiGravity:Destroy()
						brick.Velocity = Vector3.zero						
						brick.Anchored = true
						
						stickToPart(brick)

						if not ragdolled then
							RagdollModule.ragdoll(char)
							ragdolled = true
						end
						BrUARope.Enabled = true
						break
					elseif v.Parent == brick then
						
					else
						retractGrappleHook()
					end
				end
			end)

i’ve tried prismatic constraints (can’t figure it out), it works if you set the winchforce of the rope to really high but it’s not ideal because i don’t want the velocity of the character to be so high.

thanks for reading this guys, if you are confused about anything or want to help somehow please let me know! thanks!

1 Like

One idea I have is to limit the velocity from getting too high while maintaining smoother movements at low speeds by adding on an additional drag force. Using a vector force or perhaps the beta aerodynamics forces could work.

1 Like

i’m not really familiar with drag forces or vector forces cause i usually just use the normal velocity property of parts. if it’s convenient do you think you might be able to give me an example of what you mean? thanks dude

the way i see it, the spring is trying to pull you towards the part, but obviously gravity changes that.
I think by adding a vector force to the player that counteracts the players gravity (workspace.Gravity * character.HumanoidRootPart.AssemblyMass) and removing all the players velocity could work. Essentially, it would pull you in a very straight line towards the target, but it can still pull you very fast depending on how much time the spring is given to accelerate you towards your target, and at the end (or when you are close enough to release the ziplines / grapple, you remove that vector) the player will fall. This still allows the player to move around and makes it harder to reach the target position, so i think also adding the players current velocity to the target position would work, to sort of offset how the string pulls you to bring you back into allignment.
If you dont want the player to be moving while on the zipline, you could just set their EvaluateStateMachine to false, which basically turns off how the humanoid would normally interact with the world, and instead add onto that gravity vector the direction of the target
i dont really know how to solve this in a specific way, so these are just my ideas

oh wait now that im looking more at your script, you could also just replace the distance variable you have, with the target speed you want

can we see the whole script?

i feel like im missing key information, you have an antigravity reference, but it doesnt seem to be doing its job

yeah, your right. here’s the full main part of the script:

local function fireGrappleHook()
	RagdollModule.ragdoll(char)

	-- Wait for the LocalPlayer to be available
	if mouse.Target then
		if bool == false then		
			torsoSmoke:Emit(20)
			torso.Velocity += torso.CFrame.LookVector * -50

			local targetCFrame = mouse.Hit

			-- Create the anchored brick
			local brick = grapplerMesh:Clone()
			brick.Size = Vector3.new(1, 1, 1)
			brick.BrickColor = BrickColor.new("Really red")
			brick.Parent = game.Workspace
			brick.Transparency = 0
			brick.CanCollide = false
			brick.Anchored = true
			brick.Position =  rootPart.Position + brick.CFrame.LookVector * 1.5
			brick.Name = "Grappler"
			
			grapplerInstances.part = brick

			local soundsClone = fireSounds:Clone()
			soundsClone.Parent = brick

			local Sound = {}
			for i,v in pairs(soundsClone:GetChildren()) do
				if v:IsA("Sound") then
					table.insert(Sound,v)
				end
			end
			local RandomSound = Sound[math.random(1,#Sound)]
			RandomSound:Play()

			local highlight = Instance.new("Highlight")
			highlight.Parent = brick
			highlight.Adornee = brick
			highlight.Enabled = false

			brick.CFrame = CFrame.lookAt(brick.Position, targetCFrame.Position)

			local antiGravity = Instance.new("BodyForce")
			antiGravity.Force = Vector3.new(0, workspace.Gravity * brick:GetMass(),0)
			antiGravity.Parent = brick

			brick.Velocity = brick.CFrame.LookVector * 300
			brick.Anchored = false

			local startPos = brick.Position

			local UA = Instance.new("Part")
			UA.Size = Vector3.new(0.5, 0.5, 0.5)
			UA.CustomPhysicalProperties = PhysicalProperties.new(100, 0, 0, 0, 0)
			UA.Parent = brick
			UA.Shape = "Ball"
			UA.Transparency = 1
			UA.CanCollide = false
			UA.Anchored = false
			UA.Position = brick.Position

			-- Create attachments for the ball and the brick
			local UAatt = Instance.new("Attachment")
			UAatt.Parent = UA
			UAatt.WorldPosition = UA.Position
			UAatt.Name = "UAatt"

			local Brickatt = Instance.new("Attachment")
			Brickatt.Parent = brick
			Brickatt.WorldPosition = brick.Position
			Brickatt.Name = "Brickatt"

			local springConstraintEffect = Instance.new("SpringConstraint")
			springConstraintEffect.Parent = torso
			springConstraintEffect.Enabled = true
			springConstraintEffect.Color = BrickColor.new("Really black")
			springConstraintEffect.Visible = true
			springConstraintEffect.Coils = 3
			springConstraintEffect.Radius = .1
			springConstraintEffect.Attachment0 = torso:WaitForChild("BodyFrontAttachment")
			springConstraintEffect.Attachment1 = Brickatt
			
			grapplerInstances.spring = springConstraintEffect

			-- Create a rope between the anchored brick and the unanchored ball
			local BrUARope = Instance.new("RopeConstraint")
			BrUARope.Visible = false
			BrUARope.Enabled = false
			BrUARope.Attachment0 = Brickatt
			BrUARope.Attachment1 = UAatt
			BrUARope.Length = 0.1
			BrUARope.Thickness = 10000
			BrUARope.Parent = brick

			-- Create a rope between the player and the unanchored ball
			local rope1 = Instance.new("RopeConstraint")
			rope1.Enabled = false
			rope1.Visible = false
			rope1.Attachment0 = player.Character.Torso:FindFirstChild("BodyFrontAttachment")
			rope1.Attachment1 = UAatt
			rope1.Thickness = 0.15
			rope1.Parent = UA
			rope1.Name = "Rope"
			rope1.Length = player:DistanceFromCharacter(brick.Position) + 1
			rope1.Color = BrickColor.new("Really black")
			rope1.WinchEnabled = true
			rope1.WinchTarget = 0
			rope1.WinchResponsiveness = 75
			rope1.WinchSpeed = 50
			rope1.WinchForce = 20000
			rope1.Restitution = .5
			bool = true
			
			grapplerInstances.rope = rope1
			
			local ragdolled = false
			local hitSoundPlayed = false
			local forceRetractDistance = 0
			local hitPowerUp = nil
			local hasBeenTouched = false

			brick.Touched:Connect(function(hit)
				local touchingParts = brick:GetTouchingParts()
				for i, v in pairs(touchingParts) do
				--	print(i, ": ", v.Name, " Parent: ", v.Parent)
					if v.Parent == wallsFolder or v.Parent == zipPointsFolder or v.Parent == powerUpsFolder and not hasBeenTouched then
						hasBeenTouched = true
							if v.Parent == zipPointsFolder or v.Parent == powerUpsFolder then
								
								brick.Position = v.Position

								-- Manipulate rope constraints directly
								rope1.Length = 0  -- Set rope length to 0 to ensure the player is instantly pulled in
								rope1.Visible = true  -- Make sure the rope is visible

								-- Adjust other parameters if necessary
								rope1.WinchTarget = 0
								rope1.WinchResponsiveness = 1000
								rope1.WinchSpeed = 1000
								rope1.WinchForce = 5000
								rope1.Restitution = 0

								forceRetractDistance = 10
							elseif v.Parent == powerUpsFolder then
								-- Calculate direction and distance to the power-up
								local direction = (v.Position - char.HumanoidRootPart.Position).unit
								local distance = (v.Position - char.HumanoidRootPart.Position).magnitude

								-- Set up a BodyForce to pull the character towards the power-up
								local bodyForce = Instance.new("BodyForce")
								bodyForce.Force = direction * (workspace.Gravity * char:GetMass())
								bodyForce.Parent = char.HumanoidRootPart

								hitPowerUp = v
							end
							rope1.Enabled = true
							print('still running')
						spawn(function()
							repeat
								wait()
								springConstraintEffect.Coils -= 0.2
								springConstraintEffect.Radius -= 0.1
							until springConstraintEffect.Coils <= 0 and springConstraintEffect.Radius <= 0
							wait(0.1)
							springConstraintEffect:Destroy()
							rope1.Visible = true
						end)

						local soundsClone = hitSounds:Clone()
						soundsClone.Parent = brick

						local hitSound = {}
						for i, v in pairs(soundsClone:GetChildren()) do
							if v:IsA("Sound") then
								table.insert(hitSound, v)
							end
						end

						local randomHitSound = hitSound[math.random(1, #hitSound)]
						if not hitSoundPlayed then
							hitSoundPlayed = true
							randomHitSound:Play()
						end

						antiGravity:Destroy()
						brick.Velocity = Vector3.zero						
						brick.Anchored = true
						
						stickToPart(brick)

						if not ragdolled then
							RagdollModule.ragdoll(char)
							ragdolled = true
						end
						BrUARope.Enabled = true
						break
					elseif v.Parent == brick or hasBeenTouched then
						
					else
						retractGrappleHook()
					end
				end
			end)
			hasBeenTouched = true
			spawn(function()
				while not ragdolled do
					wait()
					local distanceToTarget = (brick.Position - targetCFrame.Position).Magnitude
					local maxDistance = 50  -- Adjust this value based on your preferences
					local minCoils = 0.1
					local maxCoils = 50
					local coils = distanceToTarget

					-- Adjust the Length property based on the number of coils
					torso:FindFirstChild("BodyFrontAttachment").Orientation += Vector3.new(0,0,10)
					if springConstraintEffect.Coils < maxCoils then
						springConstraintEffect.Coils += .4
					end
					if springConstraintEffect.Radius < 1 then
						springConstraintEffect.Radius += .05
					end
				end
				while ragdolled do
					wait()
					if (torso.Position - brick.Position).Magnitude < forceRetractDistance then
						retractGrappleHook()
						if hitPowerUp then
							hitPowerUp.CanCollide =  true
							hitPowerUp.Anchored = false
							
							if torso:FindFirstChild("BodyForce") then
								torso:FindFirstChild("BodyForce"):Destroy()
							end
							
							DebrisService:AddItem(hitPowerUp, 5)
							retractGrappleHook()
						end
						break
					end
				end
			end)

			torso:FindFirstChild("BodyFrontAttachment").Orientation = Vector3.new(0,0,0)
		end
	end
end

i should also mention that the springConstraint is purely for visual effects, i took inspiration from the Fortnite grappler for that effect. thanks for your help! edit: sorry i’m just kind of resistant to give the whole script because i’ve been working really hard on this, even if the chance is small i don’t want anyone to steal all of this code because i really want to make a good, fun game that lots of people can enjoy instead of all of those crap posts on the main page of Roblox if you know what i mean.

1 Like

i just fixed some bugs, here’s a better version without them: (if you guys want)

		brick.Touched:Connect(function(hit)
			local touchingParts = brick:GetTouchingParts()
			for i, v in pairs(touchingParts) do
				print(i, ": ", v.Name, " Parent: ", v.Parent)
				if v.Parent == wallsFolder or v.Parent == zipPointsFolder or v.Parent == powerUpsFolder and not hasBeenTouched then
					hasBeenTouched = true
					spawn(function()
						if v.Parent == zipPointsFolder or v.Parent == powerUpsFolder then
							
							brick.Position = v.Position

							-- Manipulate rope constraints directly
							rope1.Length = 0  -- Set rope length to 0 to ensure the player is instantly pulled in
							rope1.Visible = true  -- Make sure the rope is visible

							-- Adjust other parameters if necessary
							rope1.WinchTarget = 0
							rope1.WinchResponsiveness = 1000
							rope1.WinchSpeed = 1000
							rope1.WinchForce = 5000
							rope1.Restitution = 0

							forceRetractDistance = 30
						elseif v.Parent == powerUpsFolder then
							-- Calculate direction and distance to the power-up
							local direction = (v.Position - char.HumanoidRootPart.Position).unit
							local distance = (v.Position - char.HumanoidRootPart.Position).magnitude

							-- Set up a BodyForce to pull the character towards the power-up
							local bodyForce = Instance.new("BodyForce")
							bodyForce.Force = direction * (workspace.Gravity * char:GetMass())
							bodyForce.Parent = char.HumanoidRootPart

							hitPowerUp = v
						end
						rope1.Enabled = true
						print('still running')
						repeat
							wait()
							springConstraintEffect.Coils -= 0.2
							springConstraintEffect.Radius -= 0.1
						until springConstraintEffect.Coils <= 0 and springConstraintEffect.Radius <= 0
						wait(0.1)
						springConstraintEffect:Destroy()
						rope1.Visible = true
					end)

					local soundsClone = hitSounds:Clone()
					soundsClone.Parent = brick

					local hitSound = {}
					for i, v in pairs(soundsClone:GetChildren()) do
						if v:IsA("Sound") then
							table.insert(hitSound, v)
						end
					end

					local randomHitSound = hitSound[math.random(1, #hitSound)]
					if not hitSoundPlayed then
						hitSoundPlayed = true
						randomHitSound:Play()
					end

					antiGravity:Destroy()
					brick.Velocity = Vector3.zero						
					brick.Anchored = true
					
					stickToPart(brick)

					if not ragdolled then
						RagdollModule.ragdoll(char)
						ragdolled = true
					end
					BrUARope.Enabled = true
					break
				elseif v.Parent == brick or hasBeenTouched then
					
				else
					retractGrappleHook()
				end
			end
		end)
		spawn(function()
			while not ragdolled do
				wait()
				local distanceToTarget = (brick.Position - targetCFrame.Position).Magnitude
				local maxDistance = 50  -- Adjust this value based on your preferences
				local minCoils = 0.1
				local maxCoils = 50
				local coils = distanceToTarget

				-- Adjust the Length property based on the number of coils
				torso:FindFirstChild("BodyFrontAttachment").Orientation += Vector3.new(0,0,10)
				if springConstraintEffect.Coils < maxCoils then
					springConstraintEffect.Coils += .4
				end
				if springConstraintEffect.Radius < 1 then
					springConstraintEffect.Radius += .05
				end
			end
			while ragdolled do
				wait()
				if (torso.Position - brick.Position).Magnitude < forceRetractDistance then
					retractGrappleHook()
					if hitPowerUp then
						hitPowerUp.CanCollide =  true
						hitPowerUp.Anchored = false
						
						if torso:FindFirstChild("BodyForce") then
							torso:FindFirstChild("BodyForce"):Destroy()
						end
						
						DebrisService:AddItem(hitPowerUp, 5)
						retractGrappleHook()
					end
					break
				end
			end
		end)

I would suggest trying a LinearVelocity object instead of the BodyForce for how the player is moved towards the brick part. LinearVelocity accelerates objects towards a target speed, and the acceleration is changeable.
Id also suggesting making a seperate force, such as a VectorForce to make the player experience no gravity. in your script, you were doing direction * weight, but really, it should by direction + weight, which in this case, LinearVelocity controls the direction, and the VectorForce would control counteracting gravity. Another thing that might help is to subtract the players velocity from the direction vector, so that the player will swing above and below the brick less often (it will predict where the player will be in the next second, so we counteract that by changing our forces to put the player in the right spot)
This still means the player may miss the target if they are flung horizontally towards the brick, but it will almost guarantee the player should hit the brick if its a straight shot.
I should also say, the LinearVelocity Velocity should be updated every heartbeat

1 Like

k, i’ll try that rn thanks for your help i’ll post how it goes

1 Like
						if v.Parent == zipPointsFolder or v.Parent == powerUpsFolder then
							
							brick.Position = v.Position

							-- Manipulate rope constraints directly
							rope1.Length = 0  -- Set rope length to 0 to ensure the player is instantly pulled in
							rope1.Visible = true  -- Make sure the rope is visible

							-- Adjust other parameters if necessary
							rope1.WinchTarget = 0
							rope1.WinchResponsiveness = 1000
							rope1.WinchSpeed = 1000
							rope1.WinchForce = 5000
							rope1.Restitution = 0

							forceRetractDistance = 30
							
							if v.Parent == powerUpsFolder then
								local charAntiGravity = Instance.new("BodyForce")
								charAntiGravity.Force = Vector3.new(0,workspace.Gravity * rootPart.AssemblyMass,0)
								
								local direction = (v.Position - rootPart.Position).unit
								local distance = (v.Position - rootPart.Position).magnitude
								
								local linearVelocity = Instance.new("LinearVelocity")
								linearVelocity.VelocityConstraintMode = Enum.VelocityConstraintMode.Vector
								linearVelocity.VectorVelocity = direction + Vector3.new(0,rootPart.AssemblyMass,0)
								
								torso.Velocity = Vector3.zero
								linearVelocity.Parent = torso
								charAntiGravity.Parent = torso
								
								spawn(function()
									RunService.Heartbeat:Connect(function()
										linearVelocity.VectorVelocity = direction + Vector3.new(0,rootPart.AssemblyMass,0)
									end)
								end)
							end
						end

ok, here’s what i tried but it’s not really working, is there something that i didn’t wright right?

LinearVelocity is a constraint, but I tried my best to rewrite yours using LinearVelocity and VectorForce.
TargetSpeed is the speed we want our character to move at.
Acceleration is the speed at which our player can reach it.

local TargetSpeed = 100
local Acceleration = 100
if v.Parent == zipPointsFolder or v.Parent == powerUpsFolder then
							
							brick.Position = v.Position

							-- Manipulate rope constraints directly
							rope1.Length = 0  -- Set rope length to 0 to ensure the player is instantly pulled in
							rope1.Visible = true  -- Make sure the rope is visible

							-- Adjust other parameters if necessary
							rope1.WinchTarget = 0
							rope1.WinchResponsiveness = 1000
							rope1.WinchSpeed = 1000
							rope1.WinchForce = 5000
							rope1.Restitution = 0

							forceRetractDistance = 30
							
							if v.Parent == powerUpsFolder then
								local charAntiGravity = Instance.new("VectorForce",rootPart)
	 	 	 	 	 	 	 	 Instance.new(“Attachment”,rootPart).Name = “AGA”
								charAntiGravity.Force = Vector3.new(0,workspace.Gravity * rootPart.AssemblyMass,0)
								
								local TargetVector = (v.Position - rootPart.Position) - rootPart.AssemblyLinearVelocity
								
								local linearVelocity = Instance.new("LinearVelocity",rootPart)
								linearVelocity.VectorVelocity = TargetVector.Unit * TargetSpeed
								
								 charAntiGravity.Attachment0 = rootPart.AGA
								linearVelocity.Attachment0 = rootPart.AGA
								linearVelocity.MaxAxesForce = TargetVector.Unit * Acceleration

								spawn(function()
									RunService.Heartbeat:Connect(function()
										linearVelocity.VectorVelocity = 										 										 										 										 										TargetVector.Unit * TargetSpeed
										 linearVelocity.MaxAxesForce = TargetVector.Unit * Acceleration

									end)
								end)
							end
						end

At the end, when unragdolling, just remove the “VectorForce”, “AGA” and “LinearVelocity” objects which will be found in the players rootPart

i tried that, unfortunately it didn’t really seem to do anything.

YESS!!! finally! thank you guys so much for your help, i finally figured it out:

						spawn(function()
							if v.Parent == zipPointsFolder or v.Parent == powerUpsFolder then

								brick.Position = v.Position

								-- Manipulate rope constraints directly
								rope1.Length = 0  -- Set rope length to 0 to ensure the player is instantly pulled in
								rope1.Visible = false  -- Make sure the rope is visible

								-- Adjust other parameters if necessary
								rope1.WinchTarget = 0
								rope1.WinchResponsiveness = 200
								rope1.WinchSpeed = 200
								rope1.WinchForce = 5000
								rope1.Restitution = 0

								forceRetractDistance = 30

								if v.Parent == powerUpsFolder then
									rope1.WinchForce = 0
									print('is a power')
									local hitPowerUp = v
									
									local targetPos = v.Position
									local bodyForce = Instance.new("BodyForce")
									
									local direction = (v.Position - char.HumanoidRootPart.Position).unit * 200
									bodyForce.Force = Vector3.new(0,(workspace.Gravity * getModelMass(char)),0)
										
									bodyForce.Parent = torso
									
									spawn(function()
										while grapplerInstances.part ~= nil do
											print(grapplerInstances.part.Name)
											wait()
											local direction = (v.Position - char.HumanoidRootPart.Position).unit * 200
											torso.Velocity = direction * 2
										end
										bodyForce:Destroy()
									end)
								end
							end
							rope1.Enabled = true
							repeat
								wait()
								springConstraintEffect.Coils -= 0.2
								springConstraintEffect.Radius -= 0.1
							until springConstraintEffect.Coils <= 0 and springConstraintEffect.Radius <= 0
							wait(0.1)
							springConstraintEffect:Destroy()
							rope1.Visible = true
						end)

it’s kind of a cheap trick, but at least it works. thanks again, especially @theseformasentence !!

1 Like

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