Accessory Rotation issues - CFrames and ArcHandles

Hello. My current issue is that rotating an accessory works the first time, but after that it kind of freaks out. It also ends up messing up my other handles.
Also, some accessories will rotate in the opposite direction than intended.

I figure the issue is because I basically copied my moveAccessory function, which does work, and tried to replace parts of the script for rotation, but I can’t really wrap my head around how I’d fix this.

Below is my rotateAccessory function.

local function rotateAccessory(axis, relativeAngle)
	local primaryPart = getPrimaryPart(currentAccessory)

	local worldAxis = Vector3.FromAxis(axis)
	local accessoryAxis = cframeAtMouseDown:VectorToWorldSpace(worldAxis)

	local rotationCF = CFrame.fromAxisAngle(accessoryAxis, -relativeAngle)
	local goalCF = rotationCF * cframeAtMouseDown

	pendingTransformations.cframe = goalCF
	hasPendingChanges = true

	if primaryPart and primaryPart.AccessoryWeld then
		if primaryPart.AccessoryWeld:IsA("Weld") then
			primaryPart.AccessoryWeld.C0 = goalCF
		else
			primaryPart.AccessoryWeld.C1 = goalCF
		end
	end

	local x, y, z = goalCF:ToOrientation()
	onCoordinateChanged:Fire("Rotate", Vector3.new(x, y, z))
end

Try physically turning it over; perhaps you positioned it incorrectly.

I just realized that I’m missing other chunks of my script that are likely going to be important in regards to this issue. I would also like to add that this script isn’t entirely my own as I had it revised and updated since I couldn’t wrap my head around creating working handles initially. Below is the

This function is meant to grab the state of an accessory before it gets moved/rotated/resized. but I feel like this might be the function that’s causing issues.

local function  StoreOriginalData() --See how you can name the function properly after seperating function from connection?
	if currentAccessory then
		local primaryPart = getPrimaryPart(currentAccessory)
		local specialMesh = getSpecialMesh(currentAccessory)
		if primaryPart then
			local AccessoryWeld = primaryPart.AccessoryWeld
			if AccessoryWeld:IsA("Weld") then
				cframeAtMouseDown = primaryPart.AccessoryWeld.C0 --Other scripts have convoluted functions to ensure function across multiple types of accessories, but i have yet to encounter an accessory that would not simply work like this
			else
				cframeAtMouseDown = primaryPart.AccessoryWeld.C1
			end
			if CurrentHandlesMode == "ResizeButton" then
				if specialMesh then
					vectorAtMouseDown =  specialMesh.Scale
					print("Stored original mesh scale:", vectorAtMouseDown)
				else
					vectorAtMouseDown = primaryPart.Size
					print("Stored original part size:", vectorAtMouseDown)
				end
			elseif CurrentHandlesMode == "MoveButton" then
				vectorAtMouseDown = cframeAtMouseDown.Position --primaryPart.Position
				print("Stored original part size:", vectorAtMouseDown)

			end
			--Initialize pending transformations
			pendingTransformations.size = nil
			pendingTransformations.cframe = nil
			pendingTransformations.specialMesh = specialMesh
			pendingTransformations.accessoryWeld = primaryPart.AccessoryWeld
			pendingTransformations.accessoryParts = getAccessoryParts(currentAccessory, primaryPart.AccessoryWeld)
			hasPendingChanges = false
			
			isDragging = true
			HandlesBools["isDragging"] = true
			print("Firing HandlesModeChanged event with:", HandlesBools)
			HandlesModeChanged:Fire(HandlesBools)
		end
	end
end

Arc handles function

local function ManipulateByArcHandles(axis, relativeAngle)
	if currentAccessory and isDragging then
		local currentTime = tick()
		-- Throttle resize events to prevent spam
		if currentTime - lastResizeTime >= RESIZE_THROTTLE then

			rotateAccessory(axis, relativeAngle)
			lastResizeTime = currentTime
			-- Update handles to match new orientation
			if CurrentHandles and CurrentHandles.Adornee then
				CurrentHandles.Adornee = getPrimaryPart(currentAccessory)
			end
		end
	end
end

It might also be important to note that the only issue is the rotation function. I have other functions within the same script for moving accessories + resizing, that work perfectly fine until an accessory is rotated. Re-attaching accessories to other body parts and resizing them also has no issues, so I think I’ve narrowed down the causes to any one of these, but I’m unsure since I’ve been struggling with this for a few days by now.

I don’t exactly know what you mean by that, but I’m going to try and respond with what I think you meant.

The archandles seem to technically already be made in the correct position when they are initially made. I found that the issues with some accessories not rotating correctly only happens when the accessory has a c0 rotation that isn’t (0, 0, 0).

This was actually an issue I had with the arrow handles initially, but I basically used the function in the original post (asides from the fact this one is adjusted for rotation) to fix that issue. All I know is that the accessories’ c0 not being 0 is probably the reason why the archandles stop working properly after using them once.

I tried playing around with the rotateAccessory function in regards to worldAxis and accessoryAxis. I think I likely had the wrong impression that I could just translate the code for moving accessories into rotating accessories though, since the approach I have right now doesn’t seem to update the rotational orientation.

It might be worth it for me to revisit the script before I tried to translate the moveAccessory function into one for rotating accessories, although this is just another headache I don’t know how to wrap my head around.


The rotateAccessory function prior to me messing with it

local function rotateAccessory(axis, relativeAngle, deltaRadius)
	if not player or not player.Character or not currentAccessory then return end
	local primaryPart = getPrimaryPart(currentAccessory)

	if not primaryPart then return end
	--find the accessory in the player's character
	local axisangle = Vector3.FromAxis(axis) * -relativeAngle
	local goalCF = cframeAtMouseDown * CFrame.Angles(axisangle.X, axisangle.Y, axisangle.Z)
	local cfX, cfY, cfZ = goalCF:ToOrientation()
	local Orientation = Vector3.new(cfX, cfY, cfZ)

	TransformationEvent:FireServer(primaryPart.AccessoryWeld, nil, goalCF, nil, nil)
	onCoordinateChanged:Fire( "Rotate", Orientation)

end```

I received some outside help,. and it turns out the solution is a lot simpler than I had attempted.

Below is the fix.

local function rotateAccessory(axis, relativeAngle)
	local primaryPart = getPrimaryPart(currentAccessory)

	local worldAxis = Vector3.FromAxis(axis)

	local rotationCF = CFrame.fromAxisAngle(worldAxis, -relativeAngle)
	local goalCF = rotationCF * cframeAtMouseDown

	pendingTransformations.cframe = goalCF
	hasPendingChanges = true

	if primaryPart and primaryPart.AccessoryWeld then
		if primaryPart.AccessoryWeld:IsA("Weld") then
			primaryPart.AccessoryWeld.C0 = goalCF
		else
			primaryPart.AccessoryWeld.C1 = goalCF
		end
	end

	local x, y, z = goalCF:ToOrientation()
	onCoordinateChanged:Fire("Rotate", Vector3.new(x, y, z))
end

I basically just needed to remove one line, and alter rotationCF a bit :sweat_smile:

2 Likes

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