Skip to content

Commit 0a6ea78

Browse files
Adam AroldAdam Arold
authored andcommitted
Add cave generation and game component
1 parent 3a53910 commit 0a6ea78

10 files changed

Lines changed: 115 additions & 32 deletions

File tree

src/main/kotlin/org/hexworks/cavesofzircon/GameConfig.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import org.hexworks.zircon.api.Sizes
77

88
object GameConfig {
99

10+
// game
11+
const val DUNGEON_LEVELS = 2
12+
1013
// look & feel
1114
val TILESET = CP437TilesetResources.rogueYun16x16()
1215
val THEME = ColorThemes.zenburnVanilla()
@@ -17,6 +20,8 @@ object GameConfig {
1720
const val WINDOW_WIDTH = 80
1821
const val WINDOW_HEIGHT = 50
1922

23+
val WORLD_SIZE = Sizes.create3DSize(WINDOW_WIDTH - SIDEBAR_WIDTH, WINDOW_HEIGHT - LOG_AREA_HEIGHT, DUNGEON_LEVELS)
24+
2025
fun buildAppConfig() = AppConfigs.newConfig()
2126
.enableBetaFeatures()
2227
.withDefaultTileset(TILESET)

src/main/kotlin/org/hexworks/cavesofzircon/blocks/GameBlock.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,17 @@ import org.hexworks.zircon.api.data.BlockSide
55
import org.hexworks.zircon.api.data.Tile
66
import org.hexworks.zircon.api.data.base.BlockBase
77

8-
class GameBlock(private var defaultTile: Tile = GameTileRepository.floor())
8+
class GameBlock(private var defaultTile: Tile = GameTileRepository.FLOOR)
99
: BlockBase<Tile>() {
1010

11+
val isFloor: Boolean
12+
get() = defaultTile == GameTileRepository.FLOOR
13+
14+
15+
val isWall: Boolean
16+
get() = defaultTile == GameTileRepository.WALL
17+
18+
1119
override val layers
1220
get() = mutableListOf(defaultTile)
1321

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package org.hexworks.cavesofzircon.builders
22

33
import org.hexworks.cavesofzircon.blocks.GameBlock
4-
import org.hexworks.zircon.api.data.impl.Position3D
54

65
object GameBlockFactory {
76

8-
fun floor() = GameBlock(GameTileRepository.floor())
7+
fun floor() = GameBlock(GameTileRepository.FLOOR)
98

10-
fun wall() = GameBlock(GameTileRepository.wall())
9+
fun wall() = GameBlock(GameTileRepository.WALL)
1110

1211
}

src/main/kotlin/org/hexworks/cavesofzircon/builders/GameTileRepository.kt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@ object GameTileRepository {
88

99
val EMPTY: CharacterTile = Tiles.empty()
1010

11-
fun floor(): CharacterTile {
12-
return Tiles.newBuilder()
13-
.withCharacter(Symbols.INTERPUNCT)
14-
.withForegroundColor(GameColors.FLOOR_FOREGROUND)
15-
.withBackgroundColor(GameColors.FLOOR_BACKGROUND)
16-
.buildCharacterTile()
17-
}
11+
val FLOOR: CharacterTile = Tiles.newBuilder()
12+
.withCharacter(Symbols.INTERPUNCT)
13+
.withForegroundColor(GameColors.FLOOR_FOREGROUND)
14+
.withBackgroundColor(GameColors.FLOOR_BACKGROUND)
15+
.buildCharacterTile()
1816

19-
fun wall() = Tiles.newBuilder()
17+
val WALL: CharacterTile = Tiles.newBuilder()
2018
.withCharacter('#')
2119
.withForegroundColor(GameColors.WALL_FOREGROUND)
2220
.withBackgroundColor(GameColors.WALL_BACKGROUND)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.hexworks.cavesofzircon.extensions
2+
3+
import org.hexworks.zircon.api.data.impl.Position3D
4+
5+
fun Position3D.sameLevelNeighborsShuffled(): List<Position3D> {
6+
return (-1..1).flatMap { x ->
7+
(-1..1).map { y ->
8+
withRelativeX(x).withRelativeY(y)
9+
}
10+
}.minus(this).shuffled()
11+
}

src/main/kotlin/org/hexworks/cavesofzircon/view/PlayView.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,16 @@ package org.hexworks.cavesofzircon.view
33
import org.hexworks.cavesofzircon.GameConfig
44
import org.hexworks.cavesofzircon.blocks.GameBlock
55
import org.hexworks.cavesofzircon.world.Game
6-
import org.hexworks.zircon.api.ColorThemes
76
import org.hexworks.zircon.api.Components
87
import org.hexworks.zircon.api.GameComponents
98
import org.hexworks.zircon.api.component.ComponentAlignment
109
import org.hexworks.zircon.api.data.Tile
1110
import org.hexworks.zircon.api.game.ProjectionMode
1211
import org.hexworks.zircon.api.mvc.base.BaseView
1312

14-
// TODO
15-
class PlayView(private val game: Game) : BaseView() {
13+
class PlayView(private val game: Game = Game.create()) : BaseView() {
1614

17-
override val theme = ColorThemes.arc()
15+
override val theme = GameConfig.THEME
1816

1917
override fun onDock() {
2018

@@ -34,12 +32,13 @@ class PlayView(private val game: Game) : BaseView() {
3432

3533
screen.addComponent(logArea)
3634

37-
// TODO
3835
val gameComponent = GameComponents.newGameComponentBuilder<Tile, GameBlock>()
3936
.withGameArea(game.world)
40-
.withVisibleSize(game.visibleSize)
37+
.withVisibleSize(game.world.visibleSize())
4138
.withProjectionMode(ProjectionMode.TOP_DOWN)
4239
.withAlignmentWithin(screen, ComponentAlignment.TOP_RIGHT)
4340
.build()
41+
42+
screen.addComponent(gameComponent)
4443
}
4544
}

src/main/kotlin/org/hexworks/cavesofzircon/view/StartView.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.hexworks.cavesofzircon.view
22

3+
import org.hexworks.cavesofzircon.world.Game
34
import org.hexworks.zircon.api.ColorThemes
45
import org.hexworks.zircon.api.Components
56
import org.hexworks.zircon.api.component.ComponentAlignment
@@ -27,10 +28,10 @@ class StartView : BaseView() {
2728
.wrapWithShadow()
2829
.wrapWithBox()
2930
.build()
30-
startButton.onMouseReleased {
31-
replaceWith(PlayView())
32-
close()
33-
}
31+
startButton.onMouseReleased {
32+
replaceWith(PlayView())
33+
close()
34+
}
3435
screen.addComponent(header)
3536
screen.addComponent(startButton)
3637
}
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
package org.hexworks.cavesofzircon.world
22

3+
import org.hexworks.cavesofzircon.GameConfig
34
import org.hexworks.zircon.api.data.impl.Size3D
45

5-
class Game(val world: World,
6-
val worldSize: Size3D = world.actualSize(),
7-
val visibleSize: Size3D = world.visibleSize())
6+
class Game(val world: World) {
7+
8+
companion object {
9+
10+
fun create(worldSize: Size3D = GameConfig.WORLD_SIZE,
11+
visibleSize: Size3D = GameConfig.WORLD_SIZE) = Game(WorldBuilder(worldSize)
12+
.makeCaves()
13+
.build(visibleSize))
14+
}
15+
}

src/main/kotlin/org/hexworks/cavesofzircon/world/World.kt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,19 @@ package org.hexworks.cavesofzircon.world
22

33
import org.hexworks.cavesofzircon.blocks.GameBlock
44
import org.hexworks.cavesofzircon.builders.GameBlockFactory
5-
import org.hexworks.cobalt.datatypes.extensions.map
65
import org.hexworks.zircon.api.builder.game.GameAreaBuilder
76
import org.hexworks.zircon.api.data.Tile
87
import org.hexworks.zircon.api.data.impl.Position3D
98
import org.hexworks.zircon.api.data.impl.Size3D
109
import org.hexworks.zircon.api.game.GameArea
1110

12-
1311
class World(startingBlocks: Map<Position3D, GameBlock>,
1412
visibleSize: Size3D,
1513
actualSize: Size3D) : GameArea<Tile, GameBlock> by GameAreaBuilder.newBuilder<Tile, GameBlock>()
1614
.withVisibleSize(visibleSize)
1715
.withActualSize(actualSize)
1816
.withDefaultBlock(DEFAULT_BLOCK)
19-
.withLayersPerBlock(2)
17+
.withLayersPerBlock(1)
2018
.build() {
2119

2220
init {
@@ -25,10 +23,6 @@ class World(startingBlocks: Map<Position3D, GameBlock>,
2523
}
2624
}
2725

28-
fun withBlockAt(position: Position3D, fn: (GameBlock) -> Unit) {
29-
fetchBlockAt(position).map(fn)
30-
}
31-
3226
companion object {
3327
private val DEFAULT_BLOCK = GameBlockFactory.floor()
3428
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.hexworks.cavesofzircon.world
2+
3+
import org.hexworks.cavesofzircon.blocks.GameBlock
4+
import org.hexworks.cavesofzircon.builders.GameBlockFactory
5+
import org.hexworks.cavesofzircon.extensions.sameLevelNeighborsShuffled
6+
import org.hexworks.zircon.api.Positions
7+
import org.hexworks.zircon.api.data.impl.Position3D
8+
import org.hexworks.zircon.api.data.impl.Size3D
9+
10+
class WorldBuilder(private val worldSize: Size3D) {
11+
12+
private val width = worldSize.xLength
13+
private val height = worldSize.zLength
14+
private var blocks: MutableMap<Position3D, GameBlock> = mutableMapOf()
15+
16+
fun makeCaves(): WorldBuilder {
17+
return randomizeTiles()
18+
.smooth(8)
19+
}
20+
21+
fun build(visibleSize: Size3D): World = World(blocks, visibleSize, worldSize)
22+
23+
private fun randomizeTiles(): WorldBuilder {
24+
forAllPositions { pos ->
25+
blocks[pos] = if (Math.random() < 0.5) {
26+
GameBlockFactory.floor()
27+
} else GameBlockFactory.wall()
28+
}
29+
return this
30+
}
31+
32+
private fun smooth(iterations: Int): WorldBuilder {
33+
val newBlocks = mutableMapOf<Position3D, GameBlock>()
34+
repeat(iterations) {
35+
forAllPositions { pos ->
36+
val (x, y, z) = pos
37+
var floors = 0
38+
var rocks = 0
39+
pos.sameLevelNeighborsShuffled().plus(pos).forEach { neighbor ->
40+
blocks.whenPresent(neighbor) { block ->
41+
if (block.isFloor) {
42+
floors++
43+
} else rocks++
44+
}
45+
}
46+
newBlocks[Positions.create3DPosition(x, y, z)] = if (floors >= rocks) GameBlockFactory.floor() else GameBlockFactory.wall()
47+
}
48+
blocks = newBlocks
49+
}
50+
return this
51+
}
52+
53+
private fun forAllPositions(fn: (Position3D) -> Unit) {
54+
worldSize.fetchPositions().forEach(fn)
55+
}
56+
57+
private fun MutableMap<Position3D, GameBlock>.whenPresent(pos: Position3D, fn: (GameBlock) -> Unit) {
58+
this[pos]?.let(fn)
59+
}
60+
}

0 commit comments

Comments
 (0)