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
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
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