Placement System Snapping/Stacking

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!

I am trying to snap the item to other parts. Like the placement system in “Build A Boat For Treasure”, where it can rotate and still work.

  1. What is the issue? Include screenshots / videos if possible!

It kind of works but it doesn’t really work that well. (I don’t know how to add videos or screenshots)

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

This is the original code (Did not work with rotations but worked the best):

--originalVector3 is the mouse position
vector3new = originalVector3 + (Vector3.FromNormalId(normal) * (blockSize / 2))

*If anyone knows how to make this work with rotations, that will work! :smiley:

This is the best try I have, but it did not work out well:

local worldCF = target.CFrame:ToWorldSpace(CFrame.new(Vector3.FromNormalId(normal)))
		
local offset =  wCF.Position - target.Position
		
		
vector3value = originalVector3 + (offset * (blockSize / 2))
--I tried to find out what is the "normal" compared to the target, and then I tried to find out how was compared to the part in WorldSpace

Thank you for any help!

Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.

1 Like

for video and pics have a look at this item.

Ok thank you! I am going to try to put a video

1 Like

I tried doing this, but the offset was not correct when it was rotated:

local objOffset = target.CFrame:VectorToWorldSpace(Vector3.FromNormalId(normal))
	
resultPos = mousePos + (objOffset * (blockSize / 2))

(The video failed to upload)

1 Like

There are a bunch of ways to have a “snap” to grid feel. By far the easiest is to use Region3:ExpandToGrid() as it does this without us needing to bother about how to calculate. All we need is a region around the mouse.

The method you have tried doing is a good one however you will have to do a bit more maths and logic for it to work.

-- You need a reference CFrame and a "snap" location. In this instance I the snap location can be found simply by rounding the position of the mouse to the closest grid size
local function RoundToNearest(number: number, roundTo: number): number -- Handy function to remember
	local x = number + (roundTo / 2)
	return x - (x % roundTo)
end
-- To do this convert mouse position to target object space then round to the object space and then reconvert back to world space
local Target = RaycastResult.Position + RaycastResult.Normal -- We do this to avoid edge cases where surface of part is boundary
local BasePart: BasePart = RaycastResult.Instance -- This will be our reference.(I am raycasting from camera to mouse for this)
Target = BasePart.CFrame:PointToObjectSpace(Target)
Target = Vector3.new(
	RoundToNearest(Target.X,4),
	RoundToNearest(Target.Y,4),
	RoundToNearest(Target.Z,4)						
)					
Target = BasePart.CFrame:ToWorldSpace(CFrame.new(Target))
Preview.CFrame = Target

And Result:

The other method is a LOT simpler simply get a region around the mouse and expand it. (Cant get any simpler than that) Its a lot quicker too however you lose the ability to construct at anything other than the grid. (Sorta like Minecraft where you HAVE to build relative to the grid)

local Target = RaycastResult.Position + RaycastResult.Normal -- Avoid edge case again...
local Region = Region3.new(Target - (GRID_SIZE / 2),Target + (GRID_SIZE/2)):ExpandToGrid(8) 
-- We expand the grid to double the size as expand to grid doesn't give the closest grid location GRID_SIZE is (4,4,4)
Preview.CFrame = Region.CFrame

Who knew it only takes 2 lines?!


Hopefully this helps (mind the video quality) I don’t have any hard drive space left lol

3 Likes

Sorry I didn’t respond that soon, I will try it!

That would help with the locking to a grid but I am trying to find out how to stack the blocks, such as the game “Build A Boat For Treasure” does.

Screen Shot 2021-12-09 at 12.02.14 AM

This is an example of how it should appear.
(The orange surface would be where my mouse would be pointing, and the green block is the block being placed)

Believe it or not both methods allow for stacking. It is this piece of code that allows that to happen.

local Target = RaycastResult.Position + RaycastResult.Normal 

If you look into both pieces of code you can see that the line is present.

This code simply moves the Target away from the surface by 1 stud. This allows for the Snapping to snap to the position of wherever the grid is placed at. I could have moved it 2 studs away for clean-code however that is unnecessary.

One thing to note however, you will always want to check whether the Raycast returns a piece of the vehicle or not. If it does then you can snap to it however if not then don’t

If your looking to make a grid system
Refer this tutorial: How to make a working Grid System in Roblox

But if your looking to match rotation of mouse target
Use mouse.TargetSurface

If your pointing a block, then mouse.TargetSurface returns a NormalId or a side which you can use to set the part position