X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=core%2Fsrc%2Fru%2Fdeadsoftware%2Fcavedroid%2Fgame%2Fworld%2FGameWorldGenerator.kt;h=004a56b01a945ec581dd084a5e26c390da3de190;hb=179ecd2d5af6349fe6a7812419c6d7818afb3b38;hp=8776254f7dca8d6a1d3b3212aff95335bdb22733;hpb=4c0fc8f608f3856dcce603ccb57552321f9e0e49;p=cavedroid.git diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldGenerator.kt b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldGenerator.kt index 8776254..004a56b 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldGenerator.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldGenerator.kt @@ -1,6 +1,8 @@ package ru.deadsoftware.cavedroid.game.world -import ru.deadsoftware.cavedroid.game.GameItems +import com.google.common.primitives.Ints.min +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.model.block.Block import ru.deadsoftware.cavedroid.game.model.world.Biome import ru.deadsoftware.cavedroid.game.model.world.generator.WorldGeneratorConfig import kotlin.math.abs @@ -9,21 +11,25 @@ import kotlin.random.Random class GameWorldGenerator( private val config: WorldGeneratorConfig, + private val gameItemsHolder: GameItemsHolder, ) { private val random = Random(config.seed) - private val foreMap by lazy { Array(config.width) { IntArray(config.height) } } - private val backMap by lazy { Array(config.width) { IntArray(config.height) } } + private val foreMap by lazy { Array(config.width) { Array(config.height) { gameItemsHolder.fallbackBlock } } } + private val backMap by lazy { Array(config.width) { Array(config.height) { gameItemsHolder.fallbackBlock } } } private val heights by lazy { generateHeights() } private val biomesMap by lazy { generateBiomes() } + private val plainsPlants = listOf("dandelion", "rose", "tallgrass") + private val mushrooms = listOf("mushroom_brown", "mushroom_red",) + private fun generateHeights(): IntArray { val surfaceHeightRange = config.minSurfaceHeight .. config.maxSurfaceHeight val result = IntArray(config.width) - result[0] = (config.minSurfaceHeight + config.maxSurfaceHeight) / 2 + result[0] = surfaceHeightRange.random(random) for (x in 1 ..< config.width) { val previous = result[x - 1] @@ -57,28 +63,83 @@ class GameWorldGenerator( return xSequence.associateWith { config.biomes.random(random) } } + private fun winterBiome(x: Int) { + assert(x in 0 ..< config.width) { "x not in range of world width" } + + val surfaceHeight = heights[x] + + val grass = gameItemsHolder.getBlock("grass_snowed") + val bedrock = gameItemsHolder.getBlock("bedrock") + val dirt = gameItemsHolder.getBlock("dirt") + val stone = gameItemsHolder.getBlock("stone") + val snow = gameItemsHolder.getBlock("snow") + + foreMap[x][surfaceHeight] = grass + foreMap[x][config.height - 1] = bedrock + backMap[x][surfaceHeight] = grass + backMap[x][config.height - 1] = bedrock + + if (surfaceHeight - 1 < config.seaLevel) { + foreMap[x][surfaceHeight - 1] = snow + } + + for (y in min(surfaceHeight + 1, config.seaLevel) ..< config.height - 1) { + if (y <= surfaceHeight) { + backMap[x][y] = dirt + continue + } + + foreMap[x][y] = when { + y < surfaceHeight + random.nextInt(5, 8) -> dirt + else -> stone + } + backMap[x][y] = foreMap[x][y] + } + + val plant = random.nextInt(100) + if (surfaceHeight < config.seaLevel) { + if (plant < 10) { + generateSpruce(x) + } + } + } + private fun plainsBiome(x: Int) { assert(x in 0 ..< config.width) { "x not in range of world width" } val surfaceHeight = heights[x] - val grassId = GameItems.getBlockId("grass") - val bedrockId = GameItems.getBlockId("bedrock") - val dirtId = GameItems.getBlockId("dirt") - val stoneId = GameItems.getBlockId("stone") + val grass = gameItemsHolder.getBlock("grass") + val bedrock = gameItemsHolder.getBlock("bedrock") + val dirt = gameItemsHolder.getBlock("dirt") + val stone = gameItemsHolder.getBlock("stone") + + foreMap[x][surfaceHeight] = grass + foreMap[x][config.height - 1] = bedrock + backMap[x][surfaceHeight] = grass + backMap[x][config.height - 1] = bedrock - foreMap[x][surfaceHeight] = grassId - foreMap[x][config.height - 1] = bedrockId - backMap[x][surfaceHeight] = grassId - backMap[x][config.height - 1] = bedrockId + for (y in min(surfaceHeight + 1, config.seaLevel) ..< config.height - 1) { + if (y <= surfaceHeight) { + backMap[x][y] = dirt + continue + } - for (y in surfaceHeight + 1 ..< config.height - 1) { foreMap[x][y] = when { - y < surfaceHeight + random.nextInt(5, 8) -> dirtId - else -> stoneId + y < surfaceHeight + random.nextInt(5, 8) -> dirt + else -> stone } backMap[x][y] = foreMap[x][y] } + + val plant = random.nextInt(100) + if (surfaceHeight < config.seaLevel) { + if (plant < 10) { + generateOak(x) + } else if (plant < 40) { + generateTallGrass(x) + } + } } private fun desertBiome(x: Int) { @@ -86,69 +147,183 @@ class GameWorldGenerator( val surfaceHeight = heights[x] - val sandId = GameItems.getBlockId("sand") - val bedrockId = GameItems.getBlockId("bedrock") - val sandstoneId = GameItems.getBlockId("sandstone") - val stoneId = GameItems.getBlockId("stone") + val sand = gameItemsHolder.getBlock("sand") + val bedrock = gameItemsHolder.getBlock("bedrock") + val sandstone = gameItemsHolder.getBlock("sandstone") + val stone = gameItemsHolder.getBlock("stone") - foreMap[x][surfaceHeight] = sandId - foreMap[x][config.height - 1] = bedrockId - backMap[x][surfaceHeight] = sandId - backMap[x][config.height - 1] = bedrockId + foreMap[x][surfaceHeight] = sand + foreMap[x][config.height - 1] = bedrock + backMap[x][surfaceHeight] = sand + backMap[x][config.height - 1] = bedrock + + for (y in min(surfaceHeight + 1, config.seaLevel) ..< config.height - 1) { + if (y <= surfaceHeight) { + backMap[x][y] = sand + continue + } - for (y in surfaceHeight + 1 ..< config.height - 1) { foreMap[x][y] = when { - y < surfaceHeight + random.nextInt(5, 8) -> sandId - y < surfaceHeight + random.nextInt(0, 2) -> sandstoneId - else -> stoneId + y < surfaceHeight + random.nextInt(5, 8) -> sand + y < surfaceHeight + random.nextInt(0, 2) -> sandstone + else -> stone } backMap[x][y] = foreMap[x][y] } - if (surfaceHeight < config.seaLevel && random.nextInt(100) < 5) { - generateCactus(x) + val plant = random.nextInt(100) + if (surfaceHeight < config.seaLevel) { + if (plant < 5) { + generateCactus(x) + } else if (plant < 10) { + generateDeadBush(x) + } } } private fun fillWater() { - val waterId = GameItems.getBlockId("water") + val water = gameItemsHolder.getBlock("water") for (x in 0 ..< config.width) { for (y in config.seaLevel ..< config.height) { - if (foreMap[x][y] != 0) { + if (foreMap[x][y] != gameItemsHolder.fallbackBlock) { break } - foreMap[x][y] = waterId + foreMap[x][y] = water } } } private fun generateCactus(x: Int) { - val cactusId = GameItems.getBlockId("cactus") - val cactusHeight = random.nextInt(5) + val cactus = gameItemsHolder.getBlock("cactus") + val cactusHeight = random.nextInt(3) val h = heights[x] - 1 for (y in h downTo max(0, h - cactusHeight)) { - foreMap[x][y] = cactusId + foreMap[x][y] = cactus + } + } + + private fun generateOak(x: Int) { + val log = gameItemsHolder.getBlock("log_oak") + val leaves = gameItemsHolder.getBlock("leaves_oak") + val h = heights[x] - 1 + val treeH = random.nextInt(5, 7) + val height = max(0, h - treeH) + + val top = height - 1 + if (top >= 0) { + foreMap[x][top] = leaves + backMap[x][top] = leaves + } + + for (x1 in max(0, x - 1) .. min(config.width - 1, x + 1)) { + for (y in height .. height + treeH - 4) { + foreMap[x1][y] = leaves + backMap[x1][y] = leaves + } + if (random.nextInt(15) < 3) { + foreMap[x1][heights[x1] - 1] = gameItemsHolder.getBlock(mushrooms.random(random)) + } + } + + for (y in h downTo height) { + backMap[x][y] = log + } + } + + private fun generateSpruce(x: Int) { + val log = gameItemsHolder.getBlock("log_spruce") + val leaves = gameItemsHolder.getBlock("leaves_spruce") + val h = heights[x] - 1 + val treeH = random.nextInt(7, 9) + val height = max(0, h - treeH) + + val top = height - 1 + if (top >= 0) { + foreMap[x][top] = leaves + backMap[x][top] = leaves + } + + for (x1 in max(0, x - 1) .. min(config.width - 1, x + 1)) { + val y = height + foreMap[x1][y] = leaves + backMap[x1][y] = leaves + } + + for (y in 1..2) { + for (x1 in max(0, x - y) .. min(config.width - 1, x + y)) { + foreMap[x1][height + 1 + y] = leaves + backMap[x1][height + 1 + y] = leaves + } + } + + for (y in h downTo height) { + backMap[x][y] = log + } + } + + private fun generateTallGrass(x: Int) { + val tallGrass = gameItemsHolder.getBlock(plainsPlants.random(random)) + val h = heights[x] - 1 + if (h > 0) { + foreMap[x][h] = tallGrass + } + } + + private fun generateDeadBush(x: Int) { + val bush = gameItemsHolder.getBlock("deadbush") + val h = heights[x] - 1 + if (h > 0) { + foreMap[x][h] = bush + } + } + + private fun generateOres(x : Int) { + val stone = gameItemsHolder.getBlock("stone") + val coal = gameItemsHolder.getBlock("coal_ore") + val iron = gameItemsHolder.getBlock("iron_ore") + val gold = gameItemsHolder.getBlock("gold_ore") + val diamond = gameItemsHolder.getBlock("diamond_ore") + val lapis = gameItemsHolder.getBlock("lapis_ore") + + for (y in heights[x] ..< config.height) { + val res = random.nextInt(10000) + + val h = config.height - y + val block = when { + res in 0..<25 && h < 16 -> diamond + res in 25 ..< 50 && h < 32 -> gold + res in 50 ..< 250 && h < 64 -> iron + res in 250 ..< 450 && h < 128 -> coal + res in 450 ..< (450 + (25 - (abs(h - 16) * (25 / 16)))) -> lapis + else -> null + } + + if (block != null && foreMap[x][y] == stone) { + foreMap[x][y] = block + } } } /** * Generate world */ - fun generate(): Pair, Array> { + fun generate(): Pair>, Array>> { var biome = Biome.PLAINS for (x in 0 until config.width) { - val xHeight = heights[x] biome = biomesMap[x] ?: biome when (biome) { Biome.PLAINS -> plainsBiome(x) Biome.DESERT -> desertBiome(x) + Biome.WINTER -> winterBiome(x) } + + generateOres(x) } fillWater()