How to lock the character's Y orientation in water

I’m looking for a method to lock the player character’s Z and X axes when they step in water, while keeping the Y axis free for regular directional movement, to create a more realistic swimming and wading mechanism - the intended effect is for the character to swim upright. By the way, using a custom rotated swim animation doesn’t exactly work (I can explain if needed.)

I’ve tried using a couple methods, notably such as AlignOrientations, but none seem to work. My attempt as is follows:

	local Attachment=Instance.new('Attachment')
	Attachment.Parent=char.HumanoidRootPart
	Attachment.Name='SwimAttachment'

	local LV=Instance.new('AlignOrientation')
	LV.Parent=Attachment
	LV.RigidityEnabled=true
	LV.Enabled=true

	LV.Attachment0=Attachment
	LV.Attachment1= PartAttachment
	LV.Mode=Enum.OrientationAlignmentMode.OneAttachment
	
	game:GetService('RunService').Heartbeat:Connect(function()

		if Attachment 
		then
			
	
			LV.CFrame=CFrame.Angles(

				0,
				char.PrimaryPart.Orientation.Y,
			0,

			)
			
		end
		
	end)

So, does anyone have a fix or an alternative method? This issue relates to the default humanoid swimming state, which should honestly be toggled in the first place.

4 Likes

You could set the humanoid root part to the water’s y

3 Likes

I’m using terrain water at different heights so I’m not sure if this could work.

To anyone who sees this, I did sort of find a way to do this by automatically turning shift lock on in water, but this wasn’t my intended solution (it should be like the default non-shift lock movement) so I won’t mark it as answered.

(Sorry for the late reply :sweat_smile: )

1 Like

Hello to anyone who happens to stumble across this, as I’ve found a solution. It works both server and client-sided.

Create an AlignOrientation in the character’s RootPart, and create a RunService function that runs either every heartbeat or step. Then, set the orientation’s CFrame to the following:

   local LV=char:FindFirstChild('SwimOrientation',true)

	local con=	game:GetService('RunService').Heartbeat:Connect(function()
		if  LV and char:FindFirstChild('Humanoid') and char.Humanoid.MoveDirection.Magnitude ~=0
			and char:FindFirstChild('HumanoidRootPart')
		then 
                     --Be sure to check if the character is in water, you could use Humanoid:GetState().
			LV.CFrame =CFrame.lookAt(char.PrimaryPart.Position - char.Humanoid.MoveDirection,char.PrimaryPart.Position)
		end
	end)

Enjoy!