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