I don’t see any math.clamp
functions in your code so it’s hard for me to see what’s going on, however I’ll do my best to explain how you might approach this again.
Clamp will not override a value unless that value is out of the “range” passed into the function. One thing to remember is that on Roblox and most (if not all) other game engines, the position is taken from the center of objects. To clamp an object to the bounds you have set, you need to understand how to get the corners of the object. What you can do is take the position (which will be by default, is the center) and add or subtract half of the x or z size depending on the corner you want to get to position of. Here’s an image I made quickly to show what I mean:
What you need to do, is clamp the calculated position to each corner. If you are interested in some source code on how this is done, here is the function my module Placement Service uses to calculate position and clamp bounds:
Code
-- Clamps the x and z positions so they cannot leave the plot
local function bounds(c: CFrame, cx: number, cz: number): CFrame
local pos: CFrame = plot.CFrame
local xBound: number = (plot.Size.X*0.5) - cx
local zBound: number = (plot.Size.Z*0.5) - cz
local newX: number = clamp(c.X, -xBound, xBound)
local newZ: number = clamp(c.Z, -zBound, zBound)
local newCFrame: CFrame = cframe(newX, 0, newZ)
return newCFrame
end
-- Returns a rounded cframe to the nearest grid unit
local function snapCFrame(c: CFrame): CFrame
local offsetX: number = (plot.Size.X % (2*GRID_UNIT))*0.5
local offsetZ: number = (plot.Size.Z % (2*GRID_UNIT))*0.5
local newX: number = round(c.X/GRID_UNIT)*GRID_UNIT - offsetX
local newZ: number = round(c.Z/GRID_UNIT)*GRID_UNIT - offsetZ
local newCFrame: CFrame = cframe(newX, 0, newZ)
return newCFrame
end
-- Calculates the position of the object
local function calculateItemLocation()
if currentRot then
cx = primary.Size.X*0.5
cz = primary.Size.Z*0.5
x, z = mouse.Hit.X - cx, mouse.Hit.Z - cz
else
cx = primary.Size.Z*0.5
cz = primary.Size.X*0.5
x, z = mouse.Hit.X - cx, mouse.Hit.Z - cz
end
-- Clamps y to a max height above the plot position
y = clamp(y, initialY, maxHeight + initialY)
-- Changes y depending on mouse target
if stackable and mouse.Target and mouse.Target:IsDescendantOf(placedObjects) or mouse.Target == plot then
y = calculateYPos(mouse.Target.Position.Y, mouse.Target.Size.Y, primary.Size.Y)
end
if moveByGrid then
-- Calculates the correct position
local pltCFrame = cframe(plot.CFrame.X, plot.CFrame.Y, plot.CFrame.Z)
pos = cframe(x, 0, z)
pos = snapCFrame(pltCFrame:Inverse()*pos)
finalC = pos*pltCFrame*cframe(cx, 0, cz)
else
finalC = cframe(x, y, z)*cframe(cx, 0, cz)
end
finalC = bounds(finalC)
return finalC
end
As you can see, all I do is calculate the position first, then set the finalC
variable to the clamped return value (passing in the unclamped CFrame
to the function). The basic steps done by the clamp function are:
- Find each corner
- Create new
CFrame
with clamped values
- Return new
CFrame
One thing to note is that I am also adding/subtracting the primary part’s size/2 (cx, cz). The reason for this is the same as above. Since the position is taken from the center, (unless the pivot is changed) the object would clamp to the corners but be half way out of the surface. To fix this, we can simply compensate for this by adding/subtracting half of the model/part size (X and Z) depending on each corner.
If I am misunderstanding your issue, I will need more details and code samples with the clamp function attempts to give further assistance.
Hope this helps!