Grid placement having an offset that it shouldnt

Hello developers! so, im working on game based of Miners Haven, and now making the grid placement system, following a tutorial on YT, but when tried to test it, it wasnt very on where the mouse is. I tried chaging the hitbox, the values, but nothing really worked.

https://gyazo.com/3b081f69dd96664b03111244e90fe6f0

In that video, the dropper has an small offset from the mouse, which is kinda annoying.

Another image:

image

Code:

-- SETTINGS

-- BOOLS
local interpolation = true
local moveByGrid = true
local buildModePlacement = true

-- INTS
local rotationStep = 90
local maxHeight = 90

-- FLOATS
local lerpLevel = 0.7 --// 0 = Instant, 1 = No movement

-- OTHER
local gridTexture = 'rbxassetid://12796647774'
local placement = {}
placement.__index = placement

local players = game:GetService('Players')
local contextService = game:GetService('ContextActionService')
local runService = game:GetService('RunService')

local player = players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local mouse = player:GetMouse()

-- CONSTRUCTOR VARIABLES
local GRID_SIZE
local ITEM_LOCATION
local ROTATE_KEY
local TERMINATE_KEY

-- ACTIVATION VARIABLES
local object = nil
local placedObjects = nil
local plot = nil
local stackable = nil
local primary = nil

-- CALC VARIABLES
local posX, posY, posZ = 0, 0, 0
local speed = 1
local rotation = 0
local rotationVal = false

-- QUICK TYPE VARS
local cframe = CFrame.new
local angles = CFrame.fromEulerAnglesXYZ

local function renderGrid()
	local texture = Instance.new('Texture')
	texture.StudsPerTileU = GRID_SIZE
	texture.StudsPerTileV = GRID_SIZE
	texture.Texture = gridTexture
	texture.Face = Enum.NormalId.Top
	texture.Parent = plot
end

local function calcYPosition(toP, toS, oS)
	return (toP + toS * 0.5) + oS*0.5
end

local function rotate(actionName, inputState, inputOBJ)
	if inputState == Enum.UserInputState.Begin then
		rotation += rotationStep
		rotationVal = not rotationVal
	end
end

local function snap(c)
	local newX = math.round(c.X/GRID_SIZE)*GRID_SIZE
	local newZ = math.round(c.Z/GRID_SIZE)*GRID_SIZE
	return cframe(newX, 0, newZ)
end

local function calcItemPosition()
	local finalCframe = cframe(0,0,0)
	local x, z
	local offsetX, offsetZ
	
	if rotationVal then
		offsetX, offsetZ = primary.Size.X*0.5, primary.Size.Z*0.5
		x, z = mouse.Hit.X - offsetX, mouse.Hit.Z - offsetZ - offsetZ
	else
		offsetX, offsetZ = primary.Size.Z*0.5, primary.Size.X*0.5
		x, z = mouse.Hit.X - offsetX, mouse.Hit.Z - offsetZ - offsetZ
	end
	
	if stackable then
		posY = calcYPosition(mouse.Target.Position.Y, mouse.Target.Size.Y, primary.Size.Y)
	else
		posY = calcYPosition(plot.Position.Y, plot.Size.Y, primary.Size.Y)
	end
	
	if moveByGrid then
		local pltCFrame = cframe(plot.CFrame.X, plot.CFrame.Y, plot.CFrame.Z)
		local pos = cframe(x, 0, z)
		pos = snap(pos*pltCFrame:Inverse())
		finalCframe = pos*pltCFrame*cframe(offsetX, 0, offsetZ)
	else
		finalCframe = cframe(mouse.Hit.X, posY, mouse.Hit.Z)
	end
	
	finalCframe = cframe(finalCframe.X, posY, finalCframe.Z)
	
	return finalCframe*angles(0, math.rad(rotation), 0)
end

local function unbindInputs()
	contextService:UnbindAction('Rotate')
end

local function bindInputs()
	contextService:BindAction('Rotate', rotate, false, ROTATE_KEY)
end

local function translateObj()
	if placedObjects and object.Parent == placedObjects then
		calcItemPosition()
		
		object:PivotTo(object.PrimaryPart.CFrame:Lerp(calcItemPosition(), speed))
	end
end

-- 
local function verifyPlane()
	return plot.Size.X%GRID_SIZE == 0 and plot.Size.Z%GRID_SIZE == 0
end

local function approvePlacement()
	if not verifyPlane() then
		warn('The model cannot snap on the plot. Please change the plot size to fix this.')
		
		return false
	end
	
	if GRID_SIZE >= math.min(plot.Size.X, plot.Size.Z) then
		error('Grid size is too close to the size of the plot on at least one of the axis.')
		return false
	end
	
	return true
end

-- CONSTRUCTOR FUNCTION
function placement.new(g, o, r, t)
	local data = {}
	local metaData = setmetatable(data, placement)
	
	GRID_SIZE = g
	ITEM_LOCATION = o
	ROTATE_KEY = r
	TERMINATE_KEY = t
	
	data.grid = GRID_SIZE
	data.itemLocation = ITEM_LOCATION
	data.rotateKey = ROTATE_KEY
	data.terminateKey = TERMINATE_KEY
	
	return data
end

-- Does placement (id = name, pobjs = placeObjects, plt = plot, stk = stakable)
function placement:active(id, pobjs, plt, stk)
	object = ITEM_LOCATION:FindFirstChild(id):Clone()
	placedObjects = pobjs
	plot = plt
	stackable = stk
	primary = object.PrimaryPart
	rotation = 0
	
	if not approvePlacement() then
		return 'Placement could not work'
	end
	
	if not stackable then
		mouse.TargetFilter = placedObjects
	else
		mouse.TargetFilter = object
	end
	
	local tempSpeed = 1
	
	if interpolation then
		tempSpeed = math.clamp(math.abs(tonumber(1 - lerpLevel)), 0, 0.9)
		speed = 1
	end
	
	renderGrid()
	
	object.Parent = placedObjects
	
	task.wait()
	
	bindInputs()
	speed = tempSpeed
end

runService:BindToRenderStep('Input', Enum.RenderPriority.Input.Value, translateObj)

return placement
1 Like

i’d do

finalCframe = cframe(finalCframe.X + 5, posY, finalCframe.Z)

if that’s too little or too much try and change the value until it’s the value that matches it.

1 Like

It still didnt worked, i changed the number to some others but the problem is still the same.