How would I combine these two CFrames Properly? (Multiplying doesn't work)

I’m making a Sonic engine, and I have 2 CFrames that work excellently separately, but start violently fighting and throwing things at each other the second I try and combine them (figurative).

For simplicity, I’m just gonna name these 2 CFrames “Horizontal” and “Vertical”, and the end product will just be called “end product”.

Here’s videos of Horizontal and Vertical on their own.

Horizontal:

Vertical:

Horizontal on its own can only move along the X, and Z axes; like the default Roblox controller. However, Vertical on its own can walk on walls; you can only move forwards though, you can’t turn at all (when grounded).

Combining these two would give the player the ability to walk on walls, AND turn; but every time I try to combine them. This is the outcome:

I’ve tried multiplying Horizontal * Vertical, Vertical * Horizontal, using ToObjectSpace, ToWorldSpace, but nothing works, here’s the logic.

local hitNormal = ray.Normal
			local currentRightVector = self.hrp.CFrame.RightVector
			local upVector = hitNormal
			local newFacialVector = currentRightVector:Cross(upVector)
			
			local Rot = CFrame.fromMatrix(self.hrp.Position, currentRightVector, upVector, newFacialVector) + self.hrp.Position
			local Rot2 = self.alignOrientation.CFrame:ToObjectSpace(CFrame.lookAt(self.hrp.Position, self.hrp.Position + Vector3.new(self.move_Direction.Unit.X, 0, self.move_Direction.Unit.Z)))
            --rot is Vertical, rot2 is vertical
			if self.humanoid.MoveDirection ~= Vector3.new(0, 0, 0) then	
				self.alignOrientation.CFrame = Rot2 * Rot
			end

PLEASE, If you have an idea, don’t be afraid to tell! Thanks in advance!

Considering that Rot2 works fine, I would assume that self.move_Direction is in worldspace
this, along with how you calculate Rot2, would probably result in the fighting you see (since when Rot is applied, move_Direction.Unit.X and Z can at the extremities become 0 together)

If that assumption is correct, I believe you could just use move_Direction.Unit directly as the lookVector (newFacialVector) and construct Rot as the final CFrame

However its not impossible that move_Direction is in some more peculiar space (for example, I would believe that Rot2 is still valid on flat ground if move_Direction is oriented in an objectspace with Y axis orientation being 0), in which case it would result in a weirder situation

Trying to compose the orientation this way guarantees gimbal lock problems, especially in a world like this where the floors and walls are at right angles, and even when you have the multiplication order correct. IMHO, you should abandon the 2-axis approach and just interpret 2D user movement input in the character’s local reference frame, i.e. where their “ground plane” is the plane tangent to the surface they’re currently standing on.

2 Likes