Hi! I’ve been working for a little while on a solution to this issue and would like to hear if anyone has any ideas on how to approach this, all of my solutions have felt clunky or inconsistent.
Essentially, I’m trying to make it so you can walk on the outside of a model or part, as if that surface is the ground. When you reach an edge of that surface (which is often a 90 degree corner, one of the biggest challenges) your character should reorient to be parallel to the new surface. This is essentially supposed to be like wall climbing, but in 0 gravity so everything goes and can be walked on.
The first approach I tried was anchoring the character parallel to the surface of the “floor” (using a raycast normal to orient the character parallel) and updating the character CFrame with RenderStepped for any user WASD input. When they reached an edge of a current floor, a raycast is sent to the origin of the part. That collides with any surface between the character and the part’s origin, which is the way I grab the nearest surface to orient yourself based on. This solution isn’t terrible, and it’s the closest to consistent I’ve got. It does, however, look very “choppy” as transitions from one surface to another are instantaneous. The biggest issue here is that every time I anchor onto a new surface, the character’s relative orientation completely changes. This means you might be climbing over a corner and when the player is switched to the new orientation, their head is now where their feet would be if you were climbing over a corner. Here’s a picture showing what happens when the character moves in the direction indicated by the arrow, with the resulting transformation in the image below.
My assumption here is that the raycastResult.Normal has a rotation component based on the surface that I don’t know about, or that the character always tries to place its feet at the lowest possible point in the world reference frame given the required orientation. Does anyone know why this is happening, or what orientation a raycastResult.Normal returns? Or is it literally just returning a vector with no CFrame component, so the character orientation is reset to whatever is default? Is it possible for me to retain the character orientation around corners like this? It is worth noting some transitions from wall to wall DO seem to work nearly as intended, which is what is confusing me. The behavior seems a little random. This is basically what the script looks like, oldOrientation is what I’m trying to figure out how to utilize
function Movement:checkOrientation(humanoidRootPart, part, oldRayCastNormal)
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = {humanoidRootPart.Parent}
local rayDirection = CFrame.new(humanoidRootPart.Position, part.Position)
local raycastResult = workspace:Raycast(humanoidRootPart.Position, rayDirection.LookVector*5, raycastParams)
if ((raycastResult.Normal - oldRayCastNormal).Magnitude > .05) then
local oldOrientation = ??
humanoidRootPart.CFrame = CFrame.new(raycastResult.Position + raycastResult.Normal*2, raycastResult.Position + raycastResult.Normal*3)
end
return raycastResult.Normal