How to make terrain generation more controlled

So right now i have a script thats supposed to generate terrain for a game im making but the terrain is really repetitive and is not dynamic enough. i want to know how i can make it so that one part will have a hill and one part will be desert and in the desert there are small hills but in the mountainous region there are big hills.

current script

local X, Z = 15,15

local wedge = Instance.new("WedgePart");
wedge.Anchored = true;
wedge.TopSurface = Enum.SurfaceType.Smooth;
wedge.BottomSurface = Enum.SurfaceType.Smooth;

local function draw3dTriangle(a, b, c)
	local ab, ac, bc = b - a, c - a, c - b;
	local abd, acd, bcd = ab:Dot(ab), ac:Dot(ac), bc:Dot(bc);

	if (abd > acd and abd > bcd) then
		c, a = a, c;
	elseif (acd > bcd and acd > abd) then
		a, b = b, a;
	end

	ab, ac, bc = b - a, c - a, c - b;

	local right = ac:Cross(ab).unit;
	local up = bc:Cross(right).unit;
	local back = bc.unit;

	local height = math.abs(ab:Dot(up));

	local w1 = wedge:Clone();
	w1.Size = Vector3.new(2, height, math.abs(ab:Dot(back)));
	w1.CFrame = CFrame.fromMatrix((a + b)/2, right, up, back);
	w1.Parent = workspace.BlockTerrain;

	local w2 = wedge:Clone();
	w2.Size = Vector3.new(2, height, math.abs(ac:Dot(back)));
	w2.CFrame = CFrame.fromMatrix((a + c)/2, -right, up, -back);
	w2.Parent = workspace.BlockTerrain;

	return w1, w2;
end

local positionGrid = {}

for x = 0, X do
	positionGrid[x] = {}
	
	for z = 0, Z do
		local random = 10
		local random1 = math.random(50,100)
		local random2 = 10
		positionGrid[x][z] = Vector3.new(x*random, math.noise(x/random2, z/random2) * random1, z*random)
	end
end

for x = 0, X-1 do
	for z = 0, Z-1 do
		local a = positionGrid[x][z]
		local b = positionGrid[x+1][z]
		local c = positionGrid[x][z+1]
		local d = positionGrid[x+1][z+1]

		draw3dTriangle(a, b, c)
		draw3dTriangle(b, c, d)
	end
end
for i,v in pairs(game.Workspace.BlockTerrain:GetChildren()) do
	local s= v.Size
	if v.Name == "Water" then
		workspace.Terrain:FillBlock(v.CFrame,s,Enum.Material.Water)
		v:Destroy()
	end
end
for i,v in pairs(game.Workspace.BlockTerrain:GetChildren()) do
	local s= v.Size+Vector3.new(20,0,0)
		if v.Position.Y < -20 then
			workspace.Terrain:FillBlock(v.CFrame,s,Enum.Material.Sand)
			v:Destroy()
		elseif v.Position.Y > -20 and v.Position.Y < 15 then
			workspace.Terrain:FillBlock(v.CFrame,s,Enum.Material.Grass)
			v:Destroy()
		else
			workspace.Terrain:FillBlock(v.CFrame,s,Enum.Material.Snow)
			v:Destroy()
		end
end

thank you in advance

You’re asking a very complicated question that will require some studying.

One solution is to use layered noise and moisture systems to create different biomes. I believe this is what Minecraft used before 1.8 came out. It involves creating multiple layers of noise and blending them at different frequencies and amplitudes to create large hills coupled with smaller details. Moisture, temperature, and/or humidity maps can be combined to map out biomes.

If you look at the map on this link it can give an example of how to combine a temperature and humidity to get different combinations, and you can prevent snow biomes from spawning next to deserts in this way as well.

2 Likes