I want a smooth collision of the player’s character with walls and objects in general.
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.
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.
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.
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.
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!!
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)
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.
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)
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.
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)