Creating A Placement System For Walls(Interiors)

Hello, some time ago I was trying to make a wall placement system but I didn’t find any post useful because there was a lack of explanation and maybe a lack of posts trying to achieve my goal, but now, I found the easiest and cleanest solution and I will share here so anybody that it’s interested in creating something like this could go ahead :wink:

What do we want to achieve?

Placement system that adjusts to every surface with or without rotation like the following one

What is this for?

  • You can create a furniture placement system for interiors and exteriors.
  • Block placement system like Islands.
  • Tycoon sandbox games.

What we can do with the code?

You can use the code snippet as you want to create a very complex placement system, you can send a direct message with any troubles that you may have while trying to achieve that.

Motivation


Let’s start using a custom mouse module, you can create a ModuleScript named “Mouse” and put it wherever you want

local mouse = {}

--

function mouse:GetPosition(TargetFilter: { Instance }, FilterType: Enum.RaycastFilterType)
	local mouseLocation: Vector2 = game:GetService("UserInputService"):GetMouseLocation()
	local x: number, y: number = (mouseLocation.X - 4), (mouseLocation.Y - 36);

	local params: RaycastParams = RaycastParams.new()
	params.FilterDescendantsInstances = TargetFilter
	params.FilterType = FilterType

	local unitRay = workspace.CurrentCamera:ScreenPointToRay(x, y, 2)
	local result = workspace:Raycast(unitRay.Origin, unitRay.Direction * 500, params)

    if not result then
	    return {}
    end

	return {
		rayDirection = unitRay.Direction;
		rayHit = result.Position;
		rayInstance = result.Instance;
		rayNormal = result.Normal;
	}
end

--

return mouse

Now we must have something like this in the StarterPlayerScripts

imagen

The code for the placement system(Placement LocalScript) for interiors must be this

local mouse = require(script.Mouse)
local object: BasePart = workspace.Part
--- You can use the object you want, this path is just an example and you can change it.

game:GetService("RunService").Heartbeat:Connect(function()
	local info = mouse:GetPosition({ object }, Enum.RaycastFilterType.Blacklist)
	
	if info.rayHit then
		local cf = CFrame.lookAt(info.rayHit, info.rayHit + info.rayNormal)
		
		object.CFrame = cf * CFrame.new(
			0, 
			0, 
			-(object.Size.Z / 2)
			-- We must apply this to add offset to the CFrame.
		)
	end
end)

The result must be like this

Here is the place so you can copy every element and check the instances.
PlacementSystem.rbxl (30,5 KB)


If there is any error don’t be shy and post them here, I will be open to help with your questions and errors.

Make sure to check this post often, I will make the part 2 that will cover clamping to bounds and snapping to grid, it will be marked as the solution once it’s released

11 Likes

I forgot to mention that this is a revamp of this guide as it only works with one face and it’s basically a pivot point.

The maths are similar but he doesn’t use the bounding box, he uses a small point at the back face to position the model, I will cover a complex explanation in the second part of this tutorial.

3 Likes