Need help with CFrame math

I’m working on a skill that fires 3 parts (saws) in front of the character in 3 different directions (spaced by 20° each). However, I can’t get the blades to move with the Front face facing towards the target position. Basically they should move along the thin face
Proof: https://gyazo.com/183e69233cfccf3f09101e75effe5d55
This is where the front face is, which is also the correct direction:
image

How can I rotate them in the correct direction?

`Code:

return function(var)
    local startCF = var[2] --HumanoidRootPart CFrame
    local duration = var[3] --0.75s
    local speed = var[4] --25
    local target = var[5] --mouse position
    
    local targetXZ = Vector3.new(target.Position.X,0,target.Position.Z)    
    
    for i = 0,2 do
        local airBlade = airSaws:Clone()
        airBlade.CFrame = startCF
        local originXZ = Vector3.new(airBlade.CFrame.Position.X,0,airBlade.CFrame.Position.Z)
        airBlade.CFrame = CFrame.new(originXZ,targetXZ) + Vector3.new(0,startCF.Position.Y,0)
        airBlade.CFrame = airBlade.CFrame * CFrame.Angles(math.rad(90),0, math.rad(70 + (i * 20)))

        airBlade.Parent = workspace.Bullets
        airBlade:WaitForChild("Particles"):WaitForChild("AirSaw"):Emit(2)

        local start = tick()
        local lastRock = tick()
        local connection
        
        connection = Service.RunS.Heartbeat:Connect(function(delta)
            if tick() - start > duration then
                Service.Debris:AddItem(airBlade,3.5)
                for _,particle in pairs(airBlade.Particles:GetChildren()) do
                    particle.Enabled = false
                end
                
                connection:Disconnect()
                return
            end
            
            airBlade.CFrame = airBlade.CFrame * CFrame.new(-speed * delta,0,0)
        end)
    end
end

File:
airblade_test.rbxl (44.3 KB)

Can you try changing the X and Y rotation?

Like this?

airBlade.CFrame = airBlade.CFrame * CFrame.Angles(0,math.rad(90), math.rad(70 + (i * 20)))

Unfortunately this happens:
https://gyazo.com/dc11fd352b2604f7aee78c0138fca719

I tried swapping the axys already but nothing seems to work. Not sure what I’m doing wrong :\

That doesn’t seem to be the correct orientation, but when you do find it, note that you will also have to change the code that moves the blade in a direction (in my experience, * CFrame.new(0, 0, -distance) gives a CFrame offset in the facing direction).

Tried, but it doesn’t work either @_@ any suggestion? It just disappears.
If i try

airBlade.CFrame = airBlade.CFrame * CFrame.new(0,0,-speed * delta)

It moves upwards instead

Try all the 6 possible directions.

2 Likes

Tried all 6, did I forget something? :skull:

1. 0, math.rad(90), math.rad(70 + (i*20))  
2. math.rad(90), 0, math.rad(70 + (i * 20))  
3. math.rad(70 + (i * 20)) , math.rad(90), 0 

4. 0, math.rad(70 + (i * 20)), math.rad(90) 
5. math.rad(70 + (i * 20)), 0, math.rad(90) 
6. math.rad(90) , math.rad(70 + (i * 20)), 0

None works properly

You could try adding another one

        airBlade.CFrame = CFrame.new(originXZ,targetXZ) + Vector3.new(0,startCF.Position.Y,0)
        airBlade.CFrame = airBlade.CFrame * CFrame.Angles(math.rad(90),0, math.rad(70 + (i * 20)))
airBlade.CFrame *= CFrame.Angles(5,5,5) --replace the 5,5,5

Also you could try using CFrame.fromOrientation which applies the rotations in a different order and can generate different results.

I do not recommend using CFrame.Angles for that reason as the rotation order can mess things up.

Which is why if you look at example camera rotation script they split up the CFrame.Angles in order to apply them in a specific order

--The CFrame.Angles are split up into 2 for a specific reason
			local camRotation = camPosition * CFrame.Angles(0, math.rad(cameraAngleX), 0) * CFrame.Angles(math.rad(cameraAngleY), 0, 0)

Tried it, still not working :sob:

I’m terribly ignorant when it comes to CFrame math, my apologies, I thought it was the best way since it works with radians. How could I replace it?

Sorry for the misunderstanding, you do not necessarily need to replace it. It’s just a pointer if you are getting odd rotations with CFrame.Angles especially if you use CFrame.Angles(x,y,z)

You should specify further what is not working,

The main barrier preventing us from achieving this solution is that it depends on how you setup this part.

  1. Firstly the image below of the gif it seems to be correct and that you just need to add a 90 degree rotation in the axis of the red vector, off the normal of the thin face.

I have no way of knowing which axis is this and how you modeled it, it could be the x,y,z axis this is what I suggested here, not sure which axis of the 5,5,5 but it should be one of them.

--Example if the red vector is the X axis of the part or right vector
        airBlade.CFrame = CFrame.new(originXZ,targetXZ) + Vector3.new(0,startCF.Position.Y,0)
        airBlade.CFrame = airBlade.CFrame * CFrame.Angles(math.rad(90),0, math.rad(70 + (i * 20)))

airBlade.CFrame *= CFrame.Angles(math.pi/2,0,0) -- perhaps its this x Axis 

image

  1. And then if you were to rotate that you would need to modify the movement direction as @ElusiveEpix mentioned

This would be the brown axis labeled in the brown arrow below:

image

It would change this axis.

Apologies for the late reply!

Okay so, if I try your solution (* CFrame.new(5,5,5) --replace the 5,5,5), I replaced the 5,5,5 with math.rad(90),0,0, it off-sets the firing direction by 90°, for all 3 parts together, as seen here:
Proof

I highlighted the front part with black as you can see in the gif. We are almost there, but the mesh is upside down (the white trail needs to be down, but I can just move the attachments manually lol) and the direction, as i said, is offset by 90°.
Without your suggestion, the parts move upwards as shown here.

This is how the code is currently looking:

actions["windSaws"] = function(var) --air form
	local startCF = var[2] --HRP CFrame
	local duration = var[3]
	local speed = var[4]
	local target = var[5]
	
	for i = 0,2 do
		local airBlade = airSaws:Clone()
		airBlade.CFrame = startCF * CFrame.Angles(math.rad(90),0, math.rad(70 + (i * 20)))
		airBlade.CFrame *= CFrame.Angles(math.pi/2,0,0) --replace the 5,5,5
		
		airBlade.Parent = workspace.Bullets
		airBlade:WaitForChild("Particles"):WaitForChild("AirSaw"):Emit(2)
		
		local start = tick()
		local connection
		
		connection = Service.RunS.Heartbeat:Connect(function(delta)
			if tick() - start > duration then
				Service.Debris:AddItem(airBlade,3.5)
				for _,particle in pairs(airBlade.Particles:GetChildren()) do
					particle.Enabled = false
				end
				
				connection:Disconnect()
				return
			end
			
			airBlade.CFrame = airBlade.CFrame * CFrame.new(0,0,-speed * delta)
			
		end)
	end
end

EDIT: changed the code so it actually goes (or at least, tries to) towards the target position.
Result is the same as the first gif linked in this reply.
New code:

actions["windSaws"] = function(var) --air form
	local startCF = var[2] --HRP CFrame
	local duration = var[3]
	local speed = var[4]
	local target = var[5]
	
	local targetXZ = Vector3.new(target.Position.X,0,target.Position.Z)
	local originXZ = Vector3.new(startCF.Position.X,0,startCF.Position.Z)	
	
	for i = 0,2 do
		local airBlade = airSaws:Clone()

		--airBlade.CFrame = startCF * CFrame.Angles(math.rad(90),0, math.rad(70 + (i * 20)))
		--airBlade.CFrame *= CFrame.Angles(0,0,math.pi/2) --replace the 5,5,5
		
		airBlade.CFrame = CFrame.new(originXZ, targetXZ) + Vector3.new(0, startCF.Position.Y - 1.5, 0)
		airBlade.CFrame *= CFrame.Angles(math.rad(90), 0, math.rad(70 + (i * 20)))
		airBlade.CFrame *= CFrame.Angles(math.pi/2,0,0)
		
		airBlade.Parent = workspace.Bullets
		airBlade:WaitForChild("Particles"):WaitForChild("AirSaw"):Emit(2)
		
		--local lookVector = 
		
		local start = tick()
		local lastRock = tick()
		local connection
		
		connection = Service.RunS.Heartbeat:Connect(function(delta)
			if tick() - start > duration then
				Service.Debris:AddItem(airBlade,3.5)
				for _,particle in pairs(airBlade.Particles:GetChildren()) do
					particle.Enabled = false
				end
				
				connection:Disconnect()
				return
			end
			
			--airBlade.CFrame = airBlade.CFrame * CFrame.new(-speed * delta,0,0)
			airBlade.CFrame = airBlade.CFrame * CFrame.new(0,0,-speed * delta)
			--airBlade.CFrame = airBlade.CFrame + airBlade.CFrame.LookVector * delta * speed
		end)
	end
end

Bump? :weary:
I kept messing around with the values, but with no success.

Try rotating around the Y or Z axis instead, and maybe use math.rad if it’s in degrees?

I’m already using math.rad and made multiple attempts to find the correct rotation…

I’ve had a shot at this using the test place file you linked and I think there’s been a lot of overcomplication going on here.

Using this code seems to get me to the correct behaviour:

local function spell() --air form
	local startCF = char:WaitForChild("HumanoidRootPart").CFrame --HRP CFrame
	local duration = 5
	local speed = 25
	local target = workspace:WaitForChild("Target") --placeholder position, normally it would be the mouse click position

	local targetXZ = Vector3.new(target.Position.X,0,target.Position.Z)
	local originXZ = Vector3.new(startCF.Position.X,0,startCF.Position.Z)	

	local hitboxParams = OverlapParams.new()
	hitboxParams.FilterType = Enum.RaycastFilterType.Blacklist

	for i = 0,2 do
		local airBlade = script:WaitForChild("SawBlade"):Clone()

		local alreadyHit = {}
		local AP = airBlade:WaitForChild("AlignPosition")
		local att1 = Instance.new("Attachment")
		att1.Name = "airBladeAtt"

		airBlade.CFrame = CFrame.new(originXZ, targetXZ) + Vector3.new(0, startCF.Position.Y - 1.5, 0)
		
		airBlade.CFrame *= CFrame.Angles(0, math.rad(20*(i - 1)), 0)

		airBlade.Parent = workspace
		airBlade:WaitForChild("Particles"):WaitForChild("AirSaw"):Emit(2)


		local start = tick()
		local lastRock = tick()
		local connection

		connection = RunS.Heartbeat:Connect(function(delta)
			if tick() - start > duration then
				Debris:AddItem(airBlade,3.5)
				att1:Destroy()
				for _,particle in pairs(airBlade.Particles:GetChildren()) do
					particle.Enabled = false
				end

				connection:Disconnect()
				return
			end

			airBlade.CFrame = airBlade.CFrame * CFrame.new(0,0,-speed * delta)

		end)
	end
end

Begin by setting all the saws to the same position and looking at the target.

airBlade.CFrame = CFrame.new(originXZ, targetXZ) + Vector3.new(0, startCF.Position.Y - 1.5, 0)

“Fan out” the saws by rotating each about their y-axis (upVector axis)

airBlade.CFrame *= CFrame.Angles(0, math.rad(20*(i - 1)), 0)

Add in the velocity by stepping in the -z direction (lookVector direction)

airBlade.CFrame = airBlade.CFrame * CFrame.new(0,0,-speed * delta)
1 Like

Oh my god, THANK YOU SO MUCH. Can’t believe it was that “simple”. Will add your name in the game credits. And thank you for explaining what you did. It works now omg.

EDIT: thanks to those who tried to help as well, but without much success!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.