I’m currently working on a sitting system in Roblox. Initially, I tried using the HumanoidRootPart (HRP) for seat positioning, but the hitbox became inaccurate — especially when trying to move under low structures, the character would collide incorrectly.
To solve this, I decided to create a separate hitbox system. However, when I use a Weld and change its C0.Position from (0, 0, 0) to something else (like offsetting the seated position), the player suddenly gets launched or flung away.
This is my first time implementing a custom hitbox system, so I’m wondering if I made a fundamental mistake. Am I doing something completely wrong? How should I approach building this kind of system properly?
server Script.(Actually, this script is only related to movement, so it’s not very important.):
local RemoteEvents = script.Parent:WaitForChild("RemoteEvents", 10)
local AnimationFolder = script.Parent:WaitForChild("Animations", 10)
local animationTable = {}
local character = script.Parent.Parent
local humanoid = character:WaitForChild("Humanoid")
local animator = humanoid:FindFirstChildOfClass("Animator") or humanoid:WaitForChild("Animator")
local isRunning = false
local Crouching = false
for _, anim in pairs(AnimationFolder:GetChildren()) do
if anim:IsA("Animation") then
animationTable[anim.Name] = animator:LoadAnimation(anim)
end
end
local function playsound(object, sound)
local soundclone = sound:Clone()
soundclone.Parent = object
if object.PrimaryPart then
soundclone.Parent = object.PrimaryPart
end
soundclone:Play()
game:GetService("Debris"):AddItem(soundclone, soundclone.TimeLength + 0.1)
end
RemoteEvents.Run.OnServerEvent:Connect(function(player)
if player.Character and player.Character == character then
humanoid.WalkSpeed = 30
isRunning = true
if animationTable.Run and not animationTable.Run.IsPlaying then
animationTable.Run:Play()
animationTable.Crouch:Stop()
end
end
end)
RemoteEvents.Walk.OnServerEvent:Connect(function(player)
if player.Character and player.Character == character then
if not Crouching then
humanoid.WalkSpeed = 18
end
isRunning = false
if animationTable.Run and animationTable.Run.IsPlaying then
animationTable.Run:Stop()
end
end
end)
RemoteEvents.Crouch.OnServerEvent:Connect(function(player)
if player.Character and player.Character == character then
humanoid.WalkSpeed = 10
Crouching = true
if animationTable.Crouch and not animationTable.Crouch.IsPlaying then
animationTable.Run:Stop()
animationTable.Crouch:Play()
end
end
end)
RemoteEvents.UnCrouch.OnServerEvent:Connect(function(player)
if player.Character and player.Character == character then
Crouching = false
if isRunning then
humanoid.WalkSpeed = 30
animationTable.Run:Play()
elseif not isRunning then
humanoid.WalkSpeed = 18
end
if animationTable.Crouch and animationTable.Crouch.IsPlaying then
animationTable.Crouch:Stop()
end
end
end)
RemoteEvents.Land.OnServerEvent:Connect(function(player)
if player.Character and player.Character == character then
playsound(character, script.land)
animationTable.Land:Play()
end
end)
another server script:
local Player = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local PhysicsService = game:GetService("PhysicsService")
local function setCollisionGroup(model)
for _, descendant in model:GetDescendants() do
if descendant:IsA("BasePart") then
descendant.CollisionGroup = "PlayerInstance"
end
end
end
local function AddWeldToHitbox(character)
local weld = Instance.new("Weld")
weld.Part0 = character:WaitForChild("Hitbox")
weld.Part1 = character:FindFirstChild("HumanoidRootPart")
weld.Parent = character:FindFirstChild("Hitbox")
character:FindFirstChild("HumanoidRootPart").CanCollide = false
end
Player.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
setCollisionGroup(character)
AddWeldToHitbox(character)
end)
end)
local script(Actually, this script is just about movement, but it also includes the part where I adjust the hitbox Weld. So, it’s not very important overall, but the hitbox Weld adjustment is included here.)
local UIS = game:GetService("UserInputService")
local RemoteEvents = script.Parent:WaitForChild("RemoteEvents", 10)
local run = false
UIS.InputBegan:Connect(function(input, gameprocessedevent)
if not gameprocessedevent then
if input.KeyCode == Enum.KeyCode.LeftShift then
run = true
RemoteEvents.Run:FireServer()
elseif input.KeyCode== Enum.KeyCode.C then
game.Players.LocalPlayer.Character.Hitbox.Size = Vector3.new(4.115, 3, 1.511)
--game.Players.LocalPlayer.Character.Hitbox.Weld.C1 = CFrame.new(0,-1,0) the test code.
RemoteEvents.Crouch:FireServer()
end
end
end)
UIS.InputEnded:Connect(function(input, gameprocessedevent)
if not gameprocessedevent then
if input.KeyCode == Enum.KeyCode.LeftShift then
run = false
RemoteEvents.Walk:FireServer()
elseif input.KeyCode == Enum.KeyCode.C then
game.Players.LocalPlayer.Character.Hitbox.Size = Vector3.new(4.115, 5.256, 1.511)
--game.Players.LocalPlayer.Character.Hitbox.Weld.C1 = CFrame.new(0,1,0) the test code.
RemoteEvents.UnCrouch:FireServer()
end
end
end)
game:GetService("RunService").Heartbeat:Connect(function()
if game.Players.LocalPlayer.Character.Humanoid.MoveDirection.Magnitude < 0.1 and run == true then
RemoteEvents.Walk:FireServer()
end
end)
game.Players.LocalPlayer.Character.Humanoid.StateChanged:Connect(function(oldState, newState)
if oldState == Enum.HumanoidStateType.Freefall and newState == Enum.HumanoidStateType.Landed then
RemoteEvents.Land:FireServer()
end
end)
another local script(hitbox script. its a local)
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
print(player)
local character = player.Character or player.CharacterAdded:Wait()
print(character)
local hrp = character:WaitForChild("HumanoidRootPart")
RunService.Heartbeat:Connect(function()
script.Parent.CFrame = hrp.CFrame * CFrame.new(0, 0, 0)
end)