How do I make my building system that can build to the side of an part?

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

  1. I would like to make a building system. Almost like plane crazy or build a boat for treasure.

  2. I would like to be able to build on the blocks, not inside the blocks robloxapp-20210914-1853114.wmv - Google Drive
    (Sorry about low-quality video)

  3. I was unable to find a solution.
    Here is my code (Client sided)

   local LocalPlayer = game.Players.LocalPlayer
local selectionBox = game.ReplicatedStorage.Selection:Clone()
selectionBox.Parent = game.Workspace
local Mouse = LocalPlayer:GetMouse()
Mouse.TargetFilter = selectionBox
local function getBlockPosition(vector3)
	local posX =  math.ceil(vector3.X/2 - .5)*2
	local posY =  math.ceil(vector3.Y/2 - .5)*2 + 1
	local posZ =  math.ceil(vector3.Z/2 - .5)*2
	return Vector3.new(posX, posY, posZ)
end

Mouse.Move:Connect(function()
	
	local MousePosition = Mouse.Hit.p
	local BlockPosition = getBlockPosition(MousePosition)
	selectionBox.Position = BlockPosition
end)
Mouse.Button1Down:Connect(function()
	
	local MousePosition = Mouse.Hit.p
	game.ReplicatedStorage.Events.Place:FireServer("Blocks", "Block1x1", MousePosition)
	local placeSound = game.ReplicatedStorage.Place:Clone()
	placeSound.Parent = game.Workspace.CurrentCamera
	placeSound.Playing = true
	wait(placeSound.TimeLength)
	placeSound:Destroy()
end)

And Placement Code (Server Sided)

   local function getBlockPosition(vector3)
	local posX =  math.ceil(vector3.X/2 - .5)*2
	local posY =  math.ceil(vector3.Y/2 - .5)*2 + 1
	local posZ =  math.ceil(vector3.Z/2 - .5)*2
	return Vector3.new(posX, posY, posZ)
end

game.ReplicatedStorage.Events.Place.OnServerEvent:Connect(function(plr, partCategory, partName, pos)
	local plrFolder = game.Workspace.PlayerCreations:WaitForChild(plr.Name .. "Build")
	local part = game.ReplicatedStorage.Building:WaitForChild(partCategory):WaitForChild(partName):Clone()
	part.Parent = plrFolder
	part.Position = getBlockPosition(pos)
end)

Don’t mind the security issue about this. I can handle that later.
All help is appreciated :slight_smile:

2 Likes

I tried editing how it rounds to the nearest 2 studs, but nothing I tried worked.

1 Like

For the solution I am thinking of, it would require you to switch to a raycast system instead of mouse.hit. This is because mouse.hit doesn’t provide the surfaces normal. With the normal and the raycast position, you would add the position and the normal * half the block size and then do your rounding method. This would offset the block from the hit position.

1 Like

Okay, how can I do all of this? Can you provide me an example with some docs? I never tried using raycast.
Thanks for replying btw

Firstly, here is the docs for raycasting. To cast a ray from the camera position, we need the mouse’s position on the screen. Then the Camera(workspace.CurrentCamera) method ScreenPointToRay can be used.

--this is for the mouse.Move
local mousePosition = UserInputService:GetMouseLocation()
local unitRay = camera:ViewportPointToRay(mousePosition.X, mousePosition.Y)

This will return a unitRay with the position and direction to cast the raycast in.

-- only define raycastParams once at the top for speed
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = {player.Character, selectionBox} -- this might error with with no character, if so add to character added event.

--cast, back in the mouse.Move
-- 500 is just the distance, its really big you can decrease it if you need.
local raycastResult = workspace:Raycast(unitRay.Origin, unitRay.Direction * 500, raycastParams )

then if there is a raycastResult we can position the selection box

if raycastResult then
    local BlockPosition = getBlockPosition(raycastResult.Position + raycastResult.Normal * 1) -- change the 1 to whatever half your block size is.
    --position the selection block
end

I think because of this method you can get rid of the posY + 1, because the normal should account for it.
The mouse button down code would be done the same way, so I won’t do it. I hope this works and helps.

2 Likes

I received an error:

image

I will read the docs about this

oops its meant to be FilterDescendantsInstances, my bad.

1 Like

Thank you so much!!! It works! I will also use this for the place event later, may ask for help if needed. But I will mark as solution!!
Also mind editing your mistake so others can use it without errors?

1 Like

Uh oh. Ran into another error…

Code (Server sided)

local function getBlockPosition(vector3)
	local posX =  math.ceil(vector3.X/2 - .5)*2
	local posY =  math.ceil(vector3.Y/2 - .5)*2 + 1
	local posZ =  math.ceil(vector3.Z/2 - .5)*2
	return Vector3.new(posX, posY, posZ)
end

local UserInputService = game:GetService("UserInputService")
game.ReplicatedStorage.Events.Place.OnServerEvent:Connect(function(plr, partCategory, partName, pos, camera)
	local plrFolder = game.Workspace.PlayerCreations:WaitForChild(plr.Name .. "Build")
	local mousePosition = UserInputService:GetMouseLocation()
	local unitRay = camera:ViewportPointToRay(mousePosition.X, mousePosition.Y)
	local part = game.ReplicatedStorage.Building:WaitForChild(partCategory):WaitForChild(partName):Clone()
	part.Parent = plrFolder
	-- only define raycastParams once at the top for speed
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	raycastParams.FilterDescendantsInstances = {plr.Character, part} -- this might error with with no character, if so add to character added event.

	--cast, back in the mouse.Move
	-- 500 is just the distance, its really big you can decrease it if you need.
	local raycastResult = workspace:Raycast(unitRay.Origin, unitRay.Direction * 500, raycastParams )
	
	
	
	if raycastResult then
		local BlockPosition = getBlockPosition(raycastResult.Position + raycastResult.Normal * 1) -- change the 1 to whatever half your block size is.
		part.Position = BlockPosition
	end
end)

Client Side:

local LocalPlayer = game.Players.LocalPlayer
local selectionBox = game.ReplicatedStorage.Selection:Clone()
selectionBox.Parent = game.Workspace
LocalPlayer.CharacterAdded:Wait()
local UserInputService = game:GetService("UserInputService")
local camera = game.Workspace.CurrentCamera
local Mouse = LocalPlayer:GetMouse()
Mouse.TargetFilter = selectionBox
local function getBlockPosition(vector3)
	local posX =  math.ceil(vector3.X/2 - .5)*2
	local posY =  math.ceil(vector3.Y/2 - .5)*2
	local posZ =  math.ceil(vector3.Z/2 - .5)*2
	return Vector3.new(posX, posY, posZ)
end

Mouse.Move:Connect(function()
	--this is for the mouse.Move
	local mousePosition = UserInputService:GetMouseLocation()
	local unitRay = camera:ViewportPointToRay(mousePosition.X, mousePosition.Y)
	-- only define raycastParams once at the top for speed
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	raycastParams.FilterDescendantsInstances = {LocalPlayer.Character, selectionBox} -- this might error with with no character, if so add to character added event.

	--cast, back in the mouse.Move
	-- 500 is just the distance, its really big you can decrease it if you need.
	local raycastResult = workspace:Raycast(unitRay.Origin, unitRay.Direction * 500, raycastParams )
	
	if raycastResult then
		local BlockPosition = getBlockPosition(raycastResult.Position + raycastResult.Normal * 1) -- change the 1 to whatever half your block size is.
		--position the selection block
		selectionBox.Position = BlockPosition
	end
	
end)
Mouse.Button1Down:Connect(function()
	
	local MousePosition = Mouse.Hit.p
	game.ReplicatedStorage.Events.Place:FireServer("Blocks", "Block1x1", MousePosition, camera)
	local placeSound = game.ReplicatedStorage.Place:Clone()
	placeSound.Parent = game.Workspace.CurrentCamera
	placeSound.Playing = true
	wait(placeSound.TimeLength)
	placeSound:Destroy()
end)

The move event works fine though!

Its just the click event… I dont think there should be a problem considering I am passing all the info needed?

OHH wait I forgot about the UserInputService, I will try to fix it in a second :slight_smile:

With the click event, send the position the client wants to put the block to the server and then sanity check it and stuff. The unitRay method won’t work on the server as you cant get the players camera or their mouse position on the server.

Already done! works well!!! Thank you so much for your help
image

1 Like

Hello, new problem! This is about if the blocks are different sizes. Here it is: How do I make a building grid place a block that is a different size?