How to create a grid on one part?

So I have a 100 by 100 part, which I want people to be able to place things on. I want it so I can create a grid so the block that is moving around would match the parts edges.

local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()
local block = game.Workspace.Block
local TweenService = game:GetService("TweenService")
mouse.Move:Connect(function()
if mouse.Target == game.Workspace.Part then
local goal = {}
goal.Position = Vector3.new(math.floor(mouse.hit.Position.X),1.5,math.floor(mouse.hit.Position.Z))
local tweenInfo = TweenInfo.new(.1)
local tween = TweenService:Create(block, tweenInfo, goal)
tween:Play()
end
end)

I tried to do that, but the edges don’t match up with the block. How can I make it so they will?

2 Likes

mouse.hit.Position is just the position. To be clear, I have only 1 part, not 100.

I’m assuming what you mean is when you’re attempting to create a part, it doesn’t line up like so:

image
image
Please correct me if I’m wrong.

I’ve taken your code and tried it out on a baseplate world, and I can see that the object doesn’t line up, and instead is off by a couple pixels. Can you make sure that your 100 by 100 block that people can place objects on is perfectly aligned to the stud grid?

If that doesn’t work, you can try replacing goal.Position = Vector3.new(...) in your code with this:

local Y_OFFSET = 1.5
local PLACEMENT_OFFSET = 0
	
local relativePosition = Vector3.new(mouse.hit.Position.X,0,mouse.hit.Position.Z) - workspace.Part.Position
relativePosition = Vector3.new(math.floor(relativePosition.X), Y_OFFSET, math.floor(relativePosition.Z))

goal.Position = workspace.Part.Position + relativePosition + Vector3.new(PLACEMENT_OFFSET, 0, PLACEMENT_OFFSET)

Allow me to explain
To make this easier, I’ll be calling the part you want to place furniture and the part that you’re placing it on ground.

This script first gets the position of the furniture relative to the ground. Using that value we can then round and not be screwed over by the world grid.Then, we take that value and add it back onto the ground in order to get the offset position, and add on PLACEMENT_OFFSET in case we want to change it later.

Y_OFFSET is how far you want the object to be from your 100 by 100 part in the Y axis. If the part is instead half a stud off, you can change PLACEMENT_OFFSET to 0.5.

On an off note, you might want to consider making the function in mouse.Move:Connect() non-anonymous so you can update the position of the furniture when you move around as well.

Cheers!

EDIT In any case, this tutorial might be of use, as it’s really informative and easy to follow.

2 Likes

I have multiple places, so if I make an offset, then other plates wont be aligned.

Ah, I see. As an afterthought, you can make the offset the difference between the rounded and non-rounded positions of the plate. That way it will always be aligned, assuming the plate’s size is a whole number. As well, it might be best to have 2 separate offsets for X and Z if you were to use this method.

1 Like

I’m a bit confused can you explain more?

Sure thing!

I’ve modified your original script to reflect the changes I’ve mentioned:

local plr = game:GetService("Players").LocalPlayer
local mouse = plr:GetMouse()
local block = workspace.Block
local TweenService = game:GetService("TweenService")

mouse.Move:Connect(function()
    if mouse.Target == workspace.Part then
        local goal = {}

        local Y_OFFSET = 1.5
		local PLACEMENT_OFFSET = Vector3.new((workspace.Part.Size.X % 2 + 1) * 0.5, 0, (workspace.Part.Size.Z % 2 + 1) * 0.5)
        
        local relativePosition = Vector3.new(mouse.hit.Position.X, 0, mouse.hit.Position.Z) - workspace.Part.Position
        relativePosition = Vector3.new(math.floor(relativePosition.X), Y_OFFSET, math.floor(relativePosition.Z))

        goal.Position = workspace.Part.Position + relativePosition + PLACEMENT_OFFSET

        local tweenInfo = TweenInfo.new(.1)
        local tween = TweenService:Create(block, tweenInfo, goal)
        tween:Play()
    end
end)

My apologies for the late reply, I had to make sure the script worked!

Ignore what I said before, I’m a little tired so it was not correct. Instead, since we used relative position, PLACEMENT_OFFSET should only be changed when the size of the plate changes, not the position :sweat_smile:

The anchor point of the plate changes depending on the size, which can be disorienting when the change is not even, so I’ve changed PLACEMENT_OFFSET to be completely automatic! Placement offset was only added in the chance that the plate’s size would not be even, so then the part won’t be placed half a stud off, because the anchor point would be in the center of a stud, rather than inbetween. Give this a script a try, and let me know if it works!

1 Like

Still doesn’t work:

Can you send me the place file so I can check it out? Thanks.
As well, this is how it’s looking on my screen:
image
Which is a little odd.

1 Like

File.rbxl (15.4 KB)
I used a different plate, not the baseplate

I’ve got it working. This shouldn’t happen, but there is a discrepancy between my world and yours. It might be the new Lua VM. I’ve fixed the issue, it was order of operations. Give this a whirl and tell me how it goes:

local plr = game:GetService("Players").LocalPlayer
local mouse = plr:GetMouse()
local block = workspace.Block
local TweenService = game:GetService("TweenService")

mouse.Move:Connect(function()
    if mouse.Target == workspace.Part then
        local goal = {}

        local Y_OFFSET = 1
		local PLACEMENT_OFFSET = Vector3.new(((workspace.Part.Size.X % 2) + 1) * 0.5, 0, ((workspace.Part.Size.Z % 2) + 1) * 0.5)
        
        local relativePosition = Vector3.new(mouse.hit.Position.X, 0, mouse.hit.Position.Z) - workspace.Part.Position
        relativePosition = Vector3.new(math.floor(relativePosition.X), Y_OFFSET, math.floor(relativePosition.Z))

        goal.Position = workspace.Part.Position + relativePosition + PLACEMENT_OFFSET

        local tweenInfo = TweenInfo.new(.1)
        local tween = TweenService:Create(block, tweenInfo, goal)
        tween:Play()
    end
end)

EDIT Updated the script again, give it a try.

1 Like

Thanks for your time, it works perfectly! But one problem is that the part can outside of the plate.

Any way you can help me with the other problem too?

Thanks for bearing with me. The issue in fact wasn’t order of operations but the Y offset which I borrowed from your original script.

Now, about always having it within bounds:

local plr = game:GetService("Players").LocalPlayer
local mouse = plr:GetMouse()
local block = workspace.Block
local TweenService = game:GetService("TweenService")

mouse.Move:Connect(function()
    if mouse.Target == workspace.Part then
        local goal = {}

        local Y_OFFSET = 1
		local PLACEMENT_OFFSET = Vector3.new(((workspace.Part.Size.X % 2) + 1) * 0.5, 0, ((workspace.Part.Size.Z % 2) + 1) * 0.5)
        
        local newPosition = Vector3.new(mouse.hit.Position.X, 0, mouse.hit.Position.Z) - workspace.Part.Position
        newPosition = workspace.Part.Position + Vector3.new(math.floor(newPosition.X), Y_OFFSET, math.floor(newPosition.Z)) + PLACEMENT_OFFSET

		goal.Position = Vector3.new(
			math.clamp(
				newPosition.X,
				workspace.Part.Position.X - (workspace.Part.Size.X / 2) + 0.5,
				workspace.Part.Position.X + (workspace.Part.Size.X / 2) - 0.5),
			newPosition.Y,
			math.clamp(
				newPosition.Z,
				workspace.Part.Position.Z - (workspace.Part.Size.Z / 2) + 0.5,
				workspace.Part.Position.Z + (workspace.Part.Size.X / 2) - 0.5)
			)
		
        local tweenInfo = TweenInfo.new(.1)
        local tween = TweenService:Create(block, tweenInfo, goal)
        tween:Play()
    end
end)

This makes it so that it forces the position to be within half of it’s size going positive or negative, on both the X and Z axis. math.clamp makes sure that the value is within the range, so with this code hopefully no objects will escape the bounds!

1 Like