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