Edit: I might just be dumb and it’s fine to do all of this on the client, but I just wanna make sure
So I know controls can only be done on the client using UserInputService although for my game I’ve coded a slide, wall run and wall climbing and it’s all handled on the client and I’m gonna assume that I should probably break it up a bit and handle some things on the server although I’m not exactly sure what so my question is like what should be on the client and what should go on the server?
Heres the code which I kind of mashed together today so sorry if it’s wack.
--| Services
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UIS = game:GetService("UserInputService")
local CAS = game:GetService("ContextActionService")
--| Variables
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:wait()
local HRP = Character:WaitForChild("HumanoidRootPart")
local Humanoid = Character:WaitForChild("Humanoid")
local Animations = game:GetService("ReplicatedStorage"):WaitForChild("Animations")
local Anims = {}
if Animations then
for _,anim in pairs(Animations:GetChildren()) do
if anim:IsA("Animation") then
Anims[anim.Name] = Humanoid:LoadAnimation(anim)
end
end
end
local Climbing = false
local Face = nil
local Sliding = false
local Actions = {0;0;0;0;}
local Buttons = {"A";"D";"S";"W"}
local Left = false
local Right = false
local LeftPlaying = false
local RightPlaying = false
local Controls = {
["Q"] = function()
if (not Sliding) and (not Climbing) and (Humanoid.FloorMaterial ~= Enum.Material.Air) then
Sliding = true
Humanoid.JumpHeight = 0
Anims["Slide"]:Play()
local Slide = Instance.new("BodyVelocity")
Slide.MaxForce = Vector3.new(1,0,1)*30000
Slide.Velocity = HRP.CFrame.lookVector*100
Slide.Parent = HRP
for count = 1,8 do
wait(0.1)
Slide.Velocity *= 0.7
end
Anims["Slide"]:Stop()
Humanoid.JumpHeight = 7.2
Slide:Destroy()
Sliding = false
end
end,
["F"] = function()
if not Sliding then
if (not Climbing) then
OnClimb()
else
OffClimb()
end
end
end,
}
local Params = RaycastParams.new()
Params.CollisionGroup = ("Climbable")
Params.FilterDescendantsInstances = {Character}
Params.FilterType = Enum.RaycastFilterType.Blacklist
Params.IgnoreWater = true
local ClimbMove = Instance.new("BodyVelocity")
ClimbMove.MaxForce = Vector3.new(1,1,1)*math.huge
ClimbMove.P = math.huge
ClimbMove.Velocity = Vector3.new()
ClimbMove.Name = ("Climb Speed")
local ClimbGyro = Instance.new("BodyGyro")
ClimbGyro.CFrame = CFrame.new()
ClimbGyro.D = 100
ClimbGyro.MaxTorque = Vector3.new(1,1,1)*math.huge
ClimbGyro.P = 3000
function Down(Key)
return UIS:IsKeyDown(Enum.KeyCode[Key])
end
function MovePlayer(Part1,Part2,Cross1,Cross2)
if not HRP:FindFirstChild("WRBV") then
BodyVelocity = Instance.new("BodyVelocity",HRP)
BodyVelocity.Name = "WRBV"
end
if not HRP:FindFirstChild("WRBG") then
BodyGyro = Instance.new("BodyGyro",HRP)
BodyGyro.Name = "WRBG"
end
BodyGyro.D = 100
BodyGyro.P = 10000
BodyGyro.MaxTorque = Vector3.new(0,0,0)
BodyVelocity.MaxForce = Vector3.new(0,0,0)
BodyGyro.CFrame = HRP.CFrame
BodyGyro.MaxTorque = Vector3.new(1,1,1) * math.huge
BodyVelocity.MaxForce = Vector3.new(1,1,1) * math.huge
if Part1 then
BodyVelocity.Velocity = Cross1 * 50
Left = true
elseif Part2 then
BodyVelocity.Velocity = -Cross2 * 50
Right = true
end
end
function StopMovingPlayer()
if HRP:FindFirstChild("WRBV") and HRP:FindFirstChild("WRBG") then
HRP:FindFirstChild("WRBV"):Destroy()
HRP:FindFirstChild("WRBG"):Destroy()
Left = false
Right = false
Anims["Left"]:Stop()
Anims["Right"]:Stop()
end
end
function OffClimb()
Climbing=false
ClimbGyro.Parent=nil
ClimbMove.Parent=nil
Face=nil
end
function OnClimb()
local origin = HRP.Position
local direction = HRP.CFrame.LookVector
local result = workspace:Raycast(origin, direction, Params)
if result then
Climbing=true
HRP.CFrame = CFrame.new(HRP.CFrame.p, Vector3.new(HRP.Position.X - result.Normal.X, HRP.Position.Y, HRP.Position.Z - result.Normal.Z))
Face = CFrame.new(result.Position+result.Normal, result.Position)
Humanoid.AutoRotate=false
Humanoid.PlatformStand=true
ClimbMove.Parent=HRP
ClimbGyro.Parent=HRP
repeat
RunService.RenderStepped:Wait()
ClimbGyro.CFrame=Face or CFrame.new()
if HRP.Position.Y > result.Instance.Size.Y+3 then
Climbing=false
OffClimb()
end
local sideOrigin = HRP.CFrame*CFrame.new(0, 0, -1).Position
local sideDirection = HRP.CFrame.RightVector*(Down("D") and -2 or 2)
local Hit = workspace:Raycast(sideOrigin, sideDirection, Params)
if Hit and (Down("D") or Down("A")) then
Face=CFrame.new(Hit.Position+Hit.Normal, Hit.Position)
end
until (not Climbing)
Humanoid.AutoRotate=true
Humanoid.PlatformStand=false
end
end
function WallRun()
local Ray1 = Ray.new(HRP.CFrame.p,HRP.CFrame.rightVector * -3)
local Ray2 = Ray.new(HRP.CFrame.p,HRP.CFrame.rightVector * 3)
local Part1,Position2,Normal1 = workspace:FindPartOnRayWithIgnoreList(Ray1,{Character})
local Part2,Position2,Normal2 = workspace:FindPartOnRayWithIgnoreList(Ray2,{Character})
local Cross1 = Vector3.new(0,1,0):Cross(Normal1)
local Cross2 = Vector3.new(0,1,0):Cross(Normal2)
if (Part1) or (Part2) then -- Player is touching a part
--if Normal1.y == 0 or Normal2.y == 0 then --Not exactly sure what any of this does
if (Part1 and Part1.Name == "WallRun") or (Part2 and Part2.Name == "WallRun") then
if Part1 then
HRP.CFrame = CFrame.new(HRP.CFrame.p,Vector3.new(HRP.Position.X + Cross1.x,HRP.Position.Y,HRP.Position.Z + Cross1.z))
elseif Part2 then
HRP.CFrame = CFrame.new(HRP.CFrame.p,Vector3.new(HRP.Position.X - Cross2.x,HRP.Position.Y,HRP.Position.Z - Cross2.z))
end
if Down("W") and not Climbing then
MovePlayer(Part1,Part2,Cross1,Cross2)
else
StopMovingPlayer()
end
end
elseif (not Part1 and not Part2) then --Player is no longer touching a part
StopMovingPlayer()
end
if Left and not LeftPlaying then
--print("LEFT")
Anims["Left"]:Play()
LeftPlaying = true
elseif not Left then
LeftPlaying = false
end
if Right and not RightPlaying then
--print("RIGHT")
Anims["Right"]:Play()
RightPlaying = true
elseif not Right then
RightPlaying = false
end
end
UIS.InputBegan:Connect(function(Input,IsTyping)
if IsTyping then return end
local Key = UIS:GetStringForKeyCode(Input.KeyCode)
local Test = table.find(Buttons, Key)
if Test then
Actions[Test]=1
elseif Controls[Key] then
Controls[Key]()
end
end)
UIS.InputEnded:Connect(function(Input,IsTyping)
if IsTyping then return end
local Key = UIS:GetStringForKeyCode(Input.KeyCode)
local Test = table.find(Buttons, Key)
if Test then
Actions[Test]=0
end
end)
RunService.RenderStepped:Connect(function()
local Strafe = Actions[2] - Actions[1]
local Surge = Actions[3] - Actions[4]
ClimbMove.Velocity=HRP.CFrame.RightVector*(Strafe*8)+Vector3.new(0, Surge*-8, 0)
WallRun()
end)