local Players = game:GetService("Players") local UserInputService = game:GetService("UserInputService") local RunService = game:GetService("RunService") local TweenService = game:GetService("TweenService") local player = Players.LocalPlayer local character = player.Character or player.CharacterAdded:Wait() local humanoid = character:WaitForChild("Humanoid") local rootPart = character:WaitForChild("HumanoidRootPart") local camera = workspace.CurrentCamera local WALL_STICK_FORCE = 50 local MOVE_SPEED = 16 local JUMP_FORCE = 50 local WALL_CHECK_DISTANCE = 5 local GRAVITY = workspace.Gravity local WEB_SPEED = 100 local WEB_RANGE = 100 local WEB_THICKNESS = 0.2 local WEB_COLOR = Color3.fromRGB(255, 255, 255) local isWallWalking = false local wallNormal = Vector3.new(0, 1, 0) local bodyVelocity = nil local bodyGyro = nil local isWebSwinging = false local function setupBodyVelocity() if not bodyVelocity then bodyVelocity = Instance.new("BodyVelocity") bodyVelocity.MaxForce = Vector3.new(math.huge, math.huge, math.huge) bodyVelocity.Parent = rootPart end bodyVelocity.Velocity = Vector3.new(0, 0, 0) end local function setupBodyGyro() if not bodyGyro then bodyGyro = Instance.new("BodyGyro") bodyGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge) bodyGyro.P = 10000 bodyGyro.Parent = rootPart end end local function stopWallWalking() isWallWalking = false if bodyVelocity then bodyVelocity:Destroy() bodyVelocity = nil end if bodyGyro then bodyGyro:Destroy() bodyGyro = nil end humanoid.PlatformStand = false workspace.Gravity = GRAVITY end local function startWallWalking(normal) isWallWalking = true wallNormal = normal workspace.Gravity = 0 humanoid.PlatformStand = true setupBodyVelocity() setupBodyGyro() end local function checkForWall() local rayOrigin = rootPart.Position local rayDirection = rootPart.CFrame.LookVector * WALL_CHECK_DISTANCE local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = {character} raycastParams.FilterType = Enum.RaycastFilterType.Blacklist local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams) if raycastResult and not isWallWalking and not isWebSwinging then startWallWalking(raycastResult.Normal) end end local function updateWallWalking() if not isWallWalking or isWebSwinging then return end local upVector = -wallNormal local lookVector = rootPart.CFrame.LookVector local rightVector = upVector:Cross(lookVector) local cframe = CFrame.fromMatrix(rootPart.Position, rightVector, upVector, lookVector) bodyGyro.CFrame = cframe local moveDirection = Vector3.new(0, 0, 0) if UserInputService:IsKeyDown(Enum.KeyCode.W) then moveDirection = moveDirection + rootPart.CFrame.LookVector end if UserInputService:IsKeyDown(Enum.KeyCode.S) then moveDirection = moveDirection - rootPart.CFrame.LookVector end if UserInputService:IsKeyDown(Enum.KeyCode.A) then moveDirection = moveDirection - rootPart.CFrame.RightVector end if UserInputService:IsKeyDown(Enum.KeyCode.D) then moveDirection = moveDirection + rootPart.CFrame.RightVector end bodyVelocity.Velocity = moveDirection * MOVE_SPEED + (wallNormal * -WALL_STICK_FORCE) end local function createWebRope(startPos, endPos) local rope = Instance.new("Part") rope.Anchored = true rope.CanCollide = false rope.Material = Enum.Material.Neon rope.Color = WEB_COLOR rope.Parent = workspace local distance = (endPos - startPos).Magnitude rope.Size = Vector3.new(WEB_THICKNESS, WEB_THICKNESS, distance) rope.CFrame = CFrame.new(startPos, endPos) * CFrame.new(0, 0, -distance / 2) local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Linear, Enum.EasingDirection.In) local tween = TweenService:Create(rope, tweenInfo, {Transparency = 1}) tween:Play() tween.Completed:Connect(function() rope:Destroy() end) end local function webSwing() if isWebSwinging or isWallWalking then return end local mouse = player:GetMouse() local rayOrigin = camera.CFrame.Position local rayDirection = (mouse.Hit.Position - rayOrigin).Unit * WEB_RANGE local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = {character} raycastParams.FilterType = Enum.RaycastFilterType.Blacklist local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams) if raycastResult then isWebSwinging = true local targetPos = raycastResult.Position createWebRope(rootPart.Position, targetPos) local direction = (targetPos - rootPart.Position).Unit rootPart.Velocity = direction * WEB_SPEED task.wait(0.5) rootPart.Velocity = Vector3.new(0, 0, 0) isWebSwinging = false end end UserInputService.InputBegan:Connect(function(input, gameProcessedEvent) if gameProcessedEvent then return end if input.KeyCode == Enum.KeyCode.E then webSwing() end end) UserInputService.JumpRequest:Connect(function() if isWallWalking then stopWallWalking() rootPart.Velocity = wallNormal * JUMP_FORCE end end) local function checkWallContact() if isWallWalking then local rayOrigin = rootPart.Position local rayDirection = -wallNormal * WALL_CHECK_DISTANCE local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = {character} raycastParams.FilterType = Enum.RaycastFilterType.Blacklist local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams) if not raycastResult then stopWallWalking() end end end RunService.RenderStepped:Connect(function() checkForWall() updateWallWalking() checkWallContact() end) player.CharacterAdded:Connect(function(newCharacter) character = newCharacter humanoid = character:WaitForChild("Humanoid") rootPart = character:WaitForChild("HumanoidRootPart") stopWallWalking() isWebSwinging = false end)