Creating blocks around mined area

local function CreateOre(ore, position)
	ore.Parent = Mine
	ore.CFrame = position
	print(position.Y)
	if position.Y > 13995 or BlockData:FindFirstChild(tostring(ore.CFrame)) then
		ore:Destroy()
	end
	
	Instance.new('Folder', BlockData).Name = tostring(ore.CFrame)
end

For some reason, it only starts working a layer down


robloxapp-20200103-1122108
Shows that when I mine the top layer, it gets destroyed. I tried changing the code to

local function CreateOre(ore, position)
	ore.Parent = Mine
	ore.CFrame = position
	print(position.Y)
	if position.Y > 14000 or BlockData:FindFirstChild(tostring(ore.CFrame)) then
		ore:Destroy()
	end
	
	Instance.new('Folder', BlockData).Name = tostring(ore.CFrame)
end

But that creates blocks over top of other blocks

Unfortunately I don’t think we can particularly help much without knowing more about those magic numbers you use for your Y coordinates. What are the sizes of your blocks / what size grid are they aligned upon?

If you add more information on this, it will be easier for other people to figure out what your code does and find a solution to your issue :slightly_smiling_face:

(also, have you considered using a constant for your magic number?)

Blocks are 8. I use 14000 as that’s what layer the top level is at

I suspect this is a combination of multiple issues with your code.

The first change I’d make is to not use the CFrame to name your block data instances. Instead, I’d use string.format to generate a string containing the integer block position and use that instead;

local function CreateOre(ore, position)
    ore.Parent = Mine
    ore.CFrame = position

    local blockDataName = ("%d,%d,%d"):format(ore.Position.X, ore.Position.Y, ore.Position.Z)
    if position.Y > 13995 or BlockData:FindFirstChild(blockDataName) then
        ore:Destroy()
    end

    Instance.new('Folder', BlockData).Name = blockDataName
end

Secondly, I’d change your altitude checking code to round the position;

local function CreateOre(ore, position)
    ore.Parent = Mine
    ore.CFrame = position

    local blockDataName = ("%d,%d,%d"):format(ore.Position.X, ore.Position.Y, ore.Position.Z)
    if math.floor(position.Y + 0.5) > 14000 or BlockData:FindFirstChild(blockDataName) then
        ore:Destroy()
    end

    Instance.new('Folder', BlockData).Name = blockDataName
end

I’ve tried setting like a grid position, so if the position is anywhere with the starting grid then it doesn’t create a block

-- Above the grid
if position.Y > 14000 then
		ore:Destroy()
	end
	
	if position.Y > 13995 or BlockData:FindFirstChild(tostring(ore.CFrame)) then
		if position.X < 36 and position.Z > -36 then
			if position.X > -36 and position.Z > 36 then
				ore:Destroy()
			end
		end
	end

If I get the 2 opposite corners of a square, they are
28, -28
-28,28

So that’s the opposite corners of the starting blocks

Try what I suggested above, it may help.
More specifically, you might be running into floating point precision errors by converting your ore’s CFrame to a string and using it to uniquely index each grid position.

Still is replacing the default floor with new blocks
robloxapp-20200103-1147212

Are you adding the default floor blocks to BlockData?

Nooo :grimacing: guessing I Should

1 Like

Haha it was a lot simpler then! I’d recommend reusing the function (you used to place the blocks around where you dig) for placing the floor blocks to avoid that in future :grin:

The function I use only creates blocks when I’ve mined, so how can I create the default floor without that?

The function you posted should work with different block types pretty easily; all it does is set the parent and CFrame, and adds its position to BlockData. The only condition where it wouldn’t place the block would be either if you try to place the block above ground level or if you place a block where another block exists (determined by the instances in BlockData). Therefore it shouldn’t be an issue to simply call that function with each floor block and it’s intended position, just like you presumably are doing elsewhere in your code to place each block in its position around your mined block.

But since my floor is preplaced in studio, how can I automatically place it with code?

1 Like

I’d personally use two nested for loops, possibly something like this;

local function CreateFloor()
    local blockSize = 8
    for xPos=-24, 24, blockSize do
        for zPos=-24, 24, blockSize do
            local block = YourBlockInstanceInStorage:Clone()
            CreateOre(block, CFrame.new(xPos, 14000, zPos))
        end
    end
end

The -24 and 24 represent the range of block positions along the X and Z axes; feel free to modify those to fit your surface’s size. Calling that function would in theory place a brand new floor at the surface.

You’d probably want a function like this for if/when you reset the blocks to their initial state anyways. Hope it helps :slightly_smiling_face:

local function CreateOre(ore, position)
	ore.Parent = Mine
	ore.CFrame = position -- Cframe expected, got Vector
	
	local blockDataName = ("%d,%d,%d"):format(ore.Position.X, ore.Position.Y, ore.Position.Z)
	
	if math.floor(position.Y + 0.5) > 14000 or BlockData:FindFirstChild(blockDataName) then
		ore:Destroy()
	end

	Instance.new('Folder', BlockData).Name = blockDataName
end

local function CreateFloor()
    local blockSize = 8
    for xPos=-24, 24, blockSize do
        for zPos=-24, 24, blockSize do
            local block = Blocks.Dirt:Clone()
            CreateOre(block, Vector3.new(xPos, 14000, zPos))
        end
    end
end

Would I change the CFrame to Vector3, or the Vector3 to CFrame?

Oops, change the Vector3 to CFrame! :sweat_smile:

Why limit yourself to only cframe values

you could always update the function to take both cframe values and position values

ore.CFrame = (typeof(position) == “CFrame” and position) or (CFrame.new(position))

That’s unnecessarily complex for Ninjo’s use case; in most cases, it’s usually better not to introduce multiple ways of doing things where it’s not explicitly needed.

Ok that seems to all be working :+1: But I just realised that spawning blocks on the surface layer would mean that there’d be no roof, like example:
If I have grass or whatever above it as like natural land, ye it’s good, but players could just mine well past that



And it wouldn’t make sense to just extend the grass, so my solution would be create bedrock on that top layer, but how I can determine that?

local function CreateBedrock(_, position)
	local Bedrock = Blocks:FindFirstChild('Bedrock')
	if Bedrock then
		local Clone = Bedrock:Clone()
		Clone.Parent = Mine
		Clone.CFrame = position
	end
end

local function CreateOre(ore, position)
	ore.Parent = Mine
	ore.CFrame = position
	
	local blockDataName = ("%d,%d,%d"):format(ore.Position.X, ore.Position.Y, ore.Position.Z)
	
	if math.floor(position.Y + 0.5) > 14000 or BlockData:FindFirstChild(blockDataName) then
		ore:Destroy()
	end
-- Somehow check if block is at surface level (same level as the default dirt)
-- if it is, then use CreateBedrock() function

	Instance.new('Folder', BlockData).Name = blockDataName
end

That is indeed the solution I’ve seen most mining games use! Typically the first layer of blocks is all bedrock, except for the middle area where you dig down. This stops people from digging back up to the surface outside of the middle area.

The way I’d approach this is by first writing a function to determine whether bedrock should be placed at a given location;

local function ShouldPlaceBedrockAt(position)
    if position.Y < 14000 then
        -- don't place bedrock if the vertical position is below the first laer
        return false
    end
   
    if (position.X >= -24 and position.X <= 24) and (position.Z >= -24 and position.Z <= 24) then
        -- don't place bedrock if the horizontal position is in the middle area
        return false
    end

    -- place bedrock here; this position is not in the middle area and not below the first layer
    return true
end

Then, I’d use the result of that function in the code which determines which block types to place when you dig a block. Specifically, for each block surrounding the mined block, if ShouldPlaceBedrockAt(position) returns true, use the bedrock block type, otherwise calculate your block type as usual.

Have to go to sleep, but that should work. If you have any other issues, I’m sure there’s plenty of others willing to help here! I’ll check back in with this thread in the morning just in case :slightly_smiling_face: