In short, i started making a CIV6 like game but couldn’t really find a team, so i am going to release the code for the Map Generation here, Like i am pretty sure there are other better ways to do this but this is what i made (after torturing ChatGpt for many hours and losing my mental sanity)
Basically it uses perlin noise to make a map, the current default one is pretty small so it may not seem that detailed, so increase size of the board if you want more beautiful landscapes.
This is also my first post so i might have done somethings wrong, i apologise if i did.
Link to my badly made game
local replicatedStorage = game:GetService("ReplicatedStorage")
local tile = replicatedStorage.Assets:WaitForChild("HexagonTile")
local trees = replicatedStorage.Assets:WaitForChild("Trees")
local mountains = replicatedStorage.Assets:WaitForChild("Mountains")
local boardSize = 20
local pos = Vector3.new(0, 0, 0) -- Starting point, will adjust later
-- Define tile types and their properties including material and reflectance
local TILE_TYPES = {
{name = "WATER", color = BrickColor.new("Bright blue"), threshold = 0.075, material = Enum.Material.Plastic, reflectance = 0.25},
{name = "LAND", color = BrickColor.new("Bright green"), threshold = 0.45, material = Enum.Material.Fabric, reflectance = 0.1},
{name = "MOUNTAIN", color = BrickColor.new("Reddish brown"), threshold = 1.0, material = Enum.Material.Fabric, reflectance = 0.05},
}
-- Function to get tile type based on Perlin noise value
local function getTileType(noiseValue)
for _, typeInfo in ipairs(TILE_TYPES) do
if noiseValue < typeInfo.threshold then
return typeInfo
end
end
return TILE_TYPES[#TILE_TYPES]
end
-- Generate a random seed
math.randomseed(tick())
-- Create a unique seed offset
local seedOffsetX = math.random() * 1000
local seedOffsetY = math.random() * 1000
local function generatePerlinNoise(x, y, baseFrequency, baseAmplitude, octaves, persistence, lacunarity, offsetX, offsetY)
local noise = 0
local amplitude = baseAmplitude
local frequency = baseFrequency
for i = 1, octaves do
noise = noise + math.noise((x + offsetX) * frequency, (y + offsetY) * frequency) * amplitude
amplitude = amplitude * persistence
frequency = frequency * lacunarity
end
return noise
end
-- Array to store the created tiles
local board = {}
local baseFrequency = 0.1
local baseAmplitude = 1
local octaves = 5
local persistence = 0.7
local lacunarity = 1.9
local hexagonWidth = tile.Size.X
local hexagonHeight = tile.Size.Z * 0.75
local maxBoardWidth = (boardSize + math.ceil(boardSize / 2) - 1) * hexagonWidth
pos = Vector3.new(-maxBoardWidth / 2, 0, -(boardSize * hexagonHeight / 2))
for x = 1, boardSize do
board[x] = {}
local start, finish = nil, nil
if x < math.ceil(boardSize / 2) then
start, finish = math.ceil(boardSize / 2) - x + 1, boardSize
else
start, finish = 1, boardSize - math.floor(x - boardSize / 2)
end
for y = start, finish do
local newTile = tile:Clone()
newTile.Parent = workspace
local offset = 0
if y % 2 == 0 then
offset = newTile.Size.X * 0.5
end
newTile.Position = pos + Vector3.new((x + math.floor(y / 2)) * newTile.Size.X - offset, 0, y * hexagonHeight)
-- Get Perlin noise value and determine tile type based on thresholds
local noiseValue = generatePerlinNoise(x, y, baseFrequency, baseAmplitude, octaves, persistence, lacunarity, seedOffsetX, seedOffsetY)
-- Determine the tile type and set properties
local tileTypeInfo = getTileType(noiseValue)
newTile.BrickColor = tileTypeInfo.color
newTile.Material = tileTypeInfo.material
newTile.Reflectance = tileTypeInfo.reflectance
-- Create and set the StringValue for tile type
local tileTypeValue = Instance.new("StringValue")
tileTypeValue.Name = "Type"
tileTypeValue.Value = tileTypeInfo.name
tileTypeValue.Parent = newTile
-- Store the type in the board
board[x][y] = tileTypeInfo.name
-- Spawn trees on "LAND" and mountains on "MOUNTAIN" with random Y-rotation, parented to the tile
if tileTypeInfo.name == "LAND" then
local treeInstance = trees:Clone()
treeInstance.Position = newTile.Position + Vector3.new(0, 2.25, 0)
treeInstance.Orientation = Vector3.new(0, math.random(0, 360), 0)
treeInstance.Parent = newTile -- Parent to the tile
elseif tileTypeInfo.name == "MOUNTAIN" then
local mountainInstance = mountains:Clone()
mountainInstance.Position = newTile.Position + Vector3.new(0, 2.25, 0)
mountainInstance.Orientation = Vector3.new(0, math.random(0, 360), 0)
mountainInstance.Parent = newTile -- Parent to the tile
end
end
end