Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --# <|=============== SERVICES ===============|>
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local CollectionService = game:GetService("CollectionService")
- --# <|=============== DEPENDENCIES ===============|>
- local Knit = require(ReplicatedStorage.Packages.Knit)
- --- <|=============== AUX FUNCTIONS ===============|>
- -- Fractal Brownian Motion noise function (full credit to Stephen Leitnick a.k.a sleitnick, src: https://github.com/Sleitnick/RDC2019-Procedural-Generation)
- local function FBM(x, z, seed, amplitude, octaves, persistence, frequency, lacunarity, gain, resultScale)
- local result = 0
- for _ = 1,octaves do
- result = (result + (amplitude * math.noise(((x + seed)/frequency) * persistence, ((z + seed)/frequency) * persistence)))
- frequency = (frequency * lacunarity)
- amplitude = (amplitude * gain)
- end
- return result/resultScale
- end
- -- S shaped function to generate square filter that'll remove edges of the map
- local function GenerateSquareFallOff(x, z, mapSize, offset, smoothness)
- -- Normalization of values
- local widthFallOff = math.abs(x/mapSize * 2 - 1)
- local lengthFallOff = math.abs(z/mapSize * 2 - 1)
- -- Get the closes to one
- local fallOffResult = math.clamp(math.max(widthFallOff, lengthFallOff), 0, 1)
- local a = smoothness
- local b = offset
- local value = fallOffResult
- return math.pow(value, a)/(math.pow(value, a)+math.pow(b - b * value, a))
- end
- --? <|=============== KNIT LIFECYCLE ===============|>
- local MapGenerationService = Knit.CreateService {
- Name = "MapGenerationService",
- Client = {},
- }
- --# Initial setup
- function MapGenerationService:KnitInit()
- self.Terrains = { --# Biomes
- [1] = {
- Name = "Ocean",
- Threshold = 0,
- BrickColor = BrickColor.new("Deep blue"),
- Elevation = 0
- },
- [2] = {
- Name = "Coast",
- Threshold = 0.01,
- BrickColor = BrickColor.new("Steel blue"),
- Elevation = 0
- },
- [3] = {
- Name = "Beach",
- Threshold = 0.2,
- BrickColor = BrickColor.new("Daisy orange"),
- Elevation = 0.25
- },
- [4] = {
- Name = "Plains",
- Threshold = 0.30,
- BrickColor = BrickColor.new("Bright green"),
- Elevation = 0.25
- },
- [5] = {
- Name = "Hills",
- Threshold = 0.60,
- BrickColor = BrickColor.new("Dark green"),
- Elevation = 0.50
- },
- [6] = {
- Name = "Mountains",
- Threshold = 0.88,
- BrickColor = BrickColor.new("Medium stone grey"),
- Elevation = 0.75
- },
- [7] = {
- Name = "Impassable",
- Threshold = 0.99,
- BrickColor = BrickColor.new("Dark stone grey"),
- Elevation = 1.25
- },
- [8] = { --! needed placeholder due to the way appearance is set!
- Name = "Placeholder",
- Threshold = 1.01,
- BrickColor = BrickColor.new("Daisy orange"),
- }
- }
- end
- --# Start process
- function MapGenerationService:KnitStart()
- --[[ source of these comments:
- - http://libnoise.sourceforge.net/glossary/#octave
- - https://medium.com/@yvanscher/playing-with-perlin-noise-generating-realistic-archipelagos-b59f004d8401
- - https://thebookofshaders.com/13/
- -- ]]
- --# Generation Config
- local seed = math.random(-100_000, 100_000) -- Determines the output of the noise result
- local amplitude = 42 -- Maximum displacement of the FBR Sine wave
- local octaves = 6 -- These are added together to Form noise, more = = higher detail noise [1, n]
- local persistence = 0.4 -- Modifies the amplitude of each octave the rate each octave diminshes [0.0, 1.0]
- local frequency = 72 -- Determines
- local lacunarity = 0.40 -- Determines how much each octave contributes to the final result [0.0, 1.0]
- local gain = 0.52 -- Scales the amplitude between each octave [0.0, 1.0]
- local terrainScale = 27 -- outer amplitude [1, n]
- local mapSize = 325 -- Determines the area of the map, mapsize^2 [1, n]
- local fallOffSmoothness = 4 -- Detemines how smooth is the transition of biomes from the outermost to the innermost
- local fallOffOffset = 8 -- determines the offset between the edge of the filter and land (literally padding)
- --# Tilemap generations
- for x = 1, mapSize do
- for z = 1, mapSize do
- local noiseVal: number = FBM(x, z, seed, amplitude, octaves, persistence, frequency, lacunarity, gain, terrainScale)
- noiseVal -= GenerateSquareFallOff(x, z, mapSize, fallOffOffset, fallOffSmoothness)
- noiseVal = math.clamp(noiseVal, 0, 1)
- local Tile: Part = Instance.new("Part")
- Tile.Anchored = true
- Tile.CanCollide = true
- Tile.Size = Vector3.new(1,1,1)
- Tile.Material = Enum.Material.SmoothPlastic
- --# Tile appearance
- for index, terrain in ipairs(self.Terrains) do
- local nextTerrain = self.Terrains[index + 1]
- if not nextTerrain then break end
- if terrain.Threshold <= noiseVal and nextTerrain.Threshold >= noiseVal then
- Tile.BrickColor = terrain.BrickColor
- Tile.Position = Vector3.new(x * Tile.Size.X, 20 + terrain.Elevation, z * Tile.Size.Z)
- CollectionService:AddTag(Tile, terrain.Name)
- break
- end
- end
- Tile.Parent = workspace
- end
- end
- --# output each terrain tile count
- for _, t in ipairs(self.Terrains) do
- print("ammount of", t.Name, #CollectionService:GetTagged(t.Name))
- print("Seed is:", seed)
- end
- end
- return MapGenerationService
Add Comment
Please, Sign In to add comment