How would I make a slope alignment script that also works when the player is upside down

  1. What I want to achieve
  • I am making my own gravity controller that’s using a (incomplete but still functional) player movement system. Right now I have made the player able to walk on any surface as long as the bottom part of their custom character controller is facing towards the surface that they have to walk on. I tried to make it so that the custom player controller can automatically rotate depending on the surface they’re on using various “slope alignment” scripts I’ve found on the internet, but with every single one of them I’ve ran into this issue…
  1. The Issue
  • When rotating my character using these scripts, they would always stop rotating the character when the character comes across a flat wall. When it doesn’t do this, it would stop rotating the character when the character can classified as “being upside down”

Image of it working when the player doesn’t classify as “upside down”

Image of the player reaching the maximum angle it can rotate before being unable to rotate at greater angles

Image of the player being at an area where they should rotate at different angles, but are not

here is the script I’m using to align the player with the slope they’re standing on:

local runService = game:GetService("RunService")

local player = game.Players.LocalPlayer
local character = player.Character

local humanoid = character:WaitForChild("Humanoid")
local rootpart = humanoid.RootPart

local bodyGyro = char.CustomMovementModel.MoverBlock.AlignOrientation


local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = {character}
raycastParams.IgnoreWater = true

runService.RenderStepped:connect(function(delta)
	local direction = Vector3.new(0, -10, 0)
	local ray = game.Workspace:Raycast(rootpart.Position, direction, raycastParams)

	if ray then
		local hit, pos, normal = ray.Instance, ray.Position, ray.Normal

		if hit then			
			local p1 = rootpart.CFrame.LookVector:Cross(normal)
			bodyGyro.CFrame = CFrame.fromMatrix(rootpart.Position, p1, normal)
		else
			bodyGyro.CFrame = CFrame.new(rootpart.Position, rootpart.Position + rootpart.CFrame.LookVector)
		end
	end
end)

This is a modified version of the script from this post: Slope alignment clipping - #10 by CrazyAlternetive

  1. Solutions I’ve tried
  • I’ve tried changing this portion of the script “local direction = Vector3.new(0, -10, 0)” into this “local direction = Vector3.new(-10, -10, -10)”, but this only unlocked a few more angles that it could rotate towards before being rotate again, and “X axis” portion of that snippet of code allows the player to climb up completely flat walls without having the go on a curved ramp.

Drawing of what the player does when I try this solution and what I want the player to do:

  • Another solution I’ve tried is making 2 of the same scripts. One script has this “local direction = Vector3.new(-10, -10, -10)” while the other script has this “local direction = Vector3.new(10, 10, 10)”. This resulted in a lot more freedom, aforementioned “Player walking on walls without a curved ramp” still happens and because of the second script shooting a RayCast above the player, the player can be rotated towards platforms above it

Video of what happens when I try this solution:

How can I solve all of these issues?

Lastly, I know there is an open sourced gravity controller script out there, but I’d like to make my own