So I’ve been trying to wrap my head around achieving accurate player movement along the faces of different parts (Spheres, Parts, Cylinders) for pretty much the entire day so far. My math is probably worst than a 5th grader’s, that much I know.
Want/Need
I want to add a mechanic in my game where the users would be able to scale up walls and hang upside with ease. Knowing that my math isn’t so hot, this would be impossible to achieve.
So, I have did some digging around the Forums and the internet in general for a snippet of code in which would help me understand and came across a few examples/ sources.
https://devforum.roblox.com/t/walking-on-walls-ceiling/51831/9
https://devforum.roblox.com/t/vector-math-help/32659/5
http://wiki.roblox.com/index.php?title=Cross_product
With a lead to go off of, I thank @Tinarg for the source code, it got me one step closer to my goal. After removing a few things and editing others so that it would be easier for me to implement, it produced good behavior, then no so good behavior.
Problem:
There are two problems that I’ve encountered actually.
1.) The alignment of the character is off centered when scaling along objects that aren’t on the global axis.
2.) Parts like Cylinders and Spheres return incorrect results.
Arragh! Math >_<
After tinkering and reading the output for some time, it is still hard for me to narrow down just what is going on (I’m blaming my lack of math intuition). I am totally stumped and would gladly appreciate any guidance. Here are some snippets from the local script.
Snippet #1
--From http://devforum.roblox.com/t/vector-math-help/32659/5
function Calculate_LookVector(MoveDirection,Normal)
local function clamp(value, min, max)
return (value < min and min) or (value > max and max) or value
end
local function rotateBy(vec, axis, angle)
local cosAngle = math.cos(angle)
local sinAngle = math.sin(angle)
local axisDotA = axis:Dot(vec)
return Vector3.new(
axis.X*axisDotA * (1-cosAngle) + vec.X*cosAngle + (-axis.Z*vec.Y + axis.Y*vec.Z)*sinAngle,
axis.Y*axisDotA * (1-cosAngle) + vec.Y*cosAngle + (axis.Z*vec.X - axis.X*vec.Z)*sinAngle,
axis.Z*axisDotA * (1-cosAngle) + vec.Z*cosAngle + (-axis.Y*vec.X + axis.X*vec.Y)*sinAngle
)
end
local a = Vector3.new(0, 1, 0).unit --Original Vector a
local b = MoveDirection.unit --Original Vector b
local a2 = Normal.unit --New Vector a
local axis = a:Cross(a2)
axis = axis.magnitude == 0 and a:Cross(b).unit or axis.unit
local angle = math.acos(clamp(a:Dot(a2), -1, 1))
local b2 = rotateBy(b, axis, angle) --New Vector b
return b2
end
Snippet #2
function Start()
Connection = RunService.Heartbeat:Connect(function(Tick)
local LookVector = Calculate_LookVector(Humanoid.MoveDirection,Current_Angle)
local Backward_Ray_Pos = Root.Position-(Current_Angle*3.05)+(LookVector*1.1)
local Ray_Forward = Ray.new(Root.Position,LookVector*1.3)
local Ray_Downward = Ray.new(Root.Position,-Current_Angle*3.1)
local Ray_Backward = Ray.new(Backward_Ray_Pos,-LookVector*3)
local Part_Test1, Point_Test1, Normal_Test1 = game.Workspace:FindPartOnRayWithWhitelist(Ray_Forward,game.Workspace.TestingStuff:GetChildren())
local Part_Test2, Point_Test2, Normal_Test2 = game.Workspace:FindPartOnRayWithWhitelist(Ray_Downward,game.Workspace.TestingStuff:GetChildren())
local Part_Test3, Point_Test3, Normal_Test3 = game.Workspace:FindPartOnRayWithWhitelist(Ray_Backward,game.Workspace.TestingStuff:GetChildren())
if Part_Test1 and Check_Stickable(Part_Test1) then
Normal = Normal_Test1
Point = Point_Test1
Part = Part_Test1
else if Part_Test2 and Check_Stickable(Part_Test2) then
Normal = Normal_Test2
Point = Point_Test2
Part = Part_Test2
else if Part_Test3 and Check_Stickable(Part_Test3) then
Normal = Normal_Test3
Point = Point_Test3
Part = Part_Test3
else
Normal = nil
Point = nil
Part = nil
end
end
end
if Normal then
Stick_Part = Part
Current_Angle = Normal
Current_Point = Point
if Normal.Magnitude > 0 then
Root.CFrame = CFrame.new(Point)+(Current_Angle*3)
end
end
if Humanoid.MoveDirection.Magnitude > 0 then
Root.CFrame = CFrame.new(Root.CFrame.p+((LookVector*0.28)/(Tick / (1 / 60))))
Move = Move:lerp((CFrame.Angles(0,math.pi*0.5, 0) * CFrame.new(Humanoid.MoveDirection)).p, .1 * (Tick / (1 / 60)))
end;
Root.CFrame = CFrame.new(Root.CFrame.p, Root.CFrame.p + Current_Angle) * CFrame.Angles(-math.pi*0.5,math.pi,0) * CFrame.new(Vector3.new(), Move)
end)
end
Whoops!
Forgot to attach the placefile… My bad DeScript.rbxl (41.0 KB)