Snapping a model's primary part to the base it's to be placed on

I’m working on a placement system of a new sandbox tycoon game I’ve been working on over the past week, and progress has been going really well for how long I’ve been away from lua. Anyways, I’ve been facing a problem with the placement system in recent times.

Items are supposed to snap to the base in equal increments and are supposed to line up with the edge of a base.

It’s very difficult to explain in text so here’s an image of what happens, and what I need it to do:

(what happens) https://i.imgur.com/8CJ7U94.png

(what needs to happen) https://i.imgur.com/b7ZVqmT.png

The second picture shows the hitbox more clearly than the first one.

I have tried setting the CFrame to a proper position first before snapping to the players cursor, and yet it persisted to do the same thing.

This is what I have been doing for local player movement of an item (this is called on mouse.Move:

local function pos()
	local primP = item2place.PrimaryPart
	px = math.floor(mouse.Hit.X/size+0.5)*size
	py = pl.Stats.LocalBase.Value.Base.Position.Y + primP.Size.Y/2 + pl.Stats.LocalBase.Value.Base.Size.Y/2 
	pz = math.floor(mouse.Hit.Z/size+0.5)*size
end

Is there anything I should look into on the wiki for this? I’m not the greatest at CFrame

Hello, VeryDarkDev!

There fortunately have been some “recent” updates to the engine that make this type of job pretty simple to do.

In your case, the easiest method would be to use Model.PrimaryPart and Model:SetPrimaryPartCFrame()

Here’s the wiki pages:

My most simple explanation for this is that once you assign the PrimaryPart variable of a model, you can then use Model:SetPrimaryPartCFrame(cframe argument), to move the model based off the PrimaryPart’s cframe.

Also Mouse functions are er… slightly outdated, UserInputService is a pretty neat alternative if you’re looking to dive into some newer features.

Here’s the wiki link

However, the mouse functions still work just fine.

Hope this helped :slight_smile:

Well first things first, you’re going to want to make sure your models are sized according to the grid, well the base of the model anyways, For example if your grid is a 10x10 grid of 2x2 squares you will want to make the x and z size of the base of the model a factor of 2.

Secondly, You will want to try do something as shown:

You will want to run a check to see if the math.floor() x and z values of the mouse are a factor of your grid cell size. For example your mouse is positioned at 0.5 on the x axis, and your cell grid size is 2, It will run a check as follows:

local topleft = Grid.Position - Vector3.new(grid.Size.X / 2, 0, Grid.Size.Z / 2)
local StudsOutInVector = flooredposofmouse - topleft

if StudsOutInVector.X % 2 = 0 and StudsOutInVector.Z % 2  = 0 or StudsOutInVector.X = 0 or StudsOutInVector.Z = 0 then
local CFrameMath = CFrame.new(Grid) 
model:SetPrimaryPartCFrame((topleft + StudsOutInVector) + Vector3.new(Model.Base.Size.X / 2, 0, Mode.Base.Size.Z / 2))
end

thank you for your response! Sorry for the bad clarification on my end, I should have mentioned I had already created the grid snapping, however it was not perfectly snapping to the grid like I had wished (seen in imgur links)

I was looking at world/object space thinking maybe that would help?

thank you for this response! I will be sure to check it out as soon as I can. I appreciate the support here!

1 Like

No problem, Sorry if the code is a mess and it’s not 100% accurate by the way, the if condition is a bit messed up.

I have altered the script now, if you check the original message, If there are any errors let me know.

with flooredposofmouse would that just be Mouse.Hit.X floored?

Sorry small fix again, and if you can, you want to try construct a new vector by doing Vector3.new(mouse.hit.x floored, mouse.hit.y, mouse.hit.z floored) you set flooredposofmouse to the new vector you constructed

Also the if statements can be tidied up also im sure but thats the basic way of doing it.

		local flooredposofmouse = Vector3.new(math.floor(mouse.hit.X), 0, math.floor(mouse.hit.Z))
		local StudsOutInVector = flooredposofmouse - topleft

I get Players.VeryDarkDev.PlayerGui.Main.Client Main.ClientMain:34: attempt to perform arithmetic (mod) on userdata and number

try, mouse.hit.p.X
(30characters)