I’m trying to recreate a sneaking system similar to the one in Minecraft.
Sometimes the walk speed becomes 16 even though I’m still standing at the edge. It keeps switching between 16 and 0 for a few seconds, causing the player to slip off the block and fall.
I’ve tried a few approaches, but none of them worked the way I wanted.
In Minecraft, sneaking lets you stand exactly at the edge of a block without falling, and that’s what I’m trying to replicate.
Code:
local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local Raycast = RaycastParams.new()
Raycast.FilterDescendantsInstances = {LocalPlayer.Character}
Raycast.FilterType = Enum.RaycastFilterType.Exclude
while task.wait() do
local Result = workspace:Raycast(LocalPlayer.Character.PrimaryPart.Position, Vector3.new(0, -6, 0), Raycast)
if not Result then
LocalPlayer.Character:FindFirstChildOfClass("Humanoid").WalkSpeed = 0
else
LocalPlayer.Character:FindFirstChildOfClass("Humanoid").WalkSpeed = 16
end
end
This might not solve exactly what your problem is here, but you’d probably want to raycast in a few points downward around the character instead of directly below the centre of their root part, for better accuracy.
Your current system makes it so that once the character is near to an edge, it sets the WalkSpeed to 0 and causes your character to stuck, unable to go back to their original speed earlier.
In Minecraft, there’s a a designated key that toggles the crouching system. When the key is pressed, the WalkSpeed decreases, and, when the character is near the edge, it still allows the player to walk but not fall.
You should use a service that handles the player’s input like UserInputService. To detect whether a player is near the edge, you should reposition the raycast origin position in front of the character accouting for its position and orientation. If it hits nothing then it’s most likely your character is near an edge. You’d have to figure out how to make it so that the character continues to walk but not go over the edge to prevent them from falling. My current idea is to use collision groups and filtering to setup an invisble wall that collides with anyone that is near the edge.
local char = script.Parent
local hmr: BasePart = char:WaitForChild("HumanoidRootPart")
local hmn: Humanoid = char:WaitForChild("Humanoid")
local _, size = char:GetBoundingBox()
local runService = game:GetService("RunService")
local red = Instance.new("Part", workspace)
red.Size = vector.one
red.BrickColor = BrickColor.Red()
red.Anchored = true
red.CanCollide = false
local yellow = Instance.new("Part", workspace)
yellow.Size = vector.one
yellow.BrickColor = BrickColor.Yellow()
yellow.Anchored = true
yellow.CanCollide = false
local green = Instance.new("Part", workspace)
green.Size = vector.one
green.BrickColor = BrickColor.Green()
green.Anchored = true
green.CanCollide = false
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {char, red, yellow, green}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
runService.Heartbeat:Connect(function()
local moveDir = hmn.MoveDirection
if hmn.FloorMaterial == Enum.Material.Air then
return
end
if moveDir.Magnitude < 0.1 then
hmn.WalkSpeed = 16
return
end
--// cast point a bit in front of the character
local forwardPos = hmr.Position + moveDir
local rayOrigin = forwardPos
local rayDirection = vector.create(0, -size.Y / 2 - 0.5, 0)
green.Position = rayOrigin
yellow.Position = rayOrigin + rayDirection
local result = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
if not result or not result.Instance then
--// no ground ahead -> stop movement
hmn.WalkSpeed = 0
else
red.Position = result.Position
hmn.WalkSpeed = 16
end
end)
this should work, those parts are for visuals to see if everything is correct
btw this should work good cause im using MoveDirection so even if you are at the edge facing forwards but holding S, it will let u go back to ur old position