I’m making a placement script right now, and the results are inconsistent. Sometimes, using half of the length works perfectly, but sometimes it has an odd offset.
– Notice, the barrel is pretty much perfect, but the vase is completely wrong
Here’s the script, I’m pretty certain that, in theory, it’s correct. Thanks for any help!
– Note, CurrentItem is a Model!
local function castMouse()
local mouseLocation = UserInputService:GetMouseLocation()
local ray = camera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
local params = RaycastParams.new()
params.FilterDescendantsInstances = {character, circleFolder}
return workspace:Raycast(ray.Origin, ray.Direction * 1000, params)
end
-- Function to update placement indicator position
local function updatePlacementIndicator()
if placementIndicator then
local mousePosition = getMouseWorldPosition()
placementIndicator.Position = mousePosition
local hrp = character:FindFirstChild('HumanoidRootPart')
if currItem and hrp then
local cast = castMouse()
if cast and cast.Position then
local _, size = currItem:GetBoundingBox()
local targetPos = mousePosition + Vector3.new(0, size.Y / 2, 0) -- This should fix all of it
local newCF = CFrame.new(targetPos)
newCF *= CFrame.Angles(math.rad(180), 0, 0)
currItem:PivotTo(newCF)
end
end
end
end
I do agree that your script is most likely correct, however I think that the problem might stem from the :GetBoundingBox function as model bounding boxes aren’t always perfect. Especially if you have some sort of union, mesh or special shapes like cylinders and wedges.
Maybe calculate the actual bottom of the model instead of relying on the center.
local function getModelBottom(model)
local lowestY
for _, part in ipairs(model:GetDescendants()) do
if part:IsA("BasePart") then
local partBottom = part.Position.Y - part.Size.Y/2
if not lowestY or partBottom < lowestY then
lowestY = partBottom
end
end
end
return lowestY
end
Then in your placement code:
local mousePos = getMouseWorldPosition()
local bottomY = getModelBottom(currItem)
local offset = currItem.PrimaryPart.Position.Y - bottomY
local targetPos = mousePos + Vector3.new(0, offset, 0)
currItem:PivotTo(CFrame.new(targetPos) * CFrame.Angles(math.rad(180),0,0))
Hopefully this should ensure the model always sits on the surface correctly, regardless of its shape, unions, or meshes.
I didn’t try this, but I found a different way which works pretty good! I created a part that mimics the bounding box and cframe, set it as the primary part, and used it for reference for placement.
– You’ll have to rotate it 180 on the Z axis every time for some reason, but now it works perfect!
Small angle offsets like 179 instead of 180 can often correct rounding or orientation errors caused by floating-point precision. Hard to actually tell the different from the player point of view in game. Also, perceived axes shift after rotation because local axes transform with the part’s orientation, so X and Y may swap roles relative to world space.. Especially if the part’s parent has its own rotation.