Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- hai :3
- --// Services
- local UserInputService = game:GetService("UserInputService")
- local ContextActionService = game:GetService("ContextActionService")
- local RunService = game:GetService("RunService")
- local Players = game:GetService("Players")
- --// Player and Character
- local player = Players.LocalPlayer
- local character = player.Character or player.CharacterAdded:Wait()
- local humanoid = character:WaitForChild("Humanoid")
- local rootPart = character:WaitForChild("HumanoidRootPart")
- --// Configuration
- local SWING_FORCE = 50
- local JUMP_BOOST = 50
- --// State Management
- local GrapplingHook = {}
- GrapplingHook.__index = GrapplingHook
- function GrapplingHook.new()
- local self = setmetatable({}, GrapplingHook)
- self.state = "Idle"
- self.hookPart = nil
- self.beam = nil
- self.attachment0 = nil
- self.attachment1 = nil
- self.alignPosition = nil
- self.alignOrientation = nil
- return self
- end
- function GrapplingHook:setState(newState)
- if self.state == newState then return end
- print("Grappling Hook State:", newState)
- self.state = newState
- end
- --// Grappling Hook Instance
- local hook = GrapplingHook.new()
- --// Creating hook visual :P
- function createHookPart()
- local part = Instance.new("Part")
- part.Size = Vector3.new(1, 1, 1)
- part.BrickColor = BrickColor.new("Gray")
- part.Material = Enum.Material.Metal
- part.Anchored = true
- part.CanCollide = false
- part.Name = "HookPart"
- part.Parent = workspace
- return part
- end
- --// Fire the grappling hook
- function fireHook()
- if hook.state ~= "Idle" then return end
- local mouse = player:GetMouse()
- local targetPosition = mouse.Hit.p
- local originPosition = rootPart.Position
- local direction = (targetPosition - originPosition).Unit * 10000
- local raycastParams = RaycastParams.new()
- raycastParams.FilterDescendantsInstances = {character}
- raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
- local raycastResult = workspace:Raycast(originPosition, direction, raycastParams)
- if not raycastResult or not raycastResult.Instance then
- return
- end
- hook:setState("Attached")
- hook.hookPart = createHookPart()
- hook.hookPart.Position = raycastResult.Position
- -- Create attachments
- hook.attachment0 = Instance.new("Attachment", rootPart)
- hook.attachment1 = Instance.new("Attachment", hook.hookPart)
- -- Create the beam but start it as disabled
- hook.beam = Instance.new("Beam")
- hook.beam.Enabled = false
- -- Assign attachments and visual properties
- hook.beam.Attachment0 = hook.attachment0
- hook.beam.Attachment1 = hook.attachment1
- hook.beam.Color = ColorSequence.new(Color3.new(0.8, 0.8, 0.8))
- hook.beam.FaceCamera = true
- hook.beam.Width0 = 0.1
- hook.beam.Width1 = 0.1
- hook.beam.Parent = hook.hookPart
- hook.beam.Enabled = true
- attachPlayer()
- end
- --// Attach the player and start swinging around :D
- function attachPlayer()
- if hook.state ~= "Attached" then return end
- hook:setState("Swinging")
- humanoid.Sit = true -- must be a rock to simple not jump on the platform
- -- Physics constraints for swinging
- hook.alignPosition = Instance.new("AlignPosition")
- hook.alignPosition.Attachment0 = hook.attachment0
- hook.alignPosition.Attachment1 = hook.attachment1
- hook.alignPosition.Responsiveness = 20
- hook.alignPosition.Parent = rootPart
- hook.alignOrientation = Instance.new("AlignOrientation")
- hook.alignOrientation.Attachment0 = hook.attachment0
- hook.alignOrientation.Attachment1 = hook.attachment1
- hook.alignOrientation.Responsiveness = 10
- hook.alignOrientation.Parent = rootPart
- end
- --// Handle player input for swinging
- function onUpdate(dt)
- if hook.state ~= "Swinging" then return end
- local moveDirection = humanoid.MoveDirection
- if moveDirection.Magnitude > 0 then
- local force = rootPart.CFrame:VectorToWorldSpace(moveDirection) * SWING_FORCE
- rootPart:ApplyImpulse(force)
- end
- end
- --// Release the grappling hook
- function releaseHook()
- if hook.state == "Idle" then return end
- if hook.state == "Swinging" then
- local jumpForce = rootPart.CFrame.UpVector * JUMP_BOOST
- rootPart.Velocity = rootPart.Velocity + jumpForce
- end
- cleanup()
- end
- --// Cleanup resources
- function cleanup()
- hook:setState("Idle")
- if hook.hookPart then
- hook.hookPart:Destroy()
- hook.hookPart = nil
- end
- if hook.beam then
- hook.beam:Destroy()
- hook.beam = nil
- end
- if hook.attachment0 then
- hook.attachment0:Destroy()
- hook.attachment0 = nil
- end
- -- No need to handle attachment1, it gets destroyed with hookPart
- hook.attachment1 = nil
- if hook.alignPosition then
- hook.alignPosition:Destroy()
- hook.alignPosition = nil
- end
- if hook.alignOrientation then
- hook.alignOrientation:Destroy()
- hook.alignOrientation = nil
- end
- humanoid.Sit = false
- end
- --// Input Handling -- THIS FUNCTION ALLOWS THE USER TO JUMP WHEN WALKING AROUND
- function onAction(actionName, inputState, inputObject)
- if actionName == "Grapple" and inputState == Enum.UserInputState.Begin then
- fireHook()
- return Enum.ContextActionResult.Sink -- Prevents mouse click from doing other things
- end
- if actionName == "Release" and inputState == Enum.UserInputState.Begin then
- -- Only release the hook if it's currently active
- if hook.state ~= "Idle" then
- releaseHook()
- -- Sink the input so we don't also do a normal jump
- return Enum.ContextActionResult.Sink
- else
- -- If the hook is idle, pass the input so the default jump can happen
- return Enum.ContextActionResult.Pass
- end
- end
- -- For any other input, let the game handle it normally
- return Enum.ContextActionResult.Pass
- end
- --// Bind actions and update loop
- ContextActionService:BindAction("Grapple", onAction, true, Enum.UserInputType.MouseButton1)
- ContextActionService:BindAction("Release", onAction, true, Enum.KeyCode.Space)
- RunService.Heartbeat:Connect(onUpdate)
- print("Grappling Hook system initialized.")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement