This probably isn’t suuuper helpful to OP but I just had to comment on this
It’s totally possible to combine two different noise functions, one for “flat plains” and one for “mountains” into a single noise function that has some areas where one is most prevalent and other areas where the other is prevalent. Here’s an example:
The green areas are plains, while the more grey areas are mountains. The key is to use a third noise function to tell the generator “how much mountain-ness” there is at any given point, and blend between the mountain function and the plains function using that mountain-ness function. This image above just linearly interpolates from plains to mountains based on the mountain-ness function. Something like a smootherstep function should give a sharper transition:
Sharper transitions allows higher-frequency mountain-ness noise, i.e. more plains-areas and mountain-areas close together. This also makes each mountain area smaller, so each peak is more solitary / distinct:
Combining that with the “absolute value trick” on the mountain height function you can get really cool mountain ranges / sharp-ish ridges:
(0.1x scale compared to other screenshots to actually render shadows)
Code for the last image. The earlier ones are really just simpler/tweaked version of this.
local v3 = Vector3.new
local _ = nil
local FNG = require(script.FractNoiseGen)
local mapSize = v3(256, 0, 256)
local plainsHeightGen = FNG(_, 1.25, 1/32, 1, _, _) --Height function for plains
local mountainsHeightGen = FNG(_, 30, 1/64, 3, _, _) --Height function for mountains
local mountaineousnessGen = FNG(_, 1, 1/96, 1, _, _) --Blending function for plains/mountains
function smoothstep5(x)
-- https://en.wikipedia.org/wiki/Smoothstep#5th-order_equation
return 6 * math.pow(x, 5) - 15 * math.pow(x, 4) + 10 * math.pow(x, 3)
end
function smoothstep7(x)
-- https://en.wikipedia.org/wiki/Smoothstep#7th-order_equation
return -20 * math.pow(x, 7) + 70 * math.pow(x, 6) - 84 * math.pow(x, 5) + 35 * math.pow(x, 4)
end
function mountainsHeight(x, z)
local h = mountainsHeightGen(x, 0, z)
h = 20 - math.abs(h)
return h
end
for x = 1, mapSize.X do
for z = 1, mapSize.Z do
--m = how much is this point in mountains vs plains? (range [0-1])
local m = math.clamp(smoothstep7(mountaineousnessGen(x, 0, z) + 0.5), 0, 1)
--Blended height = m * mountain + (1 - m) * plains
--Although I wanted mountains to always "stick out of" plains, not dip into them, so here
-- mountain height = plain height + something
local h = m * (plainsHeightGen(x, 0, z) + mountainsHeight(x, z)) +
(1 - m) * (plainsHeightGen(x, 0, z))
local p = script.Part:Clone()
p.CFrame = CFrame.new(x * .1, h * .1, z * .1) --* CFrame.Angles(0, math.random() * math.pi * 2, 0)
p.Color = Color3.fromHSV(0.35, 0.55 - m * 0.55, 0.60)
p.Parent = game.Workspace
end
end
I’m not sure this will be directly useful for generating AA2- style maps that are triangle-based and really low resolution, but maybe some of the techniques can be used? They could certainly also be combined with the idea of generating mountains at discrete points, e.g. with Poisson disc sampling like @dthecoolest suggested or even Voronoi diagrams/Delaunay triangulations somehow. And adding more “biomes” might be interesting too.