Hello, this is Kevman599 again, so I am working on a bloxburg type build mode system and currently the walls and paths and furniture that is currently implemented into the build mode options is able to be placed anywhere your camera can view. I need it to stay in the grid, how would I go about doing this. Examples of what is the problem down below
You can check if the furniture is inside the +X, -X and +Z,-Z corners of the grid.
if furniture.Position.X <= maximumX and furniture.Position.X >= minimumX and furniture.Position.Z <= maximumZ and furniture.Position.Z >= minimumZ then
place()
end
Say minimum X is (-1,0,0) and minimum Z is (0,0,-1)
and that maximum X is (1,0,0) and maximum Z is (0,0,1).
If the furniture is in (0,0,0) then it will be placeable.
You can get the position of your grid and add that to how big your grid is. So you would get the corner positions and check if the furniture position is inside.
grid.Position = (10,0,0)
grid.Size = (5,0,5)
local minX = grid.Position.X - grid.Size.X/2
local minZ = grid.Position.Z - grid.Size.Z/2
local maxX = grid.Position.X + grid.Size.X/2
local maxZ = grid.Position.Z + grid.Size.Z/2
if furniture.Position.X <= maxX and furniture.Position.X >= minX and furniture.Position.Z <= maxZ and furniture.Position.Z >= minZ then
place()
end
So the minimum X here would be 5, the maximum X would be 15. The minimum Z would be -5, and the maximum Z would be 5. If the furniture is at (7,0,3) then it would be placeable.
Where would I place these scripts? And why would I place them there (I am trying to learn sorry)
Whatever script you are using to place the furniture. Both of the codes that I put are just examples. Using math you can find whether the furniture is inside the width and the length of your grid. Getting the center of your grid is the position and the corners you get by adding half the width and half the length both positively and negatively. So if your grid is located at (0,0,0) and the width is 4 and the length is 6 then you would get half of that and add/subtract that to the grid’s position. (2,0,0) for the max X, (-2,0,0) for the min X, (0,0-3) for the min Z, (0,0,3) for the max Z.
Sounds good, I have marked your comment as solution! Now I better get some sleep, it is 3am in the morning, haha.
Alright I hope that solves your issue and eventually you get a cool building system going. I find that having good rest helps me feel better while I’m coding.
The solution posted by @SFTybo will make sure that the center of a placed part will be on the grid. However, it doesn’t make sure that the whole part (or model, if you’re going to use models too) is on the grid. If this isn’t a problem for you, his solution will work. But if you want to make sure the whole part or model is in the grid, you’ll need something more complicated. How complicated it needs to be depends on how your build system works.
I made a function that can be used to make sure that the whole thing is on the grid. It uses CFrame math to check if every corner of the part or every corner of every part in a model is on the grid. It has a variable for the longest distance a corner outside the grid is away from the edge, for both x and z axis. While going through the corners it updates a longest value variable if it finds out that a corner is further away from the edge on the corresponding local axis of the grid than any edge checked before.
After it has found the longest distance from its edge on its x and z axis, it calculates a valid CFrame and returns that CFrame. If the item you are placing is a model, it needs to have a PrimaryPart and the CFrame that you give this function must be the CFrame where the PrimaryPart of the model would be placed. as the first argument, before the CFrame, you give the part (if you are placing a single part) or the model.
This function should work for both models and parts, even if they are rotated. However, the calculations aren’t very efficient (The function could probably be optimised to avoid doing calculations when it’s unnecessary, but I’m not sure how.). This can be a problem if your model has a lot of parts. If that’s the case, you could probably have a bounding box part and weld the other parts to that. Then, instead of giving the model to the function, give it the bounding box part and the CFrame of the bounding box part. After placing the model, if you want, you can anchor the parts and Destroy the welds or Weldconstraints and the boundingBox, unless you need to be able to move it again.
Here’s the whole thing. It consists of one main function and helper functions that the main function uses. The function makeSureObjIsInGrid is the main function that you give the arguments.
local function getCornerCfs(cf, size)
local cornerCfs = table.create(8)
local hxs, hys, hzs = size.X/2, size.Y/2, size.Z/2
local i = 0
-- repeat for each corner of the part using the loop and multipliers in it
for ix = 1, 2 do
local xm =(-1)^ix
for iy = 1, 2 do
local ym =(-1)^iy
for iz = 1, 2 do
local zm =(-1)^iz
i += 1
cornerCfs[i] = cf*CFrame.new(xm*hxs, ym*hys, zm*hzs)
end
end
end
return cornerCfs
end
local function getExtra(cf, size, gridCenterInverse, xLimit, zLimit) -- this is a separate function to avoid code repetition
local hxs, hys, hzs = size.X/2, size.Y/2, size.Z/2
local largestExtraX, largestExtraZ = 0, 0
-- repeat for each corner of the part using the loop and multipliers in it
local cornerCfs = getCornerCfs(cf, size)
for i, cornerCf in ipairs(cornerCfs) do
local cornerX, cornerZ = cornerCf.X, cornerCf.Z
-- getting what the offset of this spesific corner of the part would be to the GRID_CENTER
-- If the object given to makeSureobjIsInGrid is a model, this is
-- the CFrame the corner would have if the PrimaryPart of the model would be set to the CFrame given to
-- the makeSureObjIsInGrid
-- if this is a single part not in a model, then the corner's Cframe this checks is the cframe where the corner would be if
-- the CFrame given to makeSureObjIsInGrid would be the CFrame of the part
local relCf = gridCenterInverse*cornerCf
local relX, relZ = relCf.X, relCf.Z
local negX, negZ = relX < 0, relZ < 0
-- this is how much the corner is too far away from the GRID_CENTER on the local x and z axes of the GRID_CENTER
local extraX, extraZ = relX-(negX and -xLimit or xLimit), relZ-(negZ and -zLimit or zLimit)
-- here the script checks if it is further away than any corner checked before
-- and if it is, the largest value will be updated
if math.abs(relX) > xLimit and ((negX and extraX < largestExtraX) or (not negX and extraX > largestExtraX)) then
largestExtraX = extraX
end
if math.abs(relZ) > zLimit and ((negZ and extraZ < largestExtraZ) or (not negZ and extraZ > largestExtraZ)) then
largestExtraZ = extraZ
end
end
return largestExtraX, largestExtraZ
end
-- When using this for models, the cf should be the CFrame that the model's PrimaryPart would be set to if that CFrame was already valid
-- the gridcenter must be a CFrame, the sizes are the sizes of the grid on the local x- and z- axes of the gridCenter
local function makeSureObjIsInGrid(obj, cf, gridCenter, gridXSize, gridZSize)
local gridCenterInverse, xLimit, zLimit = gridCenter:Inverse(), gridXSize/2, gridZSize/2
if obj:IsA("BasePart") then
local extraX, extraZ = getExtra(cf, obj.Size, gridCenterInverse, xLimit, zLimit)
-- relative CFrame of the part on the local axis of GRID_CENTER
-- (gridCenter is kind of like treated as the center of the world)
local relCf = gridCenterInverse*cf
local newPartCf = GRID_CENTER*(relCf-Vector3.new(extraX, 0, extraZ))
return newPartCf
elseif obj:IsA("Model") then -- you'll probably use models when you make furniture
-- make sure that if you use models the PrimaryPart is set. Otherwise this will error.
local realPrimaryPartCfInverse = obj:GetPrimaryPartCFrame():Inverse()
local largestExtraX, largestExtraZ = 0, 0 -- variable names may be missleading, the extra values can also be negative
for i, v in ipairs(obj:GetDescendants()) do
if v:IsA("BasePart") then
local realPartCf = v.CFrame
-- giving the getExtra function a CFrame that is relative to the cf the same way as
-- the current CFrame of the part is relative to the current PrimaryPartCFrame of the model
local extraX, extraZ = getExtra(cf*(realPrimaryPartCfInverse*realPartCf), v.Size, gridCenterInverse, xLimit, zLimit)
local negX, negZ = extraX < 0, extraZ < 0
-- changing the largestValues if distance from edge is larger than any distance found until this
-- and updating maxValueif it is
if math.abs(extraX) > math.abs(largestExtraX) then
largestExtraX = extraX
end
if math.abs(extraZ) > math.abs(largestExtraZ) then
largestExtraZ = extraZ
end
end
end
-- offset between the two cframes on the local axis of the center CFrame of the grid
local relCf = gridCenterInverse*cf
-- This will be set as the CFrame of the PrimaryPart. It's calculated by using the relative offset (relCf)
-- and substracting the extras from that and then kind of moving the GRID_CENTER on it's own axis with the resulting CFrame.
-- The value of GRID_CENTER isn't changed, of course. This is a new CFrame value.
local newPrimaryCf = GRID_CENTER*(relCf-Vector3.new(largestExtraX, 0, largestExtraZ))
return newPrimaryCf
end
end
Where would I place this script?
Just like the script from @SFTybo, place this in the script where you do the placement. Then, when you have a CFrame for placing the item, before you place it, use this function to make sure the CFrame is valid(the whole item is on the grid). To be able to use this in the correct place, this must be somewhere above the line where you place the furniture item.
Alright, thx il go test it now.