How do I make a building grid place a block that is a different size?

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? I would like to make a building grid (Already achieved, places 2 by 2 by 2) that can place different sized blocks (For example: 4 by 2 by 6)

  2. What is the issue? When I try to place these different sized blocks, they would go through the ground because of how the grid is setup.

  3. What solutions have you tried so far? Well, This works if each axis are the same. But with the example above: 4 by 2 by 6, one or two axis would go through a wall.

Here is my code

   
	local part = game.ReplicatedStorage.Building:WaitForChild(partCategory):WaitForChild(partName):Clone()
	
	-- only define raycastParams once at the top for speed
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	raycastParams.FilterDescendantsInstances = {plr.Character, part, game.Workspace.PlayerZones} -- this might error with with no character, if so add to character added event.

	--cast, back in the mouse.Move
	-- 500 is just the distance, its really big you can decrease it if you need.
	local raycastResult = workspace:Raycast(unitRay.Origin, unitRay.Direction * 500, raycastParams )
	
	
	
	if raycastResult then
		
		
		local BlockPosition = getBlockPosition(raycastResult.Position + raycastResult.Normal * part.Size.Y / 2) -- change the 1 to whatever half your block size is.
		if isInsideBrick(BlockPosition, plrZone) then
			
		
		part.Parent = plrFolder
		part.Position = BlockPosition
			part.Orientation = orient
		else
			part:Destroy()
		end
	end

All help is appreciated (This is all on the server side)

1 Like

Hey, sorry for the late reply but I think I figured out a way of doing this, so here it goes.

if raycastResult then
    --grideSize: number
    local blockOrigin = getBlockPosition(raycastResult.Position + raycastResult.Normal * gridSize/2) -- change part size to whatever half the grid size is
    local originCF = CFrame.lookAt(blockOrigin, blockOrigin + raycastResult.Normal)

    --[[
        blockSize: Vector3
        rotation: CFrame
        where blocksize is the size of the part and rotation is the CFrame.Angles for rotation
    ]]
    local blockCF = originCF * (CFrame.new(blockSize/2 - Vector3.new(gridSize/2, gridSize/2, gridSize/2)) * rotation)
    --[[
        add half of the size of the block to get its centre
        A vector representing half a grid has to be subtracted as blockOrigin is also offset by half gridesize
    ]]

    -- block: BasePart
    block.CFrame = blockCF
end

I added types to the variables in the comments so you can fill the variable names in from your own code. I think this should work but i havent been able to test it. Sorry for switching to CFrame.Angles from your original Orientation property

If you wanted to check if any blocks were in the way of the placement, you could use GetPartBoundsInBox. You would just pass the blocks new cframe and its size in and then loop through the result to make sure there is nothing in the way.

Would this work for something like a size like 4, 6, 10?

I am so close to solving this problem! I can touch it!!!

I just need to solve this problem:

I am getting the block position like this:


	if raycastResult then
		part.Orientation = orient
		part.Parent = plrFolder
		local BlockPositionX = getBlockPosition(raycastResult.Position + raycastResult.Normal * part.Size.X / 2).X -- change the 1 to whatever half your block size is.
		local BlockPositionY = getBlockPosition(raycastResult.Position + raycastResult.Normal * part.Size.Y / 2).Y
		local BlockPositionZ = getBlockPosition(raycastResult.Position + raycastResult.Normal * part.Size.Z / 2).Z
		local BlockPosition = Vector3.new(BlockPositionX, BlockPositionY, BlockPositionZ)
		if isInsideBrick(BlockPosition, plrZone) then
			
		
		
		part.Position = BlockPosition
			
		else
			part:Destroy()
		end
	end

But, this only works well on the X Axis? Why???

I’m not really sure what your error is because you haven’t attached any images but I assume it’s because you are not respecting the block’s normal.
This should be fixed by creating a CFrame at the block position and making it face the normal.

local BlockPosition = Vector3.new(BlockPositionX, BlockPositionY, BlockPositionZ)
local BlockCFrame = CFrame.lookat(BlockPosition, BlockPosition + raycastResult.Normal)
if isInsideBrick(BlockPosition, plrZone) then
    part.CFrame = blockCFrame
else

If this doesn’t work can you attach some images of what is happening in your current code so I can see what is happening.

Attempt to call a nill value.

local BlockCFrame = CFrame.lookat(BlockPosition, BlockPosition + raycastResult.Normal)

CFrame.lookAt sorry - this is for extra words

1 Like

Seems like it only works with blocks that are 1x1

When I try to place a 1x3 it just, doesn’t place.

No errors, it just doesn’t exist. I checked workspace

Can I please have the context to this problem, like the code or the place file with the building system? It’s very hard to try and solve a problem when replies are so spaced out and I have very little code to work off.

Sorry, I was using the code from

I always check this late at night, so I have a hard time thinking.

That’s fine, I will sit down in an hour or two and try and code a solution for this.

Ok, I got a chance to sit down and code this solution out and this is what I came up with.
MultiSizeBlockPlacement.rbxl (31.1 KB)

The solution shows the position the box will be placed in relative to the mouse. I did not code block placement as I just wanted the basic algorithm. You will also have to account for some clipping cases using GetPartBoundsInBox.
This solution only accounts for the client-side so you will have to figure out server-side stuff.

To change the size of the block find the Vector3Value in the workspace named BlockSize and set it to your liking to play around. The unit block is 4,4,4 as that is the size of the default Roblox grid pattern. I also added rotation, but it does not have user input (you will have to code that). It can be changed at the top of the BlockPlacement Module under the name rotation(remember it’s in radians so use math.rad).

I hope this solution helps you out and you are able to implement it into your game accordingly.

2 Likes

Hi, I was implementing your solution and I cannot seem to fix this error…

invalid argument #1 (CFrame expected, got Vector3)

Here is line 42

local blockCF = originCF * CFrame.new((part.Size/2 * Vector3.new(2,2,2)) - Vector3.new(2,2,2)/2)

This is a error from implementing your code. But your code works great in the world you sent me!

I found the answer to the problem. OriginCF is a Vector3

But now idk why its a vector3

Here is the line:

local originCF = CFrame.lookAt(blockOrigin, blockOrigin + raycastResult.Normal) * CFrame.Angles(-math.pi/2,0,0) * orient

Tysm for helping me btw :slight_smile:

Does the solution work for you now? Sorry I couldn’t help I was asleep.

1 Like

Please read my latest post…

:slight_smile:

What is the type of the orient variable? If you are using a vector rotation it won’t work. You have to use CFrame.Angles.

image
A CFrame * Vector3 returns a vector so you have to use CFrame.Angles

Ah, makes sense. It is a vector3! Does Cframe.Angles(Vector3) work?

NVM read docs

Testing it out now :slight_smile:

I don’t understand what happening?

The blocks seem to not be going where I click, and they are also curved…

No errors on my end.
Like UMMMMMM…
image

Alright, I am going to just give up on this.
image

Any ideas of how @rickje139 and @madattak manages to do this (Well kinda) in Plane Crazy?

Rick it would mean a lot if you helped me here