Affixing Accessories to Non-Humanoid Character

I am attempting to attach the handle parts of head/hat/face accessories to a non-humanoid-based character’s head. The head has been scaled up to 16 times the original size, so how would I go about scaling up the handles of the required accessories to be proportionate with the head, and apply correct placement to them within the model?

The “character” itself does not have a body, it’s just a head, so accessories which attach to other parts of the body are not necessary. I believe I can load only the accessories I need via the Players:GetCharacterAppearanceInfoAsync and InsertService:LoadAsset functions. It’s just positioning a scaled-up accessory handle to their correct position in relation to the scaled-up head which I am struggling to understand.

2 Likes

Do you have the correct attachments in the Head and are these positioned correctly?

This code assumes that the accessories aren’t already scaled and that the Head has correctly positioned attachments.

local function scaleAccoutrement(accoutrement, scaleVector3)
	local function scaleItem(obj)
		if obj:IsA("BasePart") then
	        local cf = obj.CFrame
	        obj.Size = obj.Size * scaleVector3
	        obj.CFrame = cf - cf.p + (cf.p * scaleVector3)
		elseif obj:IsA("Attachment") then
	        obj.Position = obj.Position * scaleVector3
		elseif obj:IsA("SpecialMesh") and obj.MeshType ~= Enum.MeshType.Head then
			obj.Scale  = obj.Scale  * scaleVector3
			obj.Offset = obj.Offset * scaleVector3
		end
		
		for _, child in pairs(obj:GetChildren()) do
			scaleItem(child)
		end
	end
		
	for _, child in pairs(accoutrement:GetChildren()) do
		scaleItem(child)
	end
end

local function buildWeld(weldName, parent, part0, part1, c0, c1)
	local weld = Instance.new("Weld")
	weld.Name = weldName
	weld.Part0 = part0
	weld.Part1 = part1
	weld.C0 = c0
	weld.C1 = c1
	weld.Parent = parent
	return weld
end

local function findFirstMatchingAttachment(model, name)
	for _, child in pairs(model:GetChildren()) do
		if child:IsA("Attachment") and child.Name == name then
			return child
		elseif not child:IsA("Accoutrement") and not child:IsA("Tool") then
			local foundAttachment = findFirstMatchingAttachment(child, name)
			if foundAttachment then
				return foundAttachment
			end
		end
	end
end

-- Only works correctly with accessories that should attach to the Head
local function addAccoutrement(head, headScale, item)
	item.Parent = head.Parent
	scaleAccoutrement(item, headScale)
	
	local handle = item:FindFirstChild("Handle")
	if not handle then
		return
	end

	local accoutrementAttachment = handle:FindFirstChildOfClass("Attachment")
	local headAttachment = accoutrementAttachment and findFirstMatchingAttachment(head, accoutrementAttachment.Name) or nil

	local attachmentCFrame = headAttachment and headAttachment.CFrame or CFrame.new(0, 0.5 * headScale.Y, 0)
	local hatCFrame = accoutrementAttachment and accoutrementAttachment.CFrame or item.AttachmentPoint
	
	-- Anchored case
	handle.CFrame = head.CFrame * attachmentCFrame * hatCFrame:inverse()
	
	-- Weld
	buildWeld("AccessoryWeld", handle, handle, head, hatCFrame, attachmentCFrame)
end

local HEAD_SCALE = Vector3.new(16, 16, 16)
local headPart = game.Workspace.Character.Head
local accessory = game.Workspace.BlackDominoCrown:Clone()

addAccoutrement(headPart, HEAD_SCALE, accessory)

Something like this should work for your purposes.

9 Likes