How can I turn the grass into dirt when generating in a wall?

I want the grass (that generates on the walls of hills and mountains) to turn into dirt

the grass is generating like this, but I want it replaced by dirt blocks alredy within a folder in my game, How can I generate it?

I searched in google, youtube and inside the forum, and found nothing

local BLOCK_SIZE = 3.054
local MAP_SIZE = Vector3.new(150, 64, 150)
local MOUNTAIN_INTENSITY = 8

local function PlantTree()
	
	
end

seed = workspace.SEED.Value
noisescale = 1/64
amplitude = 10

function get_density(v3)
	local noise_value = math.noise(v3.X * noisescale, v3.Y * noisescale, v3.Z * noisescale + seed)*amplitude
	local height_bonus = -v3.Y / MOUNTAIN_INTENSITY + 8

	return noise_value + height_bonus
end

function is_on_boundary(v3)
	if get_density(v3) <= 0 then
		return false
	end

	for _, dirEnum in pairs(Enum.NormalId:GetEnumItems()) do
		local dir = Vector3.FromNormalId(dirEnum)
		local neighbor_pos = v3 + dir * BLOCK_SIZE
		local neighbor_density = get_density(neighbor_pos)

		if neighbor_density <= 0 then
			return true
		end
	end

	return false
end

for x = 0, MAP_SIZE.X do
	for y = 0, MAP_SIZE.Y do
		for z = 0, MAP_SIZE.Z do
			local block_pos = Vector3.new(x, y, z) * BLOCK_SIZE
			local density = get_density(block_pos)

			if density > 0 and is_on_boundary(block_pos) then
				local block = script.Block:Clone()
				block.Parent = game.Workspace
				block.CFrame = CFrame.new(block_pos)
				if y > 25 then
					local c = game.ReplicatedStorage.Blocks.Nature.Snow:Clone()
					c:SetPrimaryPartCFrame(block.CFrame)
					c.Parent = workspace.TerrainFolder
					block:Destroy()
				elseif y < 23 and y > 1 then
					local c = game.ReplicatedStorage.Blocks.Nature.Grass:Clone()
					c:SetPrimaryPartCFrame(block.CFrame)
					c.Parent = workspace.TerrainFolder
					block:Destroy()
					local trees = game.ReplicatedStorage.Structures.Trees:GetChildren()
					if math.random(1, 100) == 1 then
						local tree = trees[math.random(1, #trees)]:Clone()
						tree.Parent = workspace.TerrainFolder.Trees
						tree:SetPrimaryPartCFrame(c.PrimaryPart.CFrame)
					end
				elseif y <= 1 then
					local c = game.ReplicatedStorage.Blocks.Nature.Sand:Clone()
					c:SetPrimaryPartCFrame(block.CFrame)
					c.Parent = workspace.TerrainFolder
					block:Destroy()
				else
					local c = game.ReplicatedStorage.Blocks.Nature.Stone:Clone()
					c:SetPrimaryPartCFrame(block.CFrame)
					c.Parent = workspace.TerrainFolder
					block:Destroy()
				end
			end
			
		end
	end
	wait(0.2)
end

So, nobody will help?

2 Likes

An easy way to do this would be to make the grass top like 0.01 studs smaller on all sides so the dirt clips through the grass and hides it

The size of the entire grass block is just like the size of the rest of the blocks, but will try!

[:pencil2:] NOTE: I am implementing this code to some minecraft-like game

I mean just change the size of the grass top of the grass block model

I forgot to mention, I also implemented a function where I generate trees on top of grass blocks, but you think that I can make the tree smaller? WRONG because it’s an entire model!

I believe you can just check the density above the block.

local function is_on_top(v3)
    return get_density(v3+Vector3.new(0, BLOCK_SIZE, 0)) <= 0
end

elseif with the new function

elseif y < 23 and y > 1 and is_on_top(block_pos) then
1 Like

Or easier, I can run a rayCast billions of studs into the sky right?

1 Like

I don’t understand how a Raycast would help. Your code seems to create blocks on lower y coordinates before higher, so even if a block was going to be placed above the block you are placing, that block would not be there yet. So if you casted a ray upwards from the position of the current block, the ray would hit nothing.

1 Like

Raycasts can only be 5000 studs long, you would only need to raycast BLOCK_SIZE studs up anyway, and @RoBoPoJu’s approach is probably more performant anyway and more flexible IMO.

I want the raycast to go to the sky because it might collide with the roof of a curved mountain

Raycasting upwards makes a lot of sense. But like RoBoPoJu mentioned, you’ll have to make sure that you generate everything from the top of the world to the bottom, otherwise there won’t be anything to detect with the ray. Or you can do it in two passes, placing grass everywhere initially and then looping over every placed block, raycasting upwards to see if there’s anything above.Or you could store every block that doesn’t have anything above it in a table and only check those in the second pass.

I did not understand, What should I put in the

local hit = workspace:Raycast(Vector3.new(c.Grass.CFrame.X,c.Grass.CFrame.Y + 1,c.Grass.CFrame.Z), Vector3.new(c.Grass.CFrame.X,c.Grass.CFrame.Y + 100,c.Grass.CFrame.Z))
					
					for i, hit in pairs(???) do

What you get back as a return value from :Raycast() is a RaycastResult, you can read more about that on the wiki. Short explanation is that if you get a RaycastResult, you can check what it hit by checking result.Instance. If it hit a block on its way up, don’t make it into grass.

The “()” in in pairs() wants a table, but I don’t know wich table to use from the entire script

You only really need one ray per block, so no need for a for loop