Hello DevForum users!
I am trying to do a Grid System, with a grid of 3, the problem is, my system dosent work that right, when i try to position the object for some reasson it appears 0.5 studs off?
Issue i wanna solve: the 0.5 studs off.
Additionally i dont want to use specific stuff to if a object haves Even or Uneven position or stuff if its possible.
Some Screenshots:
Right now its looking like this:
I want it to be like:
Heres the code, maybe its not neccesary but just so yall can analize it better.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Modules = ReplicatedStorage:WaitForChild("Modules")
local CommunityModules = Modules:WaitForChild("CommunityModules")
local Warp = require(CommunityModules:WaitForChild("Warp"))
local BuildingObjects = ReplicatedStorage:WaitForChild("BuildingObjects")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Camera = workspace.CurrentCamera
local Add = 0.01
local placementCooldown = false
local rotationAngle = 0
local rotationStep = 90
local placementRotation = CFrame.Angles(0, math.rad(rotationAngle), 0)
shared.currentObject = nil
local Place = Warp.Client("Place")
local gridSize = 3
local function basicSnap(position)
return Vector3.new(
math.round((position.X / gridSize) + Add) * gridSize,
math.round((position.Y / gridSize) + Add) * gridSize,
math.round((position.Z / gridSize ) + Add) * gridSize
)
end
local function getWorldSizeAxes(part, sizeModel)
local cf = part.CFrame
local size = sizeModel
local xSize = math.abs(cf.RightVector.X) * size.X + math.abs(cf.UpVector.X) * size.Y + math.abs(cf.LookVector.X) * size.Z
local ySize = math.abs(cf.RightVector.Y) * size.X + math.abs(cf.UpVector.Y) * size.Y + math.abs(cf.LookVector.Y) * size.Z
local zSize = math.abs(cf.RightVector.Z) * size.X + math.abs(cf.UpVector.Z) * size.Y + math.abs(cf.LookVector.Z) * size.Z
return xSize, ySize, zSize
end
local function isEven(n)
return n % 2 == 0
end
local function snapToGrid(raycastPos: Vector3, raycastNormal: Vector3, template: BasePart, rotation: CFrame)
local TemplateParent: Model = template.Parent
local size = TemplateParent:GetExtentsSize()
local xSize, ySize, zSize = getWorldSizeAxes(template, size)
local xStuds = math.round((xSize / gridSize) + Add)
local yStuds = math.round((ySize / gridSize) + Add)
local zStuds = math.round((zSize / gridSize) + Add)
local snapped = basicSnap(raycastPos)
local offset = Vector3.zero
local absNormal = Vector3.new(math.abs(raycastNormal.X), math.abs(raycastNormal.Y), math.abs(raycastNormal.Z))
local sizeInNormalDir = Vector3.new(
absNormal.X * xSize,
absNormal.Y * ySize,
absNormal.Z * zSize
)
offset += raycastNormal * (sizeInNormalDir.Magnitude / 2)
local studsInNormalDir = math.round((sizeInNormalDir.Magnitude)+ Add)
if not isEven(studsInNormalDir) then --or currentObject.Parent:GetAttribute("IncludeOffset")
if (math.abs(raycastNormal.X) > 0.5) and (not shared.currentObject.Parent:GetAttribute("IncludeOffset") or not isEven(studsInNormalDir)) then
if raycastNormal.X < 0 then
-- warn("Negative X normal")
offset = Vector3.new(offset.X, offset.Y, offset.Z)
else
-- warn("Positive X normal")
offset = Vector3.new(offset.X, offset.Y, offset.Z)
end
end
if math.abs(raycastNormal.Y) > 0.5 then
if raycastNormal.Y < 0 then
-- warn("Negative Y normal")
-- warn("Snapped y negative")
offset = Vector3.new(offset.X, offset.Y - size.Y / 2, offset.Z)
else
--warn("Positive Y normal")
-- warn("Snapped y positive")
offset = Vector3.new(offset.X, offset.Y - size.Y / 2, offset.Z)
end
end
if (math.abs(raycastNormal.Z) > 0.5) and (not shared.currentObject.Parent:GetAttribute("IncludeOffset") or not isEven(studsInNormalDir)) then
if raycastNormal.Z < 0 then
-- warn("Negative Z normal")
offset = Vector3.new(offset.X, offset.Y, offset.Z)
else
--warn("Positive Z normal")
offset = Vector3.new(offset.X, offset.Y, offset.Z)
end
end
end
local corrected = Vector3.new(
snapped.X + offset.X,
snapped.Y + offset.Y,
snapped.Z + offset.Z
)
warn(rotation)
return corrected, rotation
end
local function validatePlacement()
if shared.currentObject then
local plot
if Player:GetAttribute("Plot") then
plot = workspace.Map.Plots:FindFirstChild(Player:GetAttribute("Plot"))
else
return false
end
local overlapParams = OverlapParams.new()
overlapParams.FilterDescendantsInstances = {shared.currentObject.Parent}
overlapParams.FilterType = Enum.RaycastFilterType.Exclude
local parts = workspace:GetPartBoundsInBox(shared.currentObject.CFrame, shared.currentObject.Size - Vector3.new(0.1,0.1,0.1), overlapParams)
local parts2 = workspace:GetPartBoundsInBox(shared.currentObject.CFrame, shared.currentObject.Size, overlapParams)
local inPlot = false
for _2, object in pairs(parts2) do
-- warn("for loop", object.Name)
if object == plot.Plot.PlotArea then
-- warn("not inside area")
inPlot = true
end
end
if not inPlot then
--warn("not in plot")
return false
end
for _, part in ipairs(parts) do
if part.Name ~= "PlotArea" then
return false
end
end
return true, plot
end
end
local function Rotate(object: Model)
if object and object.PrimaryPart then
rotationAngle = (rotationAngle + rotationStep) % 360
placementRotation = CFrame.Angles(0, math.rad(rotationAngle), 0)
end
end
local function Update()
if not shared.currentObject then return end
local NewRaycast = shared.Utilities.Raycast({shared.currentObject})
if not NewRaycast then return end
local Position, rotation = snapToGrid(NewRaycast.Position, NewRaycast.Normal, shared.currentObject.PrimaryPart, placementRotation)
local FinalPos = Position + Vector3.new(0,shared.currentObject:GetExtentsSize().Y / 2,0)
shared.currentObject.PrimaryPart.CFrame = CFrame.new(FinalPos) * rotation
end
local function RemovePlaceholder()
if not shared.currentObject then return end
shared.currentObject = nil
end
local function AddPlaceholder(Name: string)
local Object = BuildingObjects:WaitForChild(Name)
if not Object then return end
RemovePlaceholder()
local NewObject = Object:Clone()
NewObject.Parent = workspace
shared.currentObject = NewObject
local Highlight = Instance.new("Highlight", shared.currentObject)
Highlight.FillTransparency = 0.75
Highlight.FillColor = Color3.new(0.333333, 1, 0)
end
UserInputService.InputBegan:Connect(function(input, gameProcessed)
if gameProcessed then return end
if input.KeyCode == Enum.KeyCode.R then
Rotate(shared.currentObject)
end
end)
UserInputService.InputBegan:Connect(function(input, gameProccesed)
if gameProccesed then return end
if not shared.currentObject then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 then
Place:Fire(true, shared.currentObject.Name, shared.currentObject.PrimaryPart.CFrame)
end
end)
RunService.Heartbeat:Connect(Update)
AddPlaceholder("Wall")

