Character jiggles/shakes when colliding with walls or objects

  1. What do you want to achieve?

I want a smooth collision of the player’s character with walls and objects in general.

  1. What is the issue?

When colliding with an object, the character starts to shake/jiggle instead of just stopping it’s movement. You can see what I mean in the video below, where the character collides with an invisible wall.

  1. What solutions have you tried so far?

I have not found any easy solution to this and simply do not know how I would go about this, just some guiding help and where I would need to start out, would be great.

Note: I force R6 characters and I use custom animations for the characters, a sprinting system and an 8-directional movement system.

It’s hard to give advice here without code specifics, but if I had to guess the animations you’re using are causing you to unintentionally fight the forces applied by the humanoid.

A humanoid moves from its rootpart and also tries to keep that rootpart upright. Since you have a tilt on the torso of the character you have a scenario that kind of looks like this:

The force is being applied from the center of the humanoid root part (transparent green). Since that force is so strong it’s causing your character to tilt / jitter as a result of how the torso is pinned against the wall. At the same time the root part is fighting to make itself upright causing this constant cycle of tilt / jitter.

An easy way to confirm this would be to disable the collision on parts of the character that aren’t the root part.

If that’s not it then I’d imagine we’ll have to see the code to help further.

3 Likes

For the animation I just have a simple sprinting script that ovverides the default movement animation with a different one while sprinting.

After you mentioned the collision I realized I had infact not turned off the collision for the torso and enabled it for the root part. (I thought I had already done that, must have changed it back sometime) However now that I did exactly that, it still jitters (tho slightly cleaner to my eye).

Here is the code where I configure the character:

local function ConfigureCharacterParts(character : Model) : ()
	CreateCustomizableHead(character)
	
	for _, part in pairs(character:GetDescendants()) do
		if (part:IsA("BasePart") or part:IsA("UnionOperation") or part:IsA("MeshPart")) then
			part.CastShadow = false
			part.CollisionGroup = PlayerCollisionGroupName
			part.CanCollide = false
			
			if part:IsA("BasePart") then
				part.Material = PART_CONFIGS.Material
			end
		end
	end
	
	character:FindFirstChild("HumanoidRootPart").CanCollide = true
end

EDIT: I checked the explorer during run-time and found out that for some reason the torso’s collision is not being affected by the code.

I’m mostly grasping at straws here. I don’t see anything that catches my attention in your code. Maybe try making the bodyparts massless? - Beyond that I’m afraid I can’t help unless you’re willing to post a repro I can tinker with.

Btw both union operations and mesh parts inherit from the base parts so you only need that singular :IsA check.

1 Like

As mentioned in the edit of my recent post, the torso’s collision is not being changed by the code for some reason. When I changed it manually in the explorer on the server side, I was not jittering when running straight into a wall. I have tried to specify disabling the torso’s collision on it’s own, but still no effect.

character:FindFirstChild("Torso").CanCollide = false

Ah, yeah I’ve experienced that before! I almost mentioned it in my intial reply, but when I went to confirm if it was actually a thing or not and I also toggled it in the explorer - I gaslit myself!! :laughing:

You should be able to get around it via collision groups. Make a new group that collides with no other groups and then set the limbs to it.

EDIT: FYI humanoids do some wacky things with overriding character collisions so this is not a bug per-say. It’s simply undocumented behavior (we love that, thanks Roblox, very cool)

1 Like

Thank you! Creating a collision group just for the torso and setting it to not collide with any other groups is working. Now the character does not jitter when going straight into a wall.

local function ConfigureCharacterParts(character : Model) : ()
	CreateCustomizableHead(character)
	
	for _, part in pairs(character:GetDescendants()) do
		if part:IsA("BasePart") then
			part.CastShadow = false
			part.CollisionGroup = PlayerCollisionGroupName
			part.CanCollide = false
			
			if part:IsA("BasePart") then
				part.Material = PART_CONFIGS.Material
			end
		end
	end
	
	PhysicsService:RegisterCollisionGroup("Torso")
	PhysicsService:CollisionGroupSetCollidable("Torso", "Default", false)
	character:FindFirstChild("Torso").CollisionGroup = "Torso"
	
	character:FindFirstChild("HumanoidRootPart").CanCollide = true
end

One problem persists: That is when the character does not walk straight into the wall (diagonally) or into a side of an object that is not a flat surface. In that case it still does jitter and this effect is contradicting with the style I am going for. Since this would mean the character goes “off-grid” and does not follow the 8-directional movement system.

How are you constraining the rotation of the player to walk in the 8 directions?

All I do is disable the auto rotation of the humanoid and instantly rotate the player in the direction they are trying to go to. (This is not my script, I have gotten this from another topic)

local Character = script.Parent
local Humanoid = Character:FindFirstChildOfClass("Humanoid")
local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")

Humanoid.AutoRotate = false --disable roblox's autorotate

Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function() --fires when the humanoid's move direction changes
	local rootPos = HumanoidRootPart.CFrame.p--get root position
	local moveDir = Humanoid.MoveDirection * 2--get character's move direction
	moveDir = Vector3.new(moveDir.X, 0, moveDir.Z)--remove the y component

	if moveDir.Magnitude > 0 then --make sure we're not standing still
		HumanoidRootPart.CFrame = CFrame.new(rootPos, rootPos + moveDir) --rotate the player
	end
end)

Yeah that’s probably the issue.

The move direction signal is only being fired when the input changes so it’s still possible for the character to rotate due to extrinsic effects via the physics system (like bumping to a wall or being hit by a boulder).

You could use a physics constraint such as AlignOrientation to enforce the rotation.

Or maybe you could try a completely different approach such as welding an invisible cylinder around the character which would keep your character a fixed radius away from bumping into anything.

2 Likes

After @EgoMoose mentioned AlignOrientation I figured out a way to fix jittering when colliding with walls, caused by my 8-directional movement system. I disabled Torso collisions and replaced them with HumanoidRootPart collisions through the workaround with collision groups, then went to include AlignOrientation with that system. That way I obliterated any jittering when the character collides with objects. Huge thanks to @EgoMoose for all the help!

Here is an implementation of the solutions:

-----------------------------------------------------------------------------------------------------------------
--------------- THIS ONLY WORKS WITH A SCRIPTED CAMERA (E.G. A TOP-DOWN OR ISOMETRIC CAMERA VIEW) ---------------
-----------------------------------------------------------------------------------------------------------------
---------------- (yes, technically it does still work, but that kinda defeats the whole purpose) ----------------

local Players = game:GetService("Players")
local PhysicsService = game:GetService("PhysicsService")

local function ConfigureCharacter(character)
	local Humanoid = character:FindFirstChildOfClass("Humanoid")
	local HumanoidRootPart = character:FindFirstChild("HumanoidRootPart")
	local Torso = character:FindFirstChild("Torso")
	-- IMPORTANT; FOR R15 YOU HAVE TO USE BOTH UPPERTORSO AND LOWERTORSO INSTEAD
	-- local UpperTorso = character:FindFirstChild("UpperTorso")
	-- local LowerTorso = character:FindFirstChild("LowerTorso")
	
	-- disable collisions for all base parts in character (this will not affect Head and Torso parts)
	for _, part in pairs(character:GetDescendants()) do
		if part:IsA("BasePart") then
			part.CanCollide = false
		end
	end
	
	-- SIMPLE SOLUTION TO DISABLE COLLISION FOR TORSO PARTS --
	PhysicsService:RegisterCollisionGroup("Torso") -- register a new collision group
	
	for _, group in PhysicsService:GetRegisteredCollisionGroups() do
		PhysicsService:CollisionGroupSetCollidable(group["name"], "Torso", false) -- disable collisions with any other collision group
	end
	
	Torso.CollisionGroup = "Torso" -- add Torso to collision group
	-- IMPORTANT; FOR R15 YOU HAVE TO ADD BOTH UPPERTORSO AND LOWERTORSO INSTEAD
	-- UpperTorso.CollisionGroup = "Character"
	-- LowerTorso.CollisionGroup = "Character"

	HumanoidRootPart.CanCollide = true -- enable collisions for the HumanoidRootPart
	
	Humanoid.AutoRotate = false -- disable character auto-rotation
	
	local Attachment = Instance.new("Attachment") -- create an attachment for AlignOrientation
	Attachment.Name = "AlignOrientationAttachment" -- rename the attachment (optional)
	Attachment.Parent = HumanoidRootPart -- parent attachment to HumanoidRootPart

	local AlignOrientation = Instance.new("AlignOrientation") -- create AlignOrientation object
	AlignOrientation.Mode = Enum.OrientationAlignmentMode.OneAttachment -- set orientation alignment mode to one attachment
	AlignOrientation.Attachment0 = Attachment -- connect to the attachment we created
	AlignOrientation.RigidityEnabled = true -- enable rigidity (this will make the reaction almost instant)
	AlignOrientation.Parent = HumanoidRootPart -- parent AlignOrientation to HumanoidRootPart
	
	local connection
	connection = Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function() -- fires when humanoid move direction changes
		local rootPos = HumanoidRootPart.CFrame.p -- get HumanoidRootPart position
		local moveDir = Humanoid.MoveDirection * 2 -- get character move direction
		moveDir = Vector3.new(moveDir.X, 0, moveDir.Z) -- remove the y-component

		if moveDir.Magnitude > 0 then -- make sure we are not standing still
			AlignOrientation.CFrame = CFrame.new(rootPos, rootPos + moveDir) -- rotate the character by changing AlignOrientation cframe
		end
	end)
	
	character.AncestryChanged:Wait()
	connection:Disconnect()
end

local function onPlayerAddedAsync(player)
	local connection = player.CharacterAppearanceLoaded:Connect(ConfigureCharacter)
	
	player.AncestryChanged:Wait()
	connection:Disconnect()
end

Players.PlayerAdded:Connect(onPlayerAddedAsync)

The solutions in action:

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