Placing blocks sometimes places on the wrong side

I am trying to make a placing block system where it places on other blocks based on where the player puts their mouse on a face. But there’s a problem, sometimes it doesnt place on the correct face and I need to be like under 25 degrees of facing the face where I want to place the block, if I try to place on like 85 degrees for bridging for example, it places it completely the wrong way or doesn’t even register where the player placed a block on. Here is the local script that gets the placement:

UserInputService.InputBegan:Connect(function(input, gameProcessed)
	local hand = camera:FindFirstChild("Hand")
	if gameProcessed or not hand then return end

	if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
		mouseIsDown = true
		if input.UserInputType == Enum.UserInputType.Touch then
			local now = tick()
			if now - lastTapTime <= doubleTapThreshold and lastTarget then
				local mousePos = UserInputService:GetMouseLocation()
				local unitRay = workspace.CurrentCamera:ScreenPointToRay(mousePos.X, mousePos.Y)
				local raycastParams = RaycastParams.new()
				raycastParams.FilterDescendantsInstances = {localPlayer.Character}
				raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

				local raycastResult = workspace:Raycast(unitRay.Origin, unitRay.Direction * 1000, raycastParams)
				if raycastResult then
					local normal = raycastResult.Normal
					local pos = raycastResult.Position
					local cf = CFrame.new(pos, pos + normal) * CFrame.Angles(math.rad(-90), 0, 0) * CFrame.new(0, 0.5, 0)
					remoteEvent:FireServer("PlaceBlock", hand.Position, lastTarget, localPlayer.Inventory.SelectedSlot.Value, normal, cf)
				end
			end
			lastTapTime = now
		end

		if lastTarget then
			remoteEvent:FireServer(lastTarget, hand.Position)
		else
			if not swingLoopRunning then
				swingLoopRunning = true
				task.spawn(function()
					while mouseIsDown and not lastTarget and not miniBlockTarget do
						remoteEvent:FireServer("None", hand.Position)
						task.wait(0.3)
					end
					swingLoopRunning = false
				end)
			end
		end
	elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
		rightMouseIsDown = true
		if lastTarget then
			local mousePos = UserInputService:GetMouseLocation()
			local unitRay = workspace.CurrentCamera:ScreenPointToRay(mousePos.X, mousePos.Y)
			local raycastParams = RaycastParams.new()
			raycastParams.FilterDescendantsInstances = {localPlayer.Character}
			raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

			local raycastResult = workspace:Raycast(unitRay.Origin, unitRay.Direction * 1000, raycastParams)
			if raycastResult then
				local normal = raycastResult.Normal
				local pos = raycastResult.Position
				local cf = CFrame.new(pos, pos + normal) * CFrame.Angles(math.rad(-90), 0, 0) * CFrame.new(0, 0.5, 0)
				remoteEvent:FireServer("PlaceBlock", hand.Position, lastTarget, localPlayer.Inventory.SelectedSlot.Value, normal, cf)
			end
		end
	elseif input.UserInputType == Enum.UserInputType.Keyboard and input.KeyCode == Enum.KeyCode.Q then
		remoteEvent:FireServer("DropBlock", hand.Position, lastTarget, localPlayer.Inventory.SelectedSlot.Value)
	end
end)
2 Likes

if you tap the screen with percision and tap in the location you want the block to be placed the block will be placed there

1 Like

your code is very unreadable and messy I recommend you clean up your code and make it more optimized so its easier for ME to help you

1 Like

Please do not troll when I am asking for help for this post.

I’m giving you actual advice I’ll help you more now

1 Like

90 deg is not 25 degrees you did say you want a 25 degree offset for the cframe after placing the block on hit position * raycast.Normal

I think the problem is right here..

CFrame.new(pos, pos + normal) * CFrame.Angles(math.rad(-90), 0, 0)

Replace that with this block and test it..

local pos = raycastResult.Position
local normal = raycastResult.Normal
local up = Vector3.yAxis
if math.abs(normal:Dot(up)) > 0.9 then
	up = Vector3.xAxis
end
local right = normal:Cross(up).Unit
local back = right:Cross(normal).Unit
local cf = CFrame.fromMatrix(pos + normal * 0.5, right, normal, back)

Even if this isn’t totally right, I still think that line is the problem.. gl.

1 Like

Works for bridging except this happens for some reason, and yes the cursor frame is positioned correctly with the mouse

dude I have the answer to ur problem

just do this

function snapvector3(vector: vector3, mult: number)
	local x = math.floor((vector.X / mult) + 0.5) * mult
    local y = math.floor((vector.Y / mult) + 0.5) * mult
    local z =  math.floor((vector.Z / mult) + 0.5) * mult

    return Vector3.new(x, y, z)
end

block.Position = snapvector3(raycastresult.Position)

just make the block placement snap to a grid I mean thats what you’re trying to do in the video

I made a system similar to yours using this kind of method

Tried using that but it still acts the same, the problem is the the local script itself not firing the correct direction where the player clicked the block at.

Hard one without something to mess around with.. Looks pretty close, keep testing.

I have a simple mathematical formula that can help you, but you need to know the size of the object.

cube.Position = (Ray.Position + cube.Size * Ray.Normal / 2) // grid * grid

1 Like