I’ve mostly fixed it, but before I send it over I have a couple of questions that might help with future issues. Do you want the snapping behavior to go to the edge even though it doesn’t fall on the grid (a place where it wouldn’t normally snap in any other condition)? Or do you want it to not go all the way to the edge because of that stopping at the nearest snap point? The buildpart is not in a snapped position or size itself, so it can lead to inconsistencies. Additionally the code stops letting you make adjustments the moment you leave the baseplate even on the axis you are still free to move on. Is this intentional behavior or do you want it to update where it can always?
I honestly don’t think I need snapping behavior. I just need something similar to meep city build system. Meep City doesn’t use a snap system I believe.
-- Placement Controller
-- Username
-- January 27, 2021
local PlacementController = {}
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Folder = ReplicatedStorage.GameClient
local Models = Folder.Models
local char = player.Character or player.CharacterAdded:Wait()
local Sign = Models.Sign:Clone()
local Grid = 0.5
local PosX
local PosY
local PosZ
local Part = game.Workspace.Part
Sign.Parent = game.Workspace
-- Customize:
local range = 250 -- Mouse object move range
function PlacementController:GetMousePoint(ignoreList)
if mouse.Target ~= nil then
local unitRay = camera:ScreenPointToRay(mouse.x, mouse.y)
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = ignoreList
local ray = workspace:Raycast(unitRay.Origin, unitRay.Direction * range, raycastParams)
if ray then
return ray.Position, ray.Instance, ray.Normal
end
end
end
local base = Part
function Snap(position)
local fakeSize = (base.Size - Sign.PrimaryPart.Size)/2
PosX = base.Position.X + math.clamp(position.X-base.Position.X, -fakeSize.X, fakeSize.X)
PosZ = base.Position.Z + math.clamp(position.Z-base.Position.Z, -fakeSize.Z, fakeSize.Z)
PosY = base.Position.Y + base.Size.Y/2--position.Y --You can change this back if you want it to be able to stack on top of parts or things, but with just Position.Y you will let it fall on the Y axis if the mouse hits the side of the brick
end
function PlacementController:Start()
local ignoreList = {char, Sign}
RunService.RenderStepped:Connect(function()
local position, target, normal = self:GetMousePoint(ignoreList)
if target == game.Workspace.Part then
Snap(position)
Sign:SetPrimaryPartCFrame(Sign.PrimaryPart.CFrame:Lerp(CFrame.new(PosX,PosY, PosZ) * CFrame.new(0, 2, 0), 0.5))
end
end)
end
function PlacementController:Init()
end
return PlacementController
Yes. A grid snap can easily be implemented. However it can be a little confusing. The buildplate you have does not have a size or a position divisible by Grid. This means that it can’t really be snapped as is because you could end up snapping it past the buildplate. And if you align the buildplate to something that divides by grid with no decimals, you could have a similar issue if the model containers size isn’t also grid aligned. To snap it, you pretty much just need to make the min of cap the lowest possible spot it can be with grid snapping and max the highest it could be with grid snapping, then you can just snap it the way you have done before after that.