Block placement system not positioning correctly

So the top surface works but on other sides, it doesn’t position correctly.

local snapValue = 3

local hitPosition = raycastResult.Position
local hitPart = raycastResult.Instance

local snapPosition = Vector3.new(
	math.floor(hitPosition.X / snapValue + 0.5) * snapValue,
	math.floor(hitPosition.Y / snapValue + 0.5) * snapValue,
	math.floor(hitPosition.Z / snapValue + 0.5) * snapValue
)

local surfaceNormal = raycastResult.Normal
local blockOffset = Vector3.new(0, 0, 0)
local newSnapValue = snapValue / 2

if surfaceNormal == Vector3.new(0, 1, 0) then
	blockOffset = Vector3.new(0, newSnapValue, 0) -- Place block above the surface
elseif surfaceNormal == Vector3.new(0, -1, 0) then
	blockOffset = Vector3.new(0, -newSnapValue, 0) -- Place block below the surface
elseif surfaceNormal == Vector3.new(1, 0, 0) then
	blockOffset = Vector3.new(newSnapValue, 0, 0) -- Place block to the right of the surface
elseif surfaceNormal == Vector3.new(-1, 0, 0) then
	blockOffset = Vector3.new(-newSnapValue, 0, 0) -- Place block to the left of the surface
elseif surfaceNormal == Vector3.new(0, 0, 1) then
	blockOffset = Vector3.new(0, 0, newSnapValue) -- Place block in front of the surface
elseif surfaceNormal == Vector3.new(0, 0, -1) then
	blockOffset = Vector3.new(0, 0, -newSnapValue) -- Place block behind the surface
end

VisualBlock.CFrame = CFrame.new(snapPosition + blockOffset)

Side Surface:

Top Surface:
image

use math.round not math.floor (if you want to snap to odd parts then you can use this)

function Round(toRound,roundTo) -- toround the number u want to round
-- roundto is the snap value (if u want to snap to a 4x4 stud grid u put 4)
	return math.round(toRound/roundTo) * roundTo
end

Thanks! But it doesn’t solve my problem though.

2 Likes

I’m biased but use this: GridPlacer: Highly-featured module for part placement, rotation, and snapping to grid

2 Likes

I’m using an npc that auto builds instead of the player.

2 Likes

It will also work for that. It only needs a raycast result, which the NPC can give.

3 Likes

Theres a problem, the part does not spawn on top of the surface, it spawns half way.

local rayDirection = (characterPrimary.CFrame.LookVector - characterPrimary.CFrame.UpVector * placeBlockAngle).Unit * 8
local raycastResult = workspace:Raycast(rayOrigin, rayDirection, placeBlockRaycastParams)
local surfaceCFrame, surfaceLocalPosition = placer.SnapSurfaceCFrame(raycastResult)

if raycastResult then
	local hitPosition = raycastResult.Position
	local hitPart = raycastResult.Instance
	
	VisualBlock.CFrame = surfaceCFrame
end
2 Likes

Read the example in the documentation linked on my post.

3 Likes

Can you tell me what modelHandleWorldCFrame is? Is that an attachment to the model?

local surfaceCFrame, surfaceLocalPosition = placer.SnapSurfaceCFrame(raycastResult)
local ppSpaceAttachmentCFrame = VisualBlock.PrimaryPart.CFrame:ToObjectSpace(modelHandleWorldCFrame)
surfaceLocalPosition = surfaceCFrame * ppSpaceAttachmentCFrame:Inverse()
VisualBlock:PivotTo(surfaceLocalPosition)
2 Likes

The model handle can be a part or attachment, its CFrame (in world space) is the location you want to use to place the model. It the handle is an attachment, then its the WorldSpaceCFrame property, if its a part, its just that part’s CFrame property.

It should be on the surface you want to place against, so an attachment is preferable. Its rotation matters, and the correction rotation described in the pdf will make it so you can just use the default rotation when an attachment is placed using the studio tool for it.

image

2 Likes

Does it work if you place it on the side of a part?

2 Likes

The dragged model will be rotated so that the handle has the same orientation relative to the surface being dragged over.

2 Likes

Doesn’t seem to work.

local surfaceCFrame, surfaceLocalPosition = placer.SnapSurfaceCFrame(raycastResult)
local ppSpaceAttachmentCFrame = VisualBlock.CFrame:ToObjectSpace(VisualBlock.HandleAttachment.WorldCFrame)
surfaceLocalPosition = surfaceCFrame * ppSpaceAttachmentCFrame:Inverse()
VisualBlock.CFrame = surfaceLocalPosition
2 Likes

Picture seems to show it working. What is wrong with it.

2 Likes

No, its a picture of the attachment. The block still stays half way to the raycast hit position.

1 Like

I can’t tell what you want it to look like.

1 Like

I want the block to be above the raycast hit part.

1 Like

Where is the raycast hit part?

1 Like

local raycastResult = workspace:Raycast(rayOrigin, rayDirection, placeBlockRaycastParams)

my old placement code worked but only on the top surface:

local newSnapValue = snapValue / 2

if surfaceNormal == Vector3.new(0, 1, 0) then
				blockOffset = Vector3.new(0, newSnapValue, 0) -- Place block above the surface
			elseif surfaceNormal == Vector3.new(0, -1, 0) then
				blockOffset = Vector3.new(0, -newSnapValue, 0) -- Place block below the surface
			elseif surfaceNormal == Vector3.new(1, 0, 0) then
				blockOffset = Vector3.new(newSnapValue, 0, 0) -- Place block to the right of the surface
			elseif surfaceNormal == Vector3.new(-1, 0, 0) then
				blockOffset = Vector3.new(-newSnapValue, 0, 0) -- Place block to the left of the surface
			elseif surfaceNormal == Vector3.new(0, 0, 1) then
				blockOffset = Vector3.new(0, 0, newSnapValue) -- Place block in front of the surface
			elseif surfaceNormal == Vector3.new(0, 0, -1) then
				blockOffset = Vector3.new(0, 0, -newSnapValue) -- Place block behind the surface
			end
1 Like

None of this tells me what you expect it to look like. Can you post a picture of where you want the block to be (like as a different color) and where its actually placing it?