Is there any way to know which way a Part is facing?

The problem is that I will always have to change this, won’t I?

I did this and it worked, but it’s going the same way, how do I change the angle of Lookvector?

Nope, as long as you change it once and you’ve got collection service going, it will work with all the others as long as they’re the same, changing the models orientaiton also works.

Heres an example:
https://gyazo.com/4183210c3a4320dffdb47fde6720460d

Wow, I didn’t know, was this supposed to be obvious? haha

In the future think of multiply the values with eachother is just being correlated/“parallel” to one another.

If it helped you, please make sure to mark it as the solution :+1:

1 Like

Hey there, there’s a pretty simple solution to this.
If you multiply a part’s CFrame by some offset, it will move the part along its local axis. Observe:
workspace.Part.CFrame = workspace.Part.CFrame * CFrame.new(1, 0, 0)

As you can see, each time I ran that code the part was moved along its local X-axis by an increment of 1.

When you multiply CFrame by another, A * B, A gets transformed by B in A’s coordinate space. CFrame multiplication is matrix multiplication, and it is not commutative.

For your purposes, you can treat the drawer’s closed state as an origin point, and multiply its CFrame by an offset to open it along its X/Y/Z axes (depending on the orientation of the part).

For example, if your offset is CFrame.new(0, 0, 0) and the drawer is closed, its CFrame would look like this:
Origin * CFrame.new(0, 0, 0) --drawer remains in place

Let’s say in order to open the drawer your part must be moved along its X axis; it would simply look like this:
Origin * CFrame.new(x, 0, 0) --where x is the distance from the origin.

You could define the origin point as some part in the model that is not the drawer (but whose faces are oriented the same as your drawer), or simply the drawer’s initial CFrame when the model loads in (if you don’t expect the overall model to move besides the drawer).

I made my code like this:

local CollectionService = game:GetService("CollectionService")
local TweenService = game:GetService("TweenService")

local Collectionbuttons = CollectionService:GetTagged("Buttons")
local Tweens = {
	Open = 0.5,Enum.EasingStyle.Linear,Enum.EasingDirection.Out,0,false,0;
	Close = 0.5,Enum.EasingStyle.Linear,Enum.EasingDirection.Out,0,false,0;	
}

for i,v in pairs(Collectionbuttons) do
	
	local OpenNow = true--	
	
	v.ClickDetector.MouseClick:Connect(function()
		if OpenNow == true then
			
		OpenNow = false	
		local TweenOpen = TweenService:Create(v,TweenInfo.new(Tweens.Open),{CFrame = v.CFrame * CFrame.new(-1.7,0,0)})			
		TweenOpen:Play()	
		else
			
		OpenNow = true
		local Tweenclose = TweenService:Create(v,TweenInfo.new(Tweens.Open),{CFrame = v.CFrame * CFrame.new(1.7,0,0)})			
		Tweenclose:Play()	
			
		end	
	end)
end

What do you think?

The problem I see with this is that if you were to spam open/close, since you’re multiplying directly from the drawer’s CFrame, things would break down quickly. This would only work if you waited for the tween to complete before interacting again. Using an unmoving origin point rather than the drawer itself as the CFrame you multiply with would fix this issue.

So, rather than setting v’s CFrame as v.CFrame * some offset, try setting v’s CFrame equal to originPoint * some offset (where the origin point is the CFrame of the closed drawer, but not dependent on the drawer part at all).

How about something like this:

local CollectionService = game:GetService("CollectionService")
local TweenService = game:GetService("TweenService")

local Collectionbuttons = CollectionService:GetTagged("Buttons")
local Tweens = {
	Open = 0.5,Enum.EasingStyle.Linear,Enum.EasingDirection.Out,0,false,0;
	Close = 0.5,Enum.EasingStyle.Linear,Enum.EasingDirection.Out,0,false,0;	
}

for i,v in pairs(Collectionbuttons) do
	
	local OpenNow = true--	
	local Origin = v.Cframe

	v.ClickDetector.MouseClick:Connect(function()
		if OpenNow == true then
			
		OpenNow = false	
		local TweenOpen = TweenService:Create(v,TweenInfo.new(Tweens.Open),{CFrame = Origin * CFrame.new(-1.7,0,0)})			
		TweenOpen:Play()	
		else
			
		OpenNow = true
		local Tweenclose = TweenService:Create(v,TweenInfo.new(Tweens.Open),{CFrame = Origin})			
		Tweenclose:Play()	
			
		end	
	end)
end

I don’t understand why you suggest putting: “Origin = v.CFrame * CFrame.new (0,0,0)” than (“Origin = v.CFrame”), if I understand what you mean.

In this update, roblox removed the Surface thing.