How do Roblox's Humanoids work?

Specifically, I was wondering about how humanoids are able to keep their root part suspended off of the ground by its given hipHeight property. when moving along uneven surfaces like stairs, the humanoids are able to seamlessly step up to the height of the object.

I was interested in this because I wanted to make my own movement system and I see this behavior as a necessity. If anybody knows the math and logic behind how that works, I would love to know!

5 Likes

I wouldn’t assume it to be anything more than raycasting

raycasting every frame? I thought about that, maybe there’s a raycast underneath the root part, and a force is applied to keep the player above the ground. would it be too resource expensive to apply that raycast every frame though? and even if it were done that way, would the end result be jittery, constantly updating the force to push the player up and then negating it to move the player back down?

Theres multiple raycasts being shot in various directions beneath the player. I’m pretty sure humanoids actually run partly (maybe entirely) in luau so whatever they’re doing you can likely do as well. To make humanoids smoothly move along drop offs or steps, id assume they shoot a ray in the direction of movement, and begin leveraging out the floor position with where they’re going. Just make sure if you’re going to be utilizing multiple rays per rig per update, that you use parallel luau

Not so much a force as an offset

how is this offset enforced? If the player is hovering above the ground and there is no force or object between them and the ground, the player is going to fall to the ground.

1 Like

Newtons third law. You do not need an equalizer force, just assume that an anchored surface is immovable and therefore any downward force enacting on the rig is negated. Position calculations based on force will be capped at the hip height from the point of the ray’s intersection

but thats the thing though - if there is no contact between the player and an anchored part, then there is no opposite force, only gravity. In Roblox, humanoids maintain an elevated “hipHeight” property that keeps the humanoidRootPart (the only collidable part in the assembly) off the ground. there is something in the player core code that prevents the rootpart from falling to the ground and maintains it at an offset of its hipheight, and i was wondering what that was.

using collision detection and animation blending

I apologize, I failed to read your reply in its entirety.

So, for all moving parts in the game, a downward gravitational force is applied. You’re saying that once the raycast finds something beneath it, the gravitational force against the player is negated? Does that mean a custom humanoid script would require new physics code in order to take that into account?

The rig will undergo a series of transformations to its position property before it is rendered on the next frame. This is what it means to simulate physics. Personally, I would queue these transformations similar to how ContextActionService works, where certain body-force objects would impart different transformations with higher authority. Once all the transformations have been done, as @2112Jay stated, it’s now a matter of collision detection. Often times, the down-force on the rig will attempt to transform the rigs position into the ground, but a collision should’ve stopped that. The collision is detected, and the rig is offset so it may be returned to the surface of what it collided with. The ray that is being cast down from the HumanoidRootPart will report whether or not a surface exists below the feet, and the rig will be offset to the hip-height should its transformed position fall below that height

I started with the simplest approach I could think of:

--ran every frame update in the client

--Ground Detection
		local castParams = RaycastParams.new()
		castParams.FilterType = Enum.RaycastFilterType.Exclude
		castParams.FilterDescendantsInstances = {workspace.Entities}
		local cast = workspace:Raycast(RootPart.Position + (-RootPart.CFrame.UpVector * (RootPart.Size.Y-.05) ), Vector3.new(0, -hipHeight, 0), castParams)

		OnGround = cast and true or false
		
		--snap to floor
		if cast then
			local dist = (RootPart.Position - cast.Position).Magnitude
			local remainder = hipHeight - dist
			RootPart.CFrame = RootPart.CFrame + Vector3.new(0, remainder, 0)
			print(remainder)
		end

The output at least conforms to expectations, but the results are a little less than ideal:
18f710884243f9b40ff02b5a1bf7ef11

I didnt expect it to work very well, but I also wasnt expecting it to be this bad lol. Do you have any tips on what I might do here?

Update: I rebound loop to preSimulation instead of frame update, and I also made it update the velocity as well as position. None of these changes improved this issue at all unfortunately

iirc you can find Humanoid code from the old source leak from around 2016.
it’s all written in c++, but it’s pretty easy to rewrite it in luau.
they work very well with character controllers, the only issue being is how slippery it can be on slopes.

I did end up finding that repository, but the amount of overall code in there was… a lot. Ill keep it in mind as a last resort, but that could potentially mean hours, maybe even days of digging through code trying to find the humanoid code

theres a folder named humanoid, you can use the explorer to search for it. Though, I will suggest you use something like Visual Studio Code otherwise it might be very difficult to port stuff over.

I don’t remember which exact file it was, so that’s why I’d suggest to open the entire folder with vsc to look for ground raycasts.

Interesting, when I search the word humanoid I come up with nothing. Are we looking at the same repository? This is the one that I found:

Those are core scripts, what I’m talking about is the 2016 source code leak.

Whenever I’m back home I can send the code here since it’s mainly 1:1 to how the code from back then handled the movement.

Roblox continues to simulate its own physics alongside yours. My proposed solution requires you to simulate the physics of the rig yourself:

--!strict
local RunService = game:GetService("RunService")


local MIN_HEIGHT = Vector3.yAxis * 5
local GRAVITY    = Vector3.yAxis * -workspace.Gravity


local Part = workspace.Part


local raycastParameters = RaycastParams.new()
raycastParameters.FilterDescendantsInstances = {Part}
raycastParameters.FilterType = Enum.RaycastFilterType.Exclude



local function onPreSimulation(deltaTime: number)
	local currentPosition = Part.Position
	local nextPosition    = currentPosition + 0.5 * GRAVITY * deltaTime
	
	local result = workspace:Raycast(nextPosition, -MIN_HEIGHT, raycastParameters)
	if result then
		nextPosition = result.Position + MIN_HEIGHT
	end
	
	Part.Position = nextPosition
end



RunService.PreSimulation:Connect(onPreSimulation)

https://gyazo.com/812ea5d3cde2ed31582495b2029d6e70

Interesting, this is the result I get when I paste the code into a part in my baseplate:

5fdde85c71d83317961bec20f7dab715

Im trying to think of what variables might be present that could produce a different result

Edit: Oh I see, the part is anchored. That wont work for me, as I still need roblox’s innate physics for the rest of the character’s movement mechanics

Edit2: I am able to get it to stay in position by zeroing out the y coordinate of the part’s velocity every time its placed into position above the ground, but its still pretty jittery.
7448c26d6b2da2f283e646aea78e927c

Would I be able to get away with using a Roblox humanoid? I dont know if it will mess with physics besides the intended behavior above, and I dont know if the addition of a humanoid will invoke other startercharacter scripts which would introduce behaviors I dont want

Most likely a blockcast(Not raycast), However the blockcast of the roblox humanoid will always be more performant than what you can ever do because their blockcast is made within their engine in C++ which will always run faster than lua