Run it
Copy the script and paste it into your executor.
Players = :()
UserInputService = :()
RunService = :()
CollectionService = :()
player = Players.LocalPlayer
camera = .CurrentCamera
WALL_WALK_ENABLED =
TOGGLE_KEY = .KeyCode.Minus
ONLY_TAGGED_SURFACES =
SURFACE_TAG =
RAY_DISTANCE =
FRONT_ATTACH_DISTANCE =
FLOOR_CHECK_DISTANCE =
SURFACE_OFFSET =
MOVE_SPEED =
WALL_UP_SPEED =
MOVE_ACCELERATION =
NO_INPUT_DAMPING =
MAX_MOVE_FORCE =
STICK_ACCELERATION =
SOFT_STICK_SPEED =
JUMP_POWER =
ALIGN_RESPONSIVENESS =
NORMAL_LERP_SPEED =
FAST_ATTACH_LERP_SPEED =
CAMERA_DISTANCE =
CAMERA_HEIGHT =
MOUSE_SENSITIVITY =
CAMERA_SMOOTHNESS =
AUTO_ATTACH_WHEN_WALKING =
DISABLE_WHEN_SURFACE_LOST_AFTER =
yaw =
pitch =
character
humanoid
root
savedWalkSpeed
savedJumpPower
savedJumpHeight
savedUseJumpPower
attachment
alignOrientation
vectorForce
currentNormal = .yAxis
lastGoodNormal = .yAxis
lastSurfaceResult =
lostSurfaceTime =
wallState =
(v, fallback)
(v) == v.Magnitude >
v.Unit
fallback .yAxis
(v, maxMagnitude)
v.Magnitude > maxMagnitude
v.Unit * maxMagnitude
v
()
character = player.Character player.CharacterAdded:()
humanoid = character:()
root = character:()
character, humanoid, root
()
params = RaycastParams.()
params.FilterType = .RaycastFilterType.Exclude
params.FilterDescendantsInstances = character {character} {}
params.IgnoreWater =
params
(result)
result
result.Instance
result.Instance.CanCollide
ONLY_TAGGED_SURFACES
CollectionService:(result.Instance, SURFACE_TAG)
(origin, direction, distance)
result = :(origin, (direction, -currentNormal) * distance, ())
(result)
result
()
alignOrientation
alignOrientation:()
alignOrientation =
vectorForce
vectorForce:()
vectorForce =
attachment
attachment:()
attachment =
()
root
()
attachment = .()
attachment.Name =
attachment.Parent = root
alignOrientation = .()
alignOrientation.Name =
alignOrientation.Mode = .OrientationAlignmentMode.OneAttachment
alignOrientation.Attachment0 = attachment
alignOrientation.Responsiveness = ALIGN_RESPONSIVENESS
alignOrientation.MaxTorque = .huge
alignOrientation.RigidityEnabled =
alignOrientation.Parent = root
vectorForce = .()
vectorForce.Name =
vectorForce.Attachment0 = attachment
vectorForce.RelativeTo = .ActuatorRelativeTo.World
vectorForce.ApplyAtCenterOfMass =
vectorForce.Force = .zero
vectorForce.Parent = root
()
x =
z =
UserInputService:(.KeyCode.W) z +=
UserInputService:(.KeyCode.S) z -=
UserInputService:(.KeyCode.D) x +=
UserInputService:(.KeyCode.A) x -=
v = .(x, , z)
v.Magnitude > v = v.Unit
v
(upVector)
forward = camera.CFrame.LookVector
forward = forward - upVector * forward:(upVector)
forward.Magnitude < root
forward = root.CFrame.LookVector - upVector * root.CFrame.LookVector:(upVector)
(forward, root root.CFrame.LookVector .zAxis)
(upVector)
input = ()
input.Magnitude <= .zero
forward = (upVector)
right = (forward:(upVector), root root.CFrame.RightVector .xAxis)
moveDirection = forward * input.Z + right * input.X
moveDirection = moveDirection - upVector * moveDirection:(upVector)
(moveDirection, .zero)
(moveDirection)
root camera
AUTO_ATTACH_WHEN_WALKING
input = ()
input.Z <=
origin = root.Position
forward = moveDirection
forward.Magnitude <
forward = (currentNormal)
cf = root.CFrame
origins = {
origin,
origin + currentNormal * ,
origin - currentNormal * ,
origin + cf.RightVector * ,
origin - cf.RightVector * ,
}
best
bestDistance = .huge
_, testOrigin (origins)
result = (testOrigin, forward, FRONT_ATTACH_DISTANCE)
result
isWallLike = .(result.Normal:(.yAxis)) <
isWallLike result.Distance < bestDistance
best = result
bestDistance = result.Distance
best
(moveDirection)
root
origin = root.Position
cf = root.CFrame
directions = {
-currentNormal,
-lastGoodNormal,
-cf.UpVector,
.(, -, ),
.(, , ),
cf.LookVector,
-cf.LookVector,
cf.RightVector,
-cf.RightVector,
}
moveDirection moveDirection.Magnitude >
.(directions, moveDirection)
.(directions, -moveDirection)
origins = {
origin,
origin + cf.LookVector * ,
origin - cf.LookVector * ,
origin + cf.RightVector * ,
origin - cf.RightVector * ,
origin + currentNormal * ,
origin - currentNormal * ,
}
bestResult
bestScore = -.huge
_, testOrigin (origins)
_, direction (directions)
result = (testOrigin, direction, RAY_DISTANCE)
result
continuity = result.Normal:(currentNormal) *
distanceScore = -result.Distance *
movementScore =
moveDirection moveDirection.Magnitude >
movementScore = .(result.Normal:(moveDirection)) *
score = continuity + distanceScore + movementScore
score > bestScore
bestScore = score
bestResult = result
bestResult
(normal)
y = normal:(.yAxis)
y >
y < -
(surfaceNormal)
input = ()
input.Magnitude <= .zero
upVector = surfaceNormal.Unit
state = (upVector)
state ==
worldUpOnWall = .yAxis - upVector * .yAxis:(upVector)
worldUpOnWall = (worldUpOnWall, (upVector))
side = (worldUpOnWall:(upVector), root root.CFrame.RightVector .xAxis)
move = worldUpOnWall * input.Z + side * input.X
(move, .zero)
(upVector)
(upVector, moveDirection)
forward
moveDirection moveDirection.Magnitude >
forward = moveDirection - upVector * moveDirection:(upVector)
forward = camera.CFrame.LookVector - upVector * camera.CFrame.LookVector:(upVector)
forward.Magnitude < root
forward = root.CFrame.LookVector - upVector * root.CFrame.LookVector:(upVector)
forward = (forward, root root.CFrame.LookVector .zAxis)
right = (forward:(upVector), root root.CFrame.RightVector .xAxis)
forward = (upVector:(right), root root.CFrame.LookVector .zAxis)
right, upVector, -forward
()
humanoid
humanoid.AutoRotate =
humanoid.PlatformStand =
savedWalkSpeed humanoid.WalkSpeed = savedWalkSpeed
savedUseJumpPower ~=
humanoid.UseJumpPower = savedUseJumpPower
savedJumpPower humanoid.JumpPower = savedJumpPower
savedJumpHeight humanoid.JumpHeight = savedJumpHeight
(()
humanoid:(.HumanoidStateType.Running)
)
(reason)
WALL_WALK_ENABLED =
()
()
camera = .CurrentCamera
camera camera.CameraType = .CameraType.Custom
UserInputService.MouseBehavior = .MouseBehavior.Default
UserInputService.MouseIconEnabled =
currentNormal = .yAxis
lastGoodNormal = .yAxis
lastSurfaceResult =
lostSurfaceTime =
wallState =
(reason ( .. reason) )
(dt)
WALL_WALK_ENABLED
character humanoid root root.Parent
()
()
camera = .CurrentCamera
camera
preliminaryMove = (currentNormal)
frontWall = (preliminaryMove)
result = frontWall (preliminaryMove)
result
lastSurfaceResult = result
lostSurfaceTime =
targetNormal = result.Normal.Unit
speed = frontWall FAST_ATTACH_LERP_SPEED NORMAL_LERP_SPEED
maxAlpha = frontWall
alpha = .(dt * speed, , maxAlpha)
currentNormal = (currentNormal:(targetNormal, alpha), targetNormal)
lastGoodNormal = currentNormal
wallState = frontWall (currentNormal)
lostSurfaceTime += dt
lostSurfaceTime < DISABLE_WHEN_SURFACE_LOST_AFTER
currentNormal = lastGoodNormal
result = lastSurfaceResult
()
upVector = currentNormal.Unit
moveDirection = (upVector)
wallState ==
wallState = (upVector)
humanoid.AutoRotate =
humanoid.PlatformStand =
humanoid.WalkSpeed = MOVE_SPEED
humanoid:(moveDirection, )
right, up, back = (upVector, moveDirection)
alignOrientation
alignOrientation.CFrame = .(root.Position, right, up, back)
mass = root.AssemblyMass
velocity = root.AssemblyLinearVelocity
normalVelocity = upVector * velocity:(upVector)
tangentialVelocity = velocity - normalVelocity
targetSpeed = wallState == WALL_UP_SPEED MOVE_SPEED
desiredTangentialVelocity = moveDirection * targetSpeed
velocityError
moveDirection.Magnitude >
velocityError = desiredTangentialVelocity - tangentialVelocity
velocityError = -tangentialVelocity
accel = moveDirection.Magnitude > MOVE_ACCELERATION NO_INPUT_DAMPING
moveForce = (velocityError * mass * accel, MAX_MOVE_FORCE)
antiGravity = .(, .Gravity * mass, )
stickForce = -upVector * STICK_ACCELERATION * mass
towardSurfaceSpeed = -velocity:(upVector)
towardSurfaceSpeed > SOFT_STICK_SPEED
stickForce *=
vectorForce
vectorForce.Force = antiGravity + stickForce + moveForce
result
minDistance = SURFACE_OFFSET *
maxDistance = SURFACE_OFFSET *
result.Distance < minDistance
root.CFrame = root.CFrame + upVector * ((minDistance - result.Distance) * )
result.Distance > maxDistance
root.CFrame = root.CFrame - upVector * ((result.Distance - maxDistance) * )
(dt)
WALL_WALK_ENABLED
root camera
upVector = currentNormal.Unit
rotacion = .(, .(yaw), ) * .(.(pitch), , )
offset = rotacion:(.(, CAMERA_HEIGHT, CAMERA_DISTANCE))
targetPosition = root.Position + offset
targetLookAt = root.Position + upVector *
targetCFrame = .(targetPosition, targetLookAt)
camera.CameraType ~= .CameraType.Scriptable
camera.CameraType = .CameraType.Scriptable
camera.CFrame = camera.CFrame:(targetCFrame, .(CAMERA_SMOOTHNESS * * dt, , ))
()
WALL_WALK_ENABLED
()
savedWalkSpeed = humanoid.WalkSpeed
savedJumpPower = humanoid.JumpPower
savedJumpHeight = humanoid.JumpHeight
savedUseJumpPower = humanoid.UseJumpPower
()
WALL_WALK_ENABLED =
currentNormal = .yAxis
lastGoodNormal = .yAxis
lastSurfaceResult =
lostSurfaceTime =
wallState =
humanoid.PlatformStand =
humanoid.AutoRotate =
humanoid.WalkSpeed = MOVE_SPEED
camera = .CurrentCamera
camera camera.CameraType = .CameraType.Scriptable
UserInputService.MouseBehavior = .MouseBehavior.LockCenter
UserInputService.MouseIconEnabled =
()
()
WALL_WALK_ENABLED
()
()
WALL_WALK_ENABLED
()
()
UserInputService.InputBegan:((input, processed)
processed
input.KeyCode == TOGGLE_KEY
()
WALL_WALK_ENABLED input.KeyCode == .KeyCode.Space root
upVector = currentNormal.Unit
velocity = root.AssemblyLinearVelocity
tangentialVelocity = velocity - upVector * velocity:(upVector)
root.AssemblyLinearVelocity = tangentialVelocity + upVector * JUMP_POWER
vectorForce
vectorForce.Force = .zero
)
UserInputService.InputChanged:((input)
WALL_WALK_ENABLED
input.UserInputType == .UserInputType.MouseMovement
yaw -= input.Delta.X * MOUSE_SENSITIVITY
pitch -= input.Delta.Y * MOUSE_SENSITIVITY
pitch = .(pitch, -, )
)
RunService.RenderStepped:((dt)
WALL_WALK_ENABLED
(dt)
(dt)
)
player.CharacterAdded:(()
.()
character =
humanoid =
root =
()
WALL_WALK_ENABLED
()
()
)
()Key ( - ) OFF / ON

Universal