Hello, I was wondering how to make a wallhang system where you can move left/right between on the wall when you press a and d when you are hanging on the wall, also when you reach the edge of the wall, you switch between the sides of the wall, so that you dont fall over.
I have already made a script that allows the player to hang, I just need to allow left/right movement while wallhanging.
You will need to raycast in front of the character for that. If the player press A or D then you could use a body mover (align position or something like this?) or a tween which could be less efficient
Do you have a example that I could use or base my script upon?
Heres my script:
local UIS = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local char = script.Parent
local iswallclimbing = false
local function findPartInFront()
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {char}
local origin = char.Humanoid.RootPart.Position
local direction = char.Humanoid.RootPart.CFrame.LookVector
local rayLength = 1
local result = game.Workspace:Raycast(origin, direction * rayLength, rayParams)
if result then
return result.Instance
end
return nil
end
UIS.InputBegan:Connect(function(i, g)
if not g and i.KeyCode == Enum.KeyCode.Space then
if iswallclimbing == true then
char.HumanoidRootPart.Anchored = false
iswallclimbing = false
char.HumanoidRootPart.Velocity = Vector3.new(0, 50, 0)
else
local humanoid : Humanoid = char:WaitForChild("Humanoid")
if humanoid:GetState() == Enum.HumanoidStateType.Freefall and findPartInFront() then
local partinfront = findPartInFront()
local playerHeadPosition = char:FindFirstChild("Head")
local wallTopPosition = partinfront.Position + partinfront.Size/2
if playerHeadPosition and wallTopPosition then
if playerHeadPosition.Position.Y > wallTopPosition.Y then
char.HumanoidRootPart.Anchored = true
iswallclimbing = true
end
end
end
end
end
end)
Also, align position moves 2 attachments closer to each other (I think), which is not my goal, are there any other body movers?
Keep in mind, I need to keep the humanoidRootPart anchored so that the player doesn’t fall down to the floor, since I need the player to be attached to the wall.
I needed a wall climb for a game so i did it, this is not the whole script but here is how i keep the player against the wall. It is important to note that my need case was for flat faces and i also use deprecated body movers:
local a, w, s, d = 0, 0, 0, 0
local n = 500
local l = 0
if left then
a = -n
l = n
end
if front then
w = n * 2
end
if back then
s = -(n * 2)
end
if right then
d = n
l = n
end
local torque = 999999999999999
local bg = root:FindFirstChild("BodyGyro") or Instance.new("BodyGyro")
bg.Parent = root
bg.CFrame = CFrame.new(root.Position, result.Position)
bg.MaxTorque = Vector3.new(0, torque, 0)
bg.P = torque
bg.D = 0
local upvec = CFrame.new(root.Position, result.Position).UpVector * (w + s)
local rightvec = CFrame.new(root.Position, result.Position).RightVector * (a + d)
local lookvec = CFrame.new(root.Position, result.Position).LookVector * l
local bv = root:FindFirstChild("BodyVelocity") or Instance.new("BodyVelocity")
bv.Parent = root
bv.Velocity = upvec + rightvec + lookvec
Before that, i use UserInputService to check which input i press. Then, i use a bool variable for each 4 movement keys. If the input Start then InputBegan, if the input ends then InputEnded.
Once you got it, you will need to raycast in front of the character. If result and result.Normal.Y == 0 then it means there is a wall of a part in front of you. if not result or result.Normal.Y ~= 0 then it means you have to delete the body mover (or align movers or waterever the name is). Also, if all the 4 bool variables are set to false then delete the body movers or align movers.
After that, you will always find someone to say “This is not the right way to do that, there is a better way”. But for me it works fine. Hope it will helps you!
in my use case, i needed to delete the body movers or align movers when the player doesnt press any key, in your case, you dont need to delete every time which means the code will be a bit different
This above solution will keep the player attached to the wall. You still need an animation and have to place the character accordingly for the full illusion.
As i said, my solution works perfectly for my use case because i just need to give the player more movement. And as i said, the code will be different for his game. I just gave one possible solution
Apologies, I am still new to the post. OP, do you want a free climbing system, or a controlled climbing system?
If you want a controlled climb, I remember a post talking about how you make invisible waypoints where if the player pushes a or d it lerps/tweens the character to the adjacent waypoint in line with a animation. I will see if I can find such topic.
local rayLeft = Ray.new(hrp.CFrame.p, hrp.CFrame.lookVector * 3)
local part, pos, normal = workspace:FindPartOnRay(rayLeft, Character)
local cross = Vector3.new(0, 1, 0):Cross(normal)
if uis:IsKeyDown(Enum.KeyCode.A) then
if not holding then return end
hrp.Anchored = false --This allows the body gyro to move the character
local Vel = hrp.Vel --Call the hrp's velocity object
local Gyro = hrp.Gyro -- Get the bodyGyro form the HRP
Gyro.CFrame = hrp.CFrame * CFrame.new(-1, 0, 0) --This makes sure the character is facing foward
Gyro.MaxTorque = Vector3.new(1 ,1 ,1) * math.huge --No need for change
Vel.MaxForce = Vector3.new(1, 1, 1) * math.huge -- No need for change
Vel.Velocity = cross * -10 -- change this to the according to the climb speed
end
This is not the full script, but feel free to personalize the velocity and body gyro system.
Okay so, I’ve figured out my own way of doing it, but one slight issue, the position changes dont replace in the server, only in the client.
Code:
local UIS = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local char = script.Parent
local RS = game:GetService("RunService")
local iswallclimbing = false
local canmoveleft = true
local canmoveright = true
local function findPartInFront(pos)
if not pos then
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {char}
local origin = char.Humanoid.RootPart.Position
local direction = char.Humanoid.RootPart.CFrame.LookVector
local rayLength = 1
local result = game.Workspace:Raycast(origin, direction * rayLength, rayParams)
if result then
return result.Instance
end
return nil
else
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {char}
local origin = pos
local direction = char.Humanoid.RootPart.CFrame.LookVector
local rayLength = 1
local result = game.Workspace:Raycast(origin, direction * rayLength, rayParams)
if result then
return result.Instance
end
return nil
end
end
local x = 0
UIS.InputBegan:Connect(function(i, g)
if not g and i.KeyCode == Enum.KeyCode.Space then
if iswallclimbing == true then
char.HumanoidRootPart.Anchored = false
iswallclimbing = false
char.Humanoid.PlatformStand = false
char.Humanoid.AutoRotate = true
char.HumanoidRootPart.Velocity = Vector3.new(0, 50, 0)
canmoveleft = true
canmoveright = true
else
local humanoid : Humanoid = char:WaitForChild("Humanoid")
if humanoid:GetState() == Enum.HumanoidStateType.Freefall and findPartInFront() then
local partinfront = findPartInFront()
local playerHeadPosition = char:FindFirstChild("Head")
local wallTopPosition = partinfront.Position + partinfront.Size/2
if playerHeadPosition and wallTopPosition then
if playerHeadPosition.Position.Y > wallTopPosition.Y then
char.HumanoidRootPart.Anchored = true
iswallclimbing = true
humanoid.PlatformStand = true
humanoid.AutoRotate = false
end
end
end
end
elseif not g and i.KeyCode == Enum.KeyCode.A then
x = -1
elseif not g and i.KeyCode == Enum.KeyCode.D then
x = 1
end
end)
UIS.InputEnded:Connect(function(i, g)
if not g and i.KeyCode == Enum.KeyCode.A then
x = 0
elseif not g and i.KeyCode == Enum.KeyCode.D then
x = 0
end
end)
RS.Stepped:Connect(function()
if iswallclimbing == true and findPartInFront() then
if x == 1 and canmoveleft == false then
return
elseif x == -1 and canmoveright == false then
return
end
char.HumanoidRootPart.CFrame = char.HumanoidRootPart.CFrame * CFrame.new(x*0.1, 0, 0)
if x == 1 and canmoveright == false then
canmoveright = true
elseif x == -1 and canmoveleft == false then
canmoveleft = true
end
elseif iswallclimbing == true and not findPartInFront() then
if x == -1 then
canmoveright = false
else
canmoveleft = false
end
char.HumanoidRootPart.CFrame = char.HumanoidRootPart.CFrame * CFrame.new(-x*0.1, 0, 0)
end
end)
Also, how do I snap the players orientation to the wall?