First person & ShiftLock resets RootJoint Tilting/Bending

  1. I’m making my own swimming physics as Roblox’s built in one was very janky and too difficult to deal with after I made a custom hitbox for my character ( Everything else is all massless and pure visual )
    Also, unlike how it is originally, I can’t rotate the whole character 90 degrees since It starts tweaking so I decided to rotate the torso with the RootJoint.

  2. The problem is: Whenever the player is in first person or uses shiftlock, RootJoint is reset.

  3. I’ve tried so many things and I’m at a point that Idek what I’m doing anymore lol

  • I tried to apply the orientation every frame, heartbeat etc.
  • Mess with AutoRotate property
  • Changing CameraSubject to root part (this worked but I don’t think I should rely on this)
  • NOT setting MouseBehavior to LockCenter ( this also worked, but ruins gameplay )

The script is something like this

local currentLean = 0
local leanAngleMax = math.rad(-90) -- swimming on surface (flat)
local leanAngleSubmerged = math.rad(-45) -- swimming up ( capped at 45 )
local lastInWaterTime = 0
local surfaceGrace = 0.25
local leanSmoothness = 0.15
local lastSend = 0
local sendRate = 0.1

local original = root.RootJoint.C0
RunService.Heartbeat:Connect(function()
	if not root or humanoid.Health <= 0 then return end

	local firstPerson = (Camera.CFrame.Position - Camera.Focus.Position).Magnitude < 1
	local shiftLock = (UserInputService.MouseBehavior == Enum.MouseBehavior.LockCenter)

	local inWater, waterState = WaterSystem.IsInWater(root.Position)
	local velocity = root.AssemblyLinearVelocity
	local horizontalVel = Vector3.new(velocity.X, 0, velocity.Z)
	local horizontalSpeed = horizontalVel.Magnitude
	local isMoving = horizontalSpeed > 2

	if inWater then
		lastInWaterTime = time() / 2

		-- Wall jumping or shift locking, these are unrelated
		if waller.Value or shiftLock then
			local tween = TweenService:Create(root.RootJoint, TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), { C0 = original })
			tween:Play()
			LeanEvent:FireServer(0, "reset")
			return
		end

		if firstPerson and not inWater then
			local tween = TweenService:Create(root.RootJoint, TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), { C0 = original })
			tween:Play()
			LeanEvent:FireServer(0, "reset")
			return
		end

		-- this is the part we bend the player as they swim
		local maxLean = (waterState == "submerged") and leanAngleSubmerged or leanAngleMax
		local targetLean = isMoving and -maxLean or 0
		currentLean = currentLean + (targetLean - currentLean) * leanSmoothness

		local tween = TweenService:Create(root.RootJoint, TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {
			C0 = original * CFrame.Angles(currentLean, 0, 0)
		})
		tween:Play()

		if tick() - lastSend > sendRate then
			lastSend = tick()
			LeanEvent:FireServer(currentLean, "lean")
		end
	else

And this is how it looks in action

I don’t know what Im supposed to do with this being related to MouseBehavior
I would reaally appreciate a fix to this or any idea to get around this whole thing

1 Like

Sorry, in your code snippet, what is

local original = root.RootJoint.C0

referring to?
I could not find RootJoint in any of the character’s limbs, so I assume it’s a child of the custom hitbox you made.
If that’s the case, are you able to provide the code (if any) that generates this hitbox or the model so I can replicate your video? Thanks in advance

Also, how did you disable roblox’s swimming system? Did you just use :setStateEnabled()?

1 Like


Just to add: I can’t find any RootJoint.

1 Like

They are only in R6 avatars inside HumanoidRootPart!

You can also disable swimming with this line in a local script, no loop necessary:
I put it in StarterCharacterScripts

humanoid:SetStateEnabled(Enum.HumanoidStateType.Swimming, false)

however it will still affect your movement inside it

1 Like

omg I’m dumb sorry

Just realized the script thinks I’m in shiftlock only because It detects the mousebehavior so it returns true when I’m in first person as well
I also wrote walljump and shiftlock detection after confirming the player is in water, It still worked outside water though so I just ignored it

Everything is fixed now
that was my fault

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.