I am creating a game that uses skinned meshes. The starter character is small and light so I thought of adding “slope rotation” to him.

It is hard to find any posts that have a good solution to this.

I know this might be a crude drawing but it is a good enough example.

I’ve tried casting a ray down and using the normal to rotate the character. The character usually either vibrates(glitchy) or faces a completely different direction.

Another solution I found worked in a 2d game I’ve also created. But unsurprisingly it does not work in 3d.

I’ve also tried solutions other people have given, however, none of them work usually due to it being a skinned mesh and all.

```
local speedy = 0
local hrp = script.Parent.HumanoidRootPart
hrp.CFrame *= CFrame.new(0,50,0)
local uis = game:GetService("UserInputService")
local speedxz = 0
local onground = false
local dnray,dnray2
local dvector = hrp.CFrame.UpVector*-2.8
local movedir = Vector3.zAxis
local function ray(origin:Vector3,dir:Vector3,filtertype:Enum.RaycastFilterType,filter,ignorewater:boolean)
local rcp = RaycastParams.new()
rcp.FilterType = filtertype
rcp.FilterDescendantsInstances = filter
rcp.IgnoreWater = ignorewater
return workspace:Raycast(origin,dir,rcp)
end
local function getRotationBetween(u, v, axis) --thanks, dthecoolest!
local dot, uxv = u:Dot(v), u:Cross(v)
if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
end
game:GetService("RunService").RenderStepped:Connect(function()
speedy -= .5
hrp.CFrame *= CFrame.new(0,speedy/10,0)
onground = false
if ray(hrp.Position,dvector,Enum.RaycastFilterType.Blacklist,{script.Parent},true)then
repeat
hrp.CFrame *= CFrame.new(0,.05,0)
dnray2 = ray(hrp.Position,dvector,Enum.RaycastFilterType.Blacklist,{script.Parent},true)
dnray = dnray2 or dnray
until not dnray2
hrp.CFrame = hrp.CFrame:Lerp(hrp.CFrame*getRotationBetween(hrp.CFrame.UpVector,dnray.Normal,movedir),.1)
onground = true
speedy = 0
end
dvector = hrp.CFrame.UpVector*-2.8
if not onground then
hrp.CFrame = hrp.CFrame:Lerp(CFrame.lookAt(hrp.Position,hrp.Position+movedir),.4)
end
if uis:IsKeyDown(Enum.KeyCode.Space)and onground then
speedy = 11
end
if uis:IsKeyDown(Enum.KeyCode.E)then
speedy = 0
speedxz = 0
hrp.CFrame = workspace.SpawnLocation.CFrame * CFrame.new(0,10,0)
end
if script.Parent.Humanoid.MoveDirection ~= Vector3.zero then
movedir = script.Parent.Humanoid.MoveDirection
if onground then
hrp.CFrame = hrp.CFrame:Lerp(CFrame.lookAt(hrp.Position,hrp.Position+script.Parent.Humanoid.MoveDirection)*getRotationBetween(hrp.CFrame.UpVector,dnray.Normal,hrp.CFrame.LookVector),.4)
else
hrp.CFrame = hrp.CFrame:Lerp(CFrame.lookAt(hrp.Position,hrp.Position+script.Parent.Humanoid.MoveDirection),.4)
end
speedxz += onground and .1 or .02
end
speedxz *= onground and .8 or .95
hrp.CFrame *= CFrame.new(0,0,-speedxz)
end)
```

Here’s a video of what that looks like:

A good example of what a game with slope rotation looks like would be Sonic Speed Simulator.