Fixing placement system offsets?

I am working on my placement module v3 and want to fix a issue that has been present for a while now. The position calculated in the module is not relative to the plot. This means that users have to position the plot(s) to work with the system (otherwise it will be offset). What I want to do, is make the calculate function account for the plot position it isn’t offset in some cases. I have tried to use math.modf() to add on offsets but it always was a bit off so I removed it.

images:
no offset

Offset (plot is positioned "incorrectly)

Calc function:

-- Calculates the position of the object
local function calculateItemLocation()
	if currentRot then
		x, z = mouse.Hit.X - primary.Size.X*0.5, mouse.Hit.Z - primary.Size.Z*0.5

		cx = primary.Size.X*0.5
		cz = primary.Size.Z*0.5
	else
		x, z = mouse.Hit.X - primary.Size.Z*0.5, mouse.Hit.Z - primary.Size.X*0.5

		cx = primary.Size.Z*0.5
		cz = primary.Size.X*0.5
	end

	if moveByGrid then
		-- Snaps models to grid
		if x%GRID_UNIT < GRID_UNIT*0.5 then
			posX = round(x - (x%GRID_UNIT))
		else
			posX = round(x + (GRID_UNIT - (x%GRID_UNIT)))
		end

		if z%GRID_UNIT < GRID_UNIT*0.5 then
			posZ = round(z - (z%GRID_UNIT))
		else
			posZ = round(z + (GRID_UNIT - (z%GRID_UNIT)))
		end
	else
		posX = x 
		posZ = z
	end

	-- Changes posY depending on mouse target
	if stackable and mouse.Target then
		posY = calculateYPos(mouse.Target.Position.Y, mouse.Target.Size.Y, primary.Size.Y)
	end

	-- Clamps posY to a max height above the plot position
	posY = clamp(posY, initialY, maxHeight + initialY)

	bounds()
end

All help is appreciated!

2 Likes

Can you show a video/image of the issue? I don’t understand exactly what you mean with the description you said in the post.

1 Like

alright I added some images. Sorry I forgot to add them before.

You can use the EgoMoose’s trick that he used in his placement system Furniture Placement System to snap the CFrame to the grid, this trick consists on using ToWorldSpace to fit the canvas position.

Also, this post can help you

1 Like

Thank you for the help. I just don’t understand enough of the math to correctly implement this. I appreciate it though. I’ll keep working on it and if I get it to work, I’ll mark it as the solution.

I’ll try my best to help explain haha.

So basically, think of your part as the world, where its CFrame is the 0,0,0 coordinate and takes into account rotation and whatnot.

The :ToObjectSpace creates a new CFrame relative to the target object’s CFrame, but this new CFrame is taking into account the CFrame of the target.

1 Like

That is correct. I understand the purpose of the functions ToObjectSpace/ToWorldSpace but actually implementing it in my code is another story. I always get offsets and what not (not to mention I managed to break my bounds function which stops the model from leaving the plot). Thank you though!

That’s what I tried to say with linking the EgoMoose’s furniture system

Ahhh okay I get what you mean.

I’ve made a new placement system since then and have made quite a few changes with the new coding practices that I know now. You also mentioned checking if it exceeds the plot bounds which I have a solution for.

Here’s the first thing. It checks if the part exceeds the plot bounds, if it does, it will return the closest vector to the mouse’s hit.

local function checkExceedsPlotBounds(vector)
	local vectorRelative = plot.CFrame:PointToObjectSpace(vector) -- mouse.Hit.p but relative to the plot
	local x = vectorRelative.X
	local maxPlotBoundsX = plot.Size.X / 2 -- since the plot's CFrame is the new 0,0,0, we have to divide each axis by 2 to account for either side
	if x > maxPlotBoundsX then -- if it exceeds the max for X then returns the furthest on the X axis
		x = maxPlotBoundsX
	elseif x < -maxPlotBoundsX then -- same but negative
		x = -maxPlotBoundsX
	end
	local z = vectorRelative.Z
	local maxPlotBoundsZ = plot.Size.Z / 2 -- same checks as above
	if z > maxPlotBoundsZ then
		z = maxPlotBoundsZ
	elseif z < -maxPlotBoundsZ then
		z = -maxPlotBoundsZ
	end
	local newVector = Vector3.new(x, vector.Y, z) -- create the new V3
	local newVectorRelative = plot.CFrame:PointToWorldSpace(newVector) -- change it to be in the world's space
	return newVectorRelative -- return it
end

As for the other thing, instead of checking the part’s position relative to the world, use :ToObjectSpace on it, then round the :ToObjectSpace CFrame, then return the :ToWorldSpace CFrame. You’re basically never going to check or manipulate the part’s CFrame relative to the world. This is also how you’re going to move objects relative to each other (like placing an object ontop of another object).

I’ve attached a place file, all of whose scripts include comments to better explain what’s going on. It’s a bit messy, just a warning.

placement.rbxl (52.0 KB)

1 Like

Thank you! I realize what I was doing wrong now. I was inputting the wrong stuff in ToObjectSpace(). I was doing objectCFrame:ToObjectSpace(plotCFrame) instead of plotCFrame:ToObjectSpace(objectCFrame). Anyway, your code samples helped me work this out so I will accept your answer.

1 Like