For this script for Roblox Studio, all I want now is for the leftfoot target and rightfoot target to be visible so each player sees each other's foot targets: -- Enhanced R6 IK with Wall Walking Physics
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
-- Configuration
local FOOT_HEIGHT_OFFSET = 0.3
local MAX_STEP_HEIGHT = 0.4
local STEP_SPEED = 11
local FOOT_DISTANCE = 1.5
local FOOT_WIDTH = 1.5
local ARM_SWING_AMOUNT = 10
local LEG_LERP_SPEED = 20.0
local ARM_LERP_SPEED = 15.0
local MOVE_SPEED = 18
local TURN_SPEED = 43
local GROUND_CHECK_DISTANCE = 0.5
local REQUIRED_GROUND_ANGLE = math.rad(45)
local CLIMB_CHECK_DISTANCE = 3.0
local JUMP_POWER = 10
local JUMP_BOUNCE = 10
local ANCHOR_DELAY = 0
local ARM_ANCHOR_HEIGHT = 0.5
local CLIMB_GRAB_DISTANCE = 5
local CLIMB_PULL_FORCE = 5
local SPIDER_LEG_SPREAD = 5
-- Wall Walking Physics
local WALL_WALK_GRAVITY = 1
local WALL_JUMP_FORCE = 10
local WALL_STICK_FORCE = 300
local CAMERA_LERP_SPEED = 0
local MAX_WALL_ANGLE = math.rad(45)
local WALL_CHECK_DISTANCE = 5
-- Services
local Players = game:GetService("Players")
local Camera = workspace.CurrentCamera
-- Create shared folders for all players to see
local sharedIKFolder = Instance.new("Folder")
sharedIKFolder.Name = "SharedIKTargets"
sharedIKFolder.Parent = workspace
-- Persistent arm storage
local armTargetsFolder = Instance.new("Folder")
armTargetsFolder.Name = "IKArmTargets"
armTargetsFolder.Parent = workspace
-- Get character
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
-- Wall Walking State
local currentWallNormal = Vector3.new(0, 1, 0)
local isWallWalking = false
local lastWallNormal = Vector3.new(0, 1, 0)
-- Function to create or get arm targets with collision
local function ensureArmTargets()
local leftArmTarget = armTargetsFolder:FindFirstChild("LeftArmIKTarget")
local rightArmTarget = armTargetsFolder:FindFirstChild("RightArmIKTarget")
if not leftArmTarget then
leftArmTarget = Instance.new("Part")
leftArmTarget.Name = "LeftArmIKTarget"
leftArmTarget.Anchored = true
leftArmTarget.CanCollide = false
leftArmTarget.Transparency = 0.5
leftArmTarget.Color = Color3.fromRGB(255, 0, 0)
leftArmTarget.Size = Vector3.new(1, 1, 1)
leftArmTarget.Parent = armTargetsFolder
local collision = Instance.new("BallSocketConstraint")
collision.Parent = leftArmTarget
end
if not rightArmTarget then
rightArmTarget = leftArmTarget:Clone()
rightArmTarget.Name = "RightArmIKTarget"
rightArmTarget.Color = Color3.fromRGB(0, 0, 255)
rightArmTarget.Parent = armTargetsFolder
end
return leftArmTarget, rightArmTarget
end
-- Function to setup character parts with shared foot targets
local function setupCharacterParts()
local leftLeg = character:FindFirstChild("Left Leg")
local rightLeg = character:FindFirstChild("Right Leg")
local leftArm = character:FindFirstChild("Left Arm")
local rightArm = character:FindFirstChild("Right Arm")
-- Create foot targets in shared folder if they don't exist
local playerFootFolder = sharedIKFolder:FindFirstChild(player.Name)
if not playerFootFolder then
playerFootFolder = Instance.new("Folder")
playerFootFolder.Name = player.Name
playerFootFolder.Parent = sharedIKFolder
end
if not playerFootFolder:FindFirstChild("LeftFootIKTarget") then
local leftFootTarget = Instance.new("Part")
leftFootTarget.Name = "LeftFootIKTarget"
leftFootTarget.Anchored = true
leftFootTarget.CanCollide = false
leftFootTarget.Transparency = 0
leftFootTarget.Color = Color3.fromRGB(0, 255, 0)
leftFootTarget.Size = Vector3.new(1, 1, 2.45)
leftFootTarget.Parent = playerFootFolder
end
if not playerFootFolder:FindFirstChild("RightFootIKTarget") then
local rightFootTarget = playerFootFolder.LeftFootIKTarget:Clone()
rightFootTarget.Name = "RightFootIKTarget"
rightFootTarget.Parent = playerFootFolder
end
return leftLeg, rightLeg, leftArm, rightArm, playerFootFolder
end
local leftLeg, rightLeg, leftArm, rightArm, playerFootFolder = setupCharacterParts()
local leftArmTarget, rightArmTarget = ensureArmTargets()
-- Movement state
local moveDir = Vector3.new()
local turnDir = 0
local isMoving = false
local isJumping = false
local isClimbing = false
local lastMoveTime = 0
local lastGroundTime = 0
local anchorFeet = false
local anchorArms = false
-- Limb states
local limbs = {
leftFoot = { currentPos = Vector3.new(), targetPos = Vector3.new(), stepProgress = 0, moving = false },
rightFoot = { currentPos = Vector3.new(), targetPos = Vector3.new(), stepProgress = 0, moving = false },
leftArm = { swingPhase = 0, swingDir = 1, anchorProgress = 0, isGrabbing = false },
rightArm = { swingPhase = math.pi, swingDir = -1, anchorProgress = 0, isGrabbing = false }
}
-- Raycast setup
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = {character}
rayParams.FilterType = Enum.RaycastFilterType.Exclude
-- Helper functions
local function lerp(a, b, t) return a + (b - a) * math.clamp(t, 0, 1) end
local function findGround(position)
local origin = position + Vector3.new(0, 2, 0)
local ray = workspace:Raycast(origin, Vector3.new(0, -GROUND_CHECK_DISTANCE, 0), rayParams)
if ray and math.acos(ray.Normal:Dot(Vector3.new(0, 1, 0))) < REQUIRED_GROUND_ANGLE then
lastGroundTime = os.clock()
return ray.Position + Vector3.new(0, FOOT_HEIGHT_OFFSET, 0), ray.Normal
end
return position - Vector3.new(0, GROUND_CHECK_DISTANCE - FOOT_HEIGHT_OFFSET, 0), Vector3.new(0, 1, 0)
end
-- Wall detection similar to referenced asset
local function checkForWalls()
local origin = rootPart.Position
local params = RaycastParams.new()
params.FilterDescendantsInstances = {character}
params.FilterType = Enum.RaycastFilterType.Exclude
-- Check in multiple directions for walls
local directions = {
rootPart.CFrame.LookVector,
-rootPart.CFrame.LookVector,
rootPart.CFrame.RightVector,
-rootPart.CFrame.RightVector
}
for _, dir in ipairs(directions) do
local ray = workspace:Raycast(origin, dir * WALL_CHECK_DISTANCE, params)
if ray and ray.Instance.CanCollide then
local angle = math.acos(ray.Normal:Dot(Vector3.new(0, 1, 0)))
if angle > MAX_WALL_ANGLE then
return ray.Position, ray.Normal
end
end
end
return nil
end
-- Enhanced spider-like climbing detection
local function findClimbSurface(armPosition, direction)
local origin = armPosition
local ray = workspace:Raycast(origin, direction.Unit * CLIMB_GRAB_DISTANCE, rayParams)
if ray and ray.Instance.CanCollide then
local angle = math.acos(ray.Normal:Dot(Vector3.new(0, 1, 0)))
if angle > math.rad(20) and angle < math.rad(160) then
return ray.Position, ray.Normal
end
end
return nil
end
-- Foot movement
local function updateFoot(dt, state, otherState, targetPart, offset)
local rootPos = rootPart.Position
local rootCF = rootPart.CFrame
local desiredPos = rootPos + rootCF:VectorToWorldSpace(offset)
state.targetPos = findGround(desiredPos)
local dist = (state.targetPos - state.currentPos).Magnitude
if dist > 0.5 and not state.moving and not otherState.moving and not anchorFeet then
state.moving = true
state.stepProgress = 0
end
if state.moving then
state.stepProgress = state.stepProgress + dt * STEP_SPEED
if state.stepProgress >= 1 then
state.currentPos = state.targetPos
state.moving = false
else
local t = state.stepProgress
local height = math.sin(t * math.pi) * MAX_STEP_HEIGHT
local mid = (state.currentPos + state.targetPos) * 0.5 + Vector3.new(0, height, 0)
state.currentPos = lerp(lerp(state.currentPos, mid, t), lerp(mid, state.targetPos, t), t)
end
end
targetPart.CFrame = CFrame.new(state.currentPos) * CFrame.Angles(math.rad(-90), 0, 0)
end
-- Enhanced spider-like arm movement with climbing and camera adjustment
local function updateArm(dt, state, side, targetPart, arm)
local rootPos = rootPart.Position
local rootCF = rootPart.CFrame
-- Check for climbable surfaces
if isMoving and not isJumping then
local armOffset = Vector3.new(side * SPIDER_LEG_SPREAD, 0, 0)
local armWorldPos = rootPos + rootCF:VectorToWorldSpace(armOffset)
local lookDir = rootCF.LookVector
local climbPos, climbNormal = findClimbSurface(armWorldPos, lookDir)
if climbPos then
state.isGrabbing = true
state.climbPos = climbPos
state.climbNormal = climbNormal
isClimbing = true
else
state.isGrabbing = false
isClimbing = limbs.leftArm.isGrabbing or limbs.rightArm.isGrabbing
end
else
state.isGrabbing = false
isClimbing = false
end
if state.isGrabbing then
-- Spider climbing behavior
local grabPos = state.climbPos + (state.climbNormal * 0.3)
local armRot = CFrame.lookAt(grabPos, grabPos + state.climbNormal)
targetPart.CFrame = armRot * CFrame.Angles(math.rad(90), 0, 0)
-- Apply climbing pull force
if isMoving then
local alongWall = rootCF.RightVector:Dot(state.climbNormal) * state.climbNormal
local moveDirection = (rootCF.LookVector - alongWall).Unit
rootPart.Velocity = moveDirection * MOVE_SPEED + (state.climbNormal * CLIMB_PULL_FORCE)
end
else
-- Normal arm movement
if not isMoving and not isJumping then
state.anchorProgress = math.min(state.anchorProgress + dt * 2, 1)
else
state.anchorProgress = math.max(state.anchorProgress - dt * 3, 0)
end
if state.anchorProgress > 0 then
-- Anchored arm position
local anchorOffset = Vector3.new(side * 1.5, -ARM_ANCHOR_HEIGHT * state.anchorProgress, 0)
local armPos = rootPos + rootCF:VectorToWorldSpace(anchorOffset)
local armRot = CFrame.Angles(math.rad(-20), 0, math.rad(side * -10))
targetPart.CFrame = CFrame.new(armPos) * armRot
else
-- Normal swinging behavior
if isMoving then
state.swingPhase = state.swingPhase + dt * 5 * state.swingDir
else
state.swingPhase = lerp(state.swingPhase, side == 1 and math.pi or 0, dt * 2)
end
local armOffset = Vector3.new(side * 1.5, 0.5, 0)
local swingOffset = Vector3.new(0, 0, math.sin(state.swingPhase) * ARM_SWING_AMOUNT)
local armPos = rootPos + rootCF:VectorToWorldSpace(armOffset + swingOffset)
local armRot = CFrame.Angles(math.rad(-20), 0, math.rad(side * -10))
targetPart.CFrame = CFrame.new(armPos) * armRot
end
end
-- Apply to actual arm with collision
if arm then
arm.CFrame = arm.CFrame:Lerp(targetPart.CFrame, dt * ARM_LERP_SPEED)
arm.CanCollide = state.isGrabbing
end
end
-- Wall walking physics update
local function updateWallWalking(dt)
local wallPos, wallNormal = checkForWalls()
if wallNormal then
-- Calculate new up vector based on wall normal
local newUp = -wallNormal
local newRight = rootPart.CFrame.RightVector - (rootPart.CFrame.RightVector:Dot(newUp)) * newUp
local newLook = newUp:Cross(newRight).Unit
-- Smoothly transition to wall orientation
currentWallNormal = lerp(currentWallNormal, newUp, dt * 5)
-- Apply wall stick force
rootPart.Velocity = rootPart.Velocity + (currentWallNormal * WALL_STICK_FORCE * dt)
-- Adjust gravity
Workspace.Gravity = WALL_WALK_GRAVITY
-- Rotate character to match wall
rootPart.CFrame = CFrame.new(rootPart.Position, rootPart.Position + newLook) * CFrame.fromMatrix(Vector3.new(), newRight, newUp, newLook)
-- Adjust camera
local camCF = Camera.CFrame
local newCamLook = camCF.LookVector - (camCF.LookVector:Dot(currentWallNormal)) * currentWallNormal
Camera.CFrame = CFrame.new(camCF.Position, camCF.Position + newCamLook)
isWallWalking = true
lastWallNormal = wallNormal
else
-- Return to normal gravity
Workspace.Gravity = 196.2
isWallWalking = false
end
end
-- Movement handling
local function updateMovement(dt)
local now = os.clock()
local wasMoving = isMoving
isMoving = moveDir.Magnitude > 0
if isMoving then
lastMoveTime = now
anchorFeet = false
if turnDir ~= 0 and moveDir.Z == 0 then
humanoid.AutoRotate = false
rootPart.CFrame = rootPart.CFrame * CFrame.Angles(0, turnDir * TURN_SPEED * dt, 0)
else
humanoid.AutoRotate = true
end
local moveVector = rootPart.CFrame:VectorToWorldSpace(moveDir) * MOVE_SPEED
if not isClimbing and not isWallWalking then
rootPart.Velocity = Vector3.new(moveVector.X, rootPart.Velocity.Y, moveVector.Z)
end
else
humanoid.AutoRotate = true
if wasMoving and now - lastMoveTime > ANCHOR_DELAY then
anchorFeet = true
end
if not isJumping and rootPart.Velocity.Y > -5 then
rootPart.Velocity = Vector3.new(0, rootPart.Velocity.Y, 0)
end
end
end
-- Enhanced jump with wall jump
local function handleJump()
if isJumping then return end
if isWallWalking then
-- Wall jump
isJumping = true
local jumpDir = (rootPart.CFrame.LookVector + lastWallNormal).Unit
rootPart.Velocity = jumpDir * WALL_JUMP_FORCE
isWallWalking = false
delay(0.5, function()
isJumping = false
end)
else
-- Normal jump
local groundPos = findGround(rootPart.Position)
if (os.clock() - lastGroundTime) < 0.1 then
isJumping = true
rootPart.Velocity = Vector3.new(rootPart.Velocity.X, JUMP_POWER, rootPart.Velocity.Z)
leftLeg.CFrame = leftLeg.CFrame * CFrame.new(0, -JUMP_BOUNCE, 0)
rightLeg.CFrame = rightLeg.CFrame * CFrame.new(0, -JUMP_BOUNCE, 0)
delay(0.5, function()
isJumping = false
end)
end
end
end
-- Main update
local function update(dt)
if not rootPart or not rootPart.Parent then return end
updateMovement(dt)
updateWallWalking(dt)
local moveOffset = Vector3.new(moveDir.X * FOOT_DISTANCE, 0, moveDir.Z * FOOT_DISTANCE)
if not isJumping then
updateFoot(dt, limbs.leftFoot, limbs.rightFoot, playerFootFolder.LeftFootIKTarget,
Vector3.new(-FOOT_WIDTH, 0, -FOOT_DISTANCE/2) + moveOffset)
updateFoot(dt, limbs.rightFoot, limbs.leftFoot, playerFootFolder.RightFootIKTarget,
Vector3.new(FOOT_WIDTH, 0, -FOOT_DISTANCE/2) + moveOffset)
end
updateArm(dt, limbs.leftArm, -1, leftArmTarget, leftArm)
updateArm(dt, limbs.rightArm, 1, rightArmTarget, rightArm)
if not isJumping then
leftLeg.CFrame = leftLeg.CFrame:Lerp(CFrame.new(limbs.leftFoot.currentPos), dt * LEG_LERP_SPEED)
rightLeg.CFrame = rightLeg.CFrame:Lerp(CFrame.new(limbs.rightFoot.currentPos), dt * LEG_LERP_SPEED)
end
end
-- Input handling
UserInputService.InputBegan:Connect(function(input)
if input.KeyCode == Enum.KeyCode.W then moveDir = Vector3.new(0, 0, -1)
elseif input.KeyCode == Enum.KeyCode.S then moveDir = Vector3.new(0, 0, 1)
elseif input.KeyCode == Enum.KeyCode.A then
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) then
turnDir = -1
else
moveDir = Vector3.new(-1, 0, 0)
end
elseif input.KeyCode == Enum.KeyCode.D then
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) then
turnDir = 1
else
moveDir = Vector3.new(1, 0, 0)
end
elseif input.KeyCode == Enum.KeyCode.Space then
handleJump()
end
end)
UserInputService.InputEnded:Connect(function(input)
if input.KeyCode == Enum.KeyCode.W or input.KeyCode == Enum.KeyCode.S then
if moveDir.Z ~= 0 then moveDir = Vector3.new(moveDir.X, 0, 0) end
elseif input.KeyCode == Enum.KeyCode.A or input.KeyCode == Enum.KeyCode.D then
if moveDir.X ~= 0 then moveDir = Vector3.new(0, 0, moveDir.Z) end
turnDir = 0
end
end)
-- Initialize
local function init()
-- Re-get character parts in case of reset
leftLeg, rightLeg, leftArm, rightArm, playerFootFolder = setupCharacterParts()
local rootPos = rootPart.Position
local rootCF = rootPart.CFrame
limbs.leftFoot.currentPos = findGround(rootPos + rootCF:VectorToWorldSpace(Vector3.new(-FOOT_WIDTH, 0, 0)))
limbs.rightFoot.currentPos = findGround(rootPos + rootCF:VectorToWorldSpace(Vector3.new(FOOT_WIDTH, 0, 0)))
playerFootFolder.LeftFootIKTarget.CFrame = CFrame.new(limbs.leftFoot.currentPos) * CFrame.Angles(math.rad(-90), 0, 0)
playerFootFolder.RightFootIKTarget.CFrame = CFrame.new(limbs.rightFoot.currentPos) * CFrame.Angles(math.rad(-90), 0, 0)
if leftArm and rightArm then
leftArmTarget.CFrame = CFrame.new(rootPos + rootCF:VectorToWorldSpace(Vector3.new(-1.5, 0.5, 0))) * CFrame.Angles(math.rad(-20), 0, math.rad(10))
rightArmTarget.CFrame = CFrame.new(rootPos + rootCF:VectorToWorldSpace(Vector3.new(1.5, 0.5, 0))) * CFrame.Angles(math.rad(-20), 0, math.rad(-10))
end
end
-- Handle character reset
player.CharacterAdded:Connect(function(newCharacter)
character = newCharacter
humanoid = character:WaitForChild("Humanoid")
rootPart = character:WaitForChild("HumanoidRootPart")
leftLeg, rightLeg, leftArm, rightArm, playerFootFolder = setupCharacterParts()
-- Reinitialize with existing arm targets
init()
end)
init()
RunService.Heartbeat:Connect(update)
print("Enhanced R6 IK with Wall Walking Physics Active")