Hey, so. All i can say is that I tried, the swinging thing is really difficult to replicate.
Local Script || StarterCharacterScripts
-- Services
local PlayService = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local DebrisService = game:GetService("Debris")
-- Objects
local Player = PlayService.LocalPlayer
local Mouse = Player:GetMouse()
local Character : Model = script.Parent
local Humanoid : Humanoid = Character:WaitForChild("Humanoid")
local Root : BasePart = Character.PrimaryPart or Character:WaitForChild("HumanoidRootPart")
local Camera = workspace.CurrentCamera
local RootAttachment = Root:WaitForChild("RootAttachment")
local EndAttachment = Instance.new("Attachment", Root)
EndAttachment.Name = "SwingerAttachment"
-- Constants
local MAX_GRAPPLE_DISTANCE = 300
local MIN_GRAPPLE_DISTANCE = 30
local GRAPPLE_DELAY = 0.6
local SWING_DELAY = 0.8
local MAX_SWING_DISTANCE = 300
local MIN_SWING_DISTANCE = 5
local ROPE_COLOR = Color3.fromRGB(34,34,34) -- has to be RGB as for current implementation
local GRAPPLE_KEY, SWING_KEY = Enum.KeyCode.F, Enum.KeyCode.E
-- State Variables
local GrappleDown, SwingDown = false, false
local IsGrappling = false
local IsSwinging = false
-- Values
local SpringTweenInfo = TweenInfo.new(0.8, Enum.EasingStyle.Elastic, Enum.EasingDirection.Out, 0, false, 0)
local Params = RaycastParams.new()
Params.FilterDescendantsInstances = {Character}
local SwingRope = nil
local SwingForce = nil
-- Functions
function Lerp(a, b, t)
return a + (b - a) * t
end
function IsDead() : boolean
return Humanoid.Health <= 0
end
function GetForce() : BodyVelocity
local BodyVelocity = Instance.new("BodyVelocity")
BodyVelocity.Name = "APPLIED_FORCE"
return BodyVelocity
end
local Spring = nil
local springConnection = nil
local springTween = nil
function RopeEffect(From: Vector3, To: Vector3, ToObject: BasePart, MakeFinal: boolean?) : RopeConstraint? -- makes the rope effect.
local direction = To - From
local distance = direction.Magnitude
EndAttachment.Parent = ToObject
EndAttachment.WorldPosition = To
Spring = Instance.new("SpringConstraint")
Spring.Color = BrickColor.new(ROPE_COLOR.R/255,ROPE_COLOR.G/255,ROPE_COLOR.B/255)
Spring.Stiffness = 0
Spring.Radius = 0.4
Spring.Coils = 8
Spring.MaxForce = 0
Spring.Damping = 0
Spring.FreeLength = distance
Spring.Visible = false
Spring.Attachment0 = RootAttachment
Spring.Attachment1 = EndAttachment
Spring.Parent = Root
local Rope : RopeConstraint? = nil
if MakeFinal == true then
Rope = Instance.new("RodConstraint", Root)
Rope.Name = "SwingerRope"
Rope.Color = BrickColor.new(ROPE_COLOR.R/255,ROPE_COLOR.G/255,ROPE_COLOR.B/255)
Rope.Length = distance
Rope.Visible = false
Rope.Attachment0 = RootAttachment
Rope.Attachment1 = EndAttachment
end
springTween = TweenService:Create(Spring, SpringTweenInfo, {
Coils = 0,
Radius = 0
})
Spring.Visible = true
springTween:Play()
springConnection = springTween.Completed:Once(function()
Spring:Destroy()
if MakeFinal == true then
Rope.Visible = true
end
end)
return Rope
end
function StopRopeEffect()
if Spring then
Spring:Destroy()
end
if springConnection then
springConnection:Disconnect()
end
if springTween then
springTween:Cancel()
end
end
function Graple() -- Simply pushes the player toward the goal position
if IsGrappling or IsSwinging or IsDead() then return end
local Direction = (Mouse.Hit.Position - Root.Position).Unit
local Raycast = workspace:Raycast(Root.Position, Direction*MAX_GRAPPLE_DISTANCE, Params)
if not Raycast then return end
local To = Raycast.Position
local GrapleDirection = To - Root.Position
local GrapleDistance = GrapleDirection.Magnitude
if GrapleDistance > MAX_GRAPPLE_DISTANCE then
return
elseif GrapleDistance < MIN_GRAPPLE_DISTANCE then
return
end
IsGrappling = true
local GrapleForce = Instance.new("VectorForce", Root)
GrapleForce.Force = Vector3.zero
GrapleForce.Attachment0 = RootAttachment
GrapleForce.RelativeTo = Enum.ActuatorRelativeTo.World
local StrengthFactor = math.abs((GrapleDistance-MIN_GRAPPLE_DISTANCE)/MAX_GRAPPLE_DISTANCE)
local RequiredStrength = Lerp(600,1300, StrengthFactor) * Root.AssemblyMass -- Strength scaling from distance.
GrapleForce.Parent = Root
task.spawn(function()
for count = 10,1,-1 do
GrapleForce.Force = (Direction).Unit * RequiredStrength * (count/10)
task.wait(0.05)
end
GrapleForce.Force = Vector3.zero
StopRopeEffect()
end)
RopeEffect(Root.Position, To, Raycast.Instance, false)
wait(GRAPPLE_DELAY)
IsGrappling = false
end
local swingLength = 0
local swingVelocity = Vector3.new(0, 0, 0)
local swingAnchor = nil
local _debug_part = Instance.new("Part")
_debug_part.Anchored = true
_debug_part.CanCollide = false
_debug_part.CanTouch = false
_debug_part.CanQuery = false
_debug_part.CastShadow = false
_debug_part.Size = Vector3.one
_debug_part.BrickColor = BrickColor.Green()
_debug_part.Transparency = 0.3
function StartSwing()
if IsGrappling or IsSwinging or IsDead() then return end
local Direction = (Mouse.Hit.Position - Root.Position).Unit
local Raycast = workspace:Raycast(Root.Position, Direction * MAX_SWING_DISTANCE, Params)
if not Raycast then return end
local To = Raycast.Position
local Target = Raycast.Instance
swingLength = (To - Root.Position).Magnitude
if swingLength > MAX_SWING_DISTANCE or swingLength < MIN_SWING_DISTANCE then return end
IsSwinging = true
swingAnchor = To
swingVelocity = Root.AssemblyLinearVelocity * 0.8 -- Preserve some momentum from before swing
SwingRope = RopeEffect(Root.Position, To, Target, true)
for _, child in pairs(Root:GetChildren()) do
if child:IsA("BodyForce") or child:IsA("VectorForce") and child.Name == "SwingForce" then
child:Destroy()
end
end
SwingForce = Instance.new("VectorForce", Root)
SwingForce.Name = "SwingForce"
SwingForce.Force = Vector3.zero
SwingForce.Attachment0 = RootAttachment
SwingForce.RelativeTo = Enum.ActuatorRelativeTo.World
_debug_part.Parent = workspace
_debug_part.Position = swingAnchor
local existingForce = Root:FindFirstChild("GravityForce")
if not existingForce then
local gravityForce = Instance.new("VectorForce", Root)
gravityForce.Name = "GravityForce"
gravityForce.Force = Vector3.new(0, -Root.AssemblyMass * workspace.Gravity, 0)
gravityForce.Attachment0 = RootAttachment
gravityForce.RelativeTo = Enum.ActuatorRelativeTo.World
end
end
local SWING_GRAVITY = workspace.Gravity
local SWING_DAMPING = 1
local SWING_INPUT_FORCE = 15
local SWING_MAX_VELOCITY = 120
local SWING_AIR_RESISTANCE = 1
function UpdateSwing(delta)
if not IsSwinging or not swingAnchor then return end
local toAnchor = swingAnchor - Root.Position
local distance = toAnchor.Magnitude
local normalizedToAnchor = toAnchor.Unit
local gravityForce = Vector3.new(0, -SWING_GRAVITY * Root.AssemblyMass, 0)
local velocity = Root.AssemblyLinearVelocity
local tangentDir = (velocity - velocity:Dot(normalizedToAnchor) * normalizedToAnchor).Unit
local normalDir = normalizedToAnchor
local tangentSpeed = (velocity - velocity:Dot(normalizedToAnchor) * normalizedToAnchor).Magnitude
local centripetalForce = (tangentSpeed * tangentSpeed / swingLength) * Root.AssemblyMass
local moveDir = Humanoid.MoveDirection
local inputForce = Vector3.new(moveDir.X, 0, moveDir.Z) * SWING_INPUT_FORCE * Root.AssemblyMass
local totalForce = gravityForce + normalDir * centripetalForce + inputForce
SwingForce.Force = totalForce
Root.AssemblyLinearVelocity = Root.AssemblyLinearVelocity * SWING_AIR_RESISTANCE
if Root.AssemblyLinearVelocity.Magnitude > SWING_MAX_VELOCITY then
Root.AssemblyLinearVelocity = Root.AssemblyLinearVelocity.Unit * SWING_MAX_VELOCITY
end
if moveDir.Magnitude < 0.1 then
Root.AssemblyLinearVelocity = Root.AssemblyLinearVelocity * SWING_DAMPING
end
end
function StopSwing()
IsSwinging = false
swingAnchor = nil
_debug_part.Parent = nil
StopRopeEffect()
if SwingRope then
SwingRope:Destroy()
end
if SwingForce then
SwingForce:Destroy()
end
local gravityForce = Root:FindFirstChild("GravityForce")
if gravityForce then
gravityForce:Destroy()
end
StopRopeEffect()
local currentVelocity = Root.AssemblyLinearVelocity
Root.AssemblyLinearVelocity = Vector3.new(currentVelocity.X * 0.8, currentVelocity.Y * 0.3, currentVelocity.Z * 0.8)
end
-- Connections
UserInputService.InputBegan:Connect(function(Input, Typing)
if Typing then return end
if Input.KeyCode == GRAPPLE_KEY then
GrappleDown = true
Graple()
elseif Input.KeyCode == SWING_KEY then
SwingDown = true
StartSwing()
end
end)
UserInputService.InputEnded:Connect(function(Input, Typing)
if Typing then return end
if Input.KeyCode == GRAPPLE_KEY then
GrappleDown = false
elseif Input.KeyCode == SWING_KEY then
SwingDown = false
StopSwing()
end
end)
RunService.Heartbeat:Connect(function(delta)
if IsSwinging then
UpdateSwing(delta)
if SwingRope and swingAnchor then
SwingRope.Attachment1.WorldPosition = swingAnchor
SwingRope.Length = (Root.Position - swingAnchor).Magnitude
end
end
end)