I want to find an equation that I can use that makes it so that a parts CFrame always on top of a part, although the issue Is I don’t know how to do this, and the equations I’ve been trying to use would not help.
The center of a part is half its Y size away from the top surface and the bottom surface if the bottom and top surfaces are the surfaces that are perpendicular to part.CFrame.UpVector
.
partThatShouldBeOnTop.CFrame = partThatShouldBeUnder.CFrame * CFrame.new(0, partThatShouldBeUnder.Size.Y / 2 + partThatShouldBeOnTop.Size.Y / 2, 0).
If the top surface of the part that should be under the part being positioned isn’t the surface perpendicular to the UpVector of the CFrame of the part and in the direction of the upvector from the center, the code above won’t work. Here’s an alternative.
local function getNormalVectorAndNormalAxisNameOfMostUpFacingSurface(part)
local rotationCf = part.CFrame - part.Position
local highestY = 0
local normalVectorWithHighestY
local axisNameOfNormalVectorWithHighestY
for _, axis in Enum.Axis:GetEnumItems() do
local positiveAxisVectorInObjectSpace = Vector3.fromAxis(axis)
local positiveAxisVectorInWorldSpace = rotationCf * positiveAxisVectorInObjectSpace
local positiveAxisYInWorldSpace = positiveAxisVectorInWorldSpace.Y
if positiveAxisYInWorldSpace > highestY then
highestY = positiveAxisYInWorldSpace
normalVectorWithHighestY = positiveAxisVectorInWorldSpace
axisNameOfNormalVectorWithHighestY = axis.Name
elseif -positiveAxisYInWorldSpace > highestY then
-- elseif because both conditions can't be true because either both Ys are 0 or one is negative and one is positive
-- and the initial highest y is 0 so 0 or a negative value can never be higher than highestY.
highestY = -positiveAxisYInWorldSpace
normalVectorWithHighestY = -positiveAxisVectorInWorldSpace
axisNameOfNormalVectorWithHighestY = axis.Name
end
end
return normalVectorWithHighestY, axisNameOfNormalVectorWithHighestY
end
local function positionPartOnMostUpFacingSurfaceOfAnotherPart(partThatShouldBeUnder, partThatShouldBeOnTop)
local topNormal, topAxisName = getNormalVectorAndNormalAxisNameOfMostUpFacingSurface(partThatShouldBeUnder)
local dotProduct = Vector3.yAxis:Dot(topNormal)
local rotationCf = dotProduct < 1 - 1e-4 and CFrame.fromAxisAngle(Vector3.yAxis:Cross(topNormal).Unit, math.acos(dotProduct)) or CFrame.new()
local position = partThatShouldBeUnder.Position + topNormal * (partThatShouldBeUnder.Size[topAxisName] + partThatShouldBeOnTop.Size.Y) / 2
partThatShouldBeOnTop.CFrame = rotationCf + position
end
For rectangles the y equation to do that is the following:
local y = bottomPart.Position.Y+(bottomPart.Size.Y+smallPart.Size.Y)/2
print(y)
if it doesn’t work change the axis of the size params until it does(for example if a part is rotated you may want to use z instead of y etc)
basically, the main idea behind this equation is that you want to move the part half the size of the big part above the big part and offset it half the size of the small part so they align perfectly.
local part = -- path to the model or part you want the second part to be on
local secondpart = -- path to the part you want to be on top of the first part
if part:IsA("Model") then
secondpart.CFrame = part.WorldPivot*CFrame.new(0,part:GetExtentsSize().Y/2,0)
else
secondpart.CFrame = part.CFrame*CFrame.new(0,part.Size.Y/2,0)
end
If you want a part to be on TOP of the model no matter its orientation then you can use is raycasting. cast a ray from a rough top position and then just set the secondparts position to the position that the raycast gave us. or use RoBoPoJu’s (goofy name ngl) solution