Ever wanted to make a realistic swing set or a rope swing? Well I made a rope swing check this out!
Then grab yourself a copy of the model in this place!
Rope Swing Tech Demo - Roblox
There is a custom animation located in the R15 rig to perform the rope swinging animation.
The rope object is made of spheres and ropes, the player touches a sphere grabs on to it and allows you to swing on the rope.
Since creating this I upgraded it to a ropeswing service architecture where the model is tagged as a “RopeModel” and the ropes are formatted and individual ropes can be connected by tagging them as “RopeSwing”
This is another Tech Demo in my series of generally useful Open Sourced tech demos. I make these for my own project on a blank baseplate and if they are useful I post them here! That being said you can check out my profile Topics for more Tech Demos and Resources!
Great for those levels where you want to clear a gap!
What’s unique about these rope swings are that they allow you to gain momentum by swinging back and forth on the rope without any invasive modifications of the Character.
Made to Swing from Rope to Rope*
I made this model to appropriately clear this gap! But using it for something like vine swinging works too
What kind of tech is used?
For this we are exploiting the behavior of falling in a direction. When your character is connected to a rope you can control your swing direction using movement controls. Align Orientation is currently being used in addition to Motor6D Welding to object space, and an animation to present the character on the rope. Besides that some debounce mechanism.
Create Varying Ropes
Located in a module called RopeCreator in the workspace
which provides functions to generate perfect chains of ropes of whatever length and fidelity you choose!
These are different than regular ropes because they are like chains of ropes with ball shaped joints.
With the algorithm to generate ropes you can control the fidelity of the rope, more joints= more realistic rope.
The source code is as follows. There are some comments in this code since I’ve been experimenting with different things.
local ropes={}
local function weldmotor(Root1,Root2)
local w=Instance.new("Motor6D")
w.Part0,w.Part1 = Root1,Root2
w.C0 = Root2.CFrame:toObjectSpace(Root1.CFrame):inverse()
w.Parent = Root1
w.Name=Root2.Name.."Joint"
return w
end
task.wait()
local climbanim=script.RopeSwing
--for i,v in script.Parent:GetChildren() do
local function formatrope(v)
if v.ClassName=="Part" and v:FindFirstChildOfClass("Attachment") and v.Anchored==false then
local connection=v.Touched:Connect(function(hit)
local hum= hit.Parent:FindFirstChild("Humanoid")
if hum and ropes[hum.DisplayName]==nil then
local key= v.Parent.ClassName=="Model" and v.Parent.PrimaryPart~=nil and tostring(v.Parent.PrimaryPart.Position)..hum.DisplayName or nil
local currentmodel=key~=nil and ropes[key]==nil or true
print(ropes[key])
print(key)
if currentmodel and (key==nil or ropes[key]==nil) then
if key then
ropes[key]=true
end
v.CanTouch=false
v.CanCollide=false
local climb=hum:LoadAnimation(climbanim)
climb:Play()
hum.AutoRotate=false
local lostconnection=nil
ropes[hum.DisplayName]=true
local hand=hit.Parent:FindFirstChild("HumanoidRootPart")
v.Anchored=true
hand.Anchored=true
local swingdirection=(hand.CFrame.Position-hand.CFrame:ToWorldSpace(CFrame.new(0,0,-60)).Position)
local rope=v:FindFirstChildOfClass("RopeConstraint")
local c=nil
for t,o in v.Parent:GetChildren() do
if o.ClassName=="Part" then
o.AssemblyLinearVelocity*=.2
end
end
if rope then
c=Instance.new("AlignOrientation")
local orientation=CFrame.new(rope.Attachment1.Parent.CFrame.Position,rope.Attachment0.Parent.CFrame.Position)-rope.Attachment1.Parent.CFrame.Position
c.Attachment0=hand:FindFirstChild("RootAttachment")
c.Attachment1=rope.Attachment0
c.Parent=hand
--while (hand.Parent and motor.Parent and rope.Parent) do
-- --local orientation=CFrame.new(rope.Attachment0.Parent.CFrame.Position,rope.Attachment1.Parent.CFrame.Position)-rope.Attachment1.Parent.CFrame.Position+hand.Position
-- local orientation=CFrame.new(hand.Position,v.Parent.PrimaryPart.Position)
-- c.CFrame=orientation
-- task.wait()
--end
end
hand.CFrame=v.CFrame:ToWorldSpace(CFrame.new(0,-1,0))
local motor= weldmotor(v,hand)
hand.AssemblyLinearVelocity=swingdirection
local speed=hum.WalkSpeed
hum.WalkSpeed=48
v.Anchored=false
hand.Anchored=false
--v.AssemblyLinearVelocity*=2
lostconnection=hum.AncestryChanged:Once(function()
ropes[hum.DisplayName]=nil
v.CanTouch=true
--v.CanCollide=true
end)
--hum:ChangeState(Enum.HumanoidStateType.Flying)
hum:GetPropertyChangedSignal("Jump"):Once(function()
if lostconnection then
lostconnection:Disconnect()
end
motor:Destroy()
climb:Stop()
climb:Destroy()
if c then
c:Destroy()
end
for t,o in v.Parent:GetChildren() do
if o.ClassName=="Part" then
o.AssemblyLinearVelocity*=.2
end
end
hum.AutoRotate=true
hum.WalkSpeed=speed
--hand.AssemblyLinearVelocity=(hand.CFrame.Position-hand.CFrame:ToWorldSpace(CFrame.new(0,10,-20)).Position)
--c:Destroy()
ropes[hum.DisplayName]=nil
task.wait(.1)
hum:ChangeState(Enum.HumanoidStateType.Jumping)
task.wait(.1)
hum:ChangeState(Enum.HumanoidStateType.Jumping)
task.wait(2)
if key then
ropes[key]=nil
end
v.CanTouch=true
v.CanCollide=true
end)
--hum.Jumping:Once(function()
--end)
end
end
end)
return connection
--table.insert(ropes,v)
end
end
local function formatropemodel(m)
local modelconnections={}
for i,v in m:GetChildren() do
local connection=formatrope(v)
if connection then
table.insert(modelconnections,connection)
end
end
return modelconnections
end
local function disconnectconnections(array)
for i,v in array do
v:Disconnect()
end
end
game.CollectionService:GetInstanceAddedSignal("RopeModel"):Connect(formatropemodel)
print(game.CollectionService:GetTagged("RopeModel") )
for i,m in game.CollectionService:GetTagged("RopeModel") do
local modelconnections=formatropemodel(m)
--print("Connecting model")
m.AncestryChanged:Once(function()
--print("Disconnecting")
disconnectconnections(modelconnections)
modelconnections=nil
end)
end
game.CollectionService:GetInstanceAddedSignal("RopeSwing"):Connect(formatrope)
for i,v in game.CollectionService:GetTagged("RopeSwing") do
local connection=formatrope(v)
if connection then
connection={connection}
v.AncestryChanged:Once(function()
disconnectconnections(connection)
connection=nil
end)
end
end
RopeCreator Module
local function getprimitive()
local primitive=Instance.new("Part")
primitive.Shape=Enum.PartType.Ball
primitive.Size=Vector3.new(.25,.25,.25)
local attachment=Instance.new("Attachment")
attachment.Parent=primitive
return primitive,attachment
end
local function formatrope(primitive,attachment,previous)
local rope=Instance.new("RopeConstraint")
rope.Color=BrickColor.new("Dark taupe")
rope.Parent=primitive
rope.Attachment0=previous
rope.Thickness=.25
rope.Visible=true
rope.Attachment1=attachment
return rope
end
local function createrope(cframe,length,fidelity)
local model=Instance.new("Model")
local previous=nil
local fidelity=math.max(.125,fidelity or 3)
local ropescale= math.floor(length/fidelity+.5)
local densityscale=math.log(length)
local maxdensity=30*densityscale
local mindensity=15*densityscale
local increment=densityscale*2
for i=0, ropescale do
local primitive,attachment=getprimitive()
primitive.Name="Rope"..i
primitive.Parent=model
if model.PrimaryPart==nil then
model.PrimaryPart=primitive
end
primitive.CustomPhysicalProperties=PhysicalProperties.new(math.max(10,maxdensity-(i*increment)),1,1)
primitive.BrickColor=BrickColor.new("Dark taupe")
primitive.CFrame=cframe:ToWorldSpace(CFrame.new(0,-i*fidelity,0))
if previous then
local rope=formatrope(primitive,attachment,previous)
rope.Length=fidelity
else
primitive.Anchored=true
end
previous=attachment
end
model:AddTag("RopeModel")
model.Name="Rope"
model.Parent=workspace
return model
end
--createrope(CFrame.new(0,27,0),20,3)
--createrope(CFrame.new(0,17,20),10,3)
--createrope(CFrame.new(0,37,40),30,3)
return createrope