diff --git a/build.gradle.kts b/build.gradle.kts index 466a101..1bf6700 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,9 +5,9 @@ plugins { } korge { - id = "io.github.rezmike.game2048" + id = "de.sauronbach.blockSmash" - name = "2048" + name = "Block Smash" icon = file("src/commonMain/resources/korge.png") diff --git a/gradle.properties b/gradle.properties index 903127f..1a8c631 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ org.gradle.jvmargs=-Xmx8g +kotlin.mpp.androidSourceSetLayoutVersion=2 diff --git a/src/commonMain/kotlin/Block.kt b/src/commonMain/kotlin/Block.kt index d91c94d..74a3773 100644 --- a/src/commonMain/kotlin/Block.kt +++ b/src/commonMain/kotlin/Block.kt @@ -3,24 +3,65 @@ import korlibs.korge.input.* import korlibs.korge.view.* import korlibs.korge.view.align.* import korlibs.math.geom.* +import korlibs.math.random.* +import kotlin.collections.random import kotlin.math.* +import kotlin.properties.* enum class BlockType { - ONEbyONE, TWObyTWO, BigL, - // OnebyThree, TWObyTHREE, THREEbyTHREE, + // Single block + ONE_BY_ONE, + // Straight blocks (all rotations are the same) + ONE_BY_TWO, + TWO_BY_ONE, + ONE_BY_THREE, + THREE_BY_ONE, + ONE_BY_FOUR, + FOUR_BY_ONE, + ONE_BY_FIVE, + FIVE_BY_ONE, -} -enum class BlockRotation { - zero, quarter, half, threequarters -} -object BlockRotationHelper { - fun getRandomRotation(): BlockRotation { - val blockRotations = BlockRotation.values().toList() - return blockRotations.random() // Picks a random BlockType - } + // Square blocks (all rotations are the same) + TWO_BY_TWO, + THREE_BY_THREE, + + // L-Shaped blocks (all rotations) + L_2X2_0, + L_2X2_90, + L_2X2_180, + L_2X2_270, + + L_2X3_0, + L_2X3_90, + L_2X3_180, + L_2X3_270, + + L_3X3_0, + L_3X3_90, + L_3X3_180, + L_3X3_270, + + // T-Shaped blocks (all rotations) + T_2X3_0, + T_2X3_90, + T_2X3_180, + T_2X3_270, + + // Rectangle blocks (all rotations) + TWO_BY_THREE_0, + TWO_BY_THREE_90, + THREE_BY_TWO_0, + THREE_BY_TWO_90, + + // S-Shaped blocks (all rotations) + S_2X3_0, + S_2X3_90, + S_2X3_180, + S_2X3_270 } + enum class StartPosition { LEFT, MIDDLE, RIGHT } @@ -46,36 +87,34 @@ object BlockColors { } } -fun Container.block(color: RGBA, blockType: BlockType, startPosition: StartPosition, rotation: BlockRotation) = - Block(color, blockType, startPosition, rotation).addTo(this) +fun Container.block(color: RGBA, blockType: BlockType, startPosition: StartPosition) = + Block(color, blockType, startPosition).addTo(this) -class Block(private var color: RGBA, blockType: BlockType, startPosition: StartPosition, rotation: BlockRotation) : Container() { +class Block(private var color: RGBA, blockType: BlockType, startPosition: StartPosition) : Container() { private var placed: Boolean = false + private var master: RoundRect by Delegates.notNull() + init { - val theWhole = this // Was originally a container() but should work like this too when (startPosition) { - StartPosition.LEFT -> this.position(-40, 680) - StartPosition.MIDDLE -> this.position(170, 680) - StartPosition.RIGHT -> this.position(380, 680) + StartPosition.LEFT -> this.position(windowWidth * 0.2, windowHeight * 0.8) + StartPosition.MIDDLE -> this.position(windowWidth * 0.4, windowHeight * 0.8) + StartPosition.RIGHT -> this.position(windowWidth * 0.6, windowHeight * 0.8) } when (blockType) { - BlockType.ONEbyONE -> theWhole.roundRect(Size(cs, cs), RectCorners(5f), fill = color) - BlockType.TWObyTWO -> twobytwo(theWhole) - BlockType.BigL -> bigL(theWhole) - else -> throw error("Block has to be defined") - } - when (rotation){ - BlockRotation.zero -> this.rotation = Angle.ZERO - BlockRotation.quarter -> this.rotation = Angle.QUARTER - BlockRotation.half -> this.rotation = Angle.HALF - BlockRotation.threequarters -> this.rotation = 270.degrees + BlockType.ONE_BY_ONE -> oneByOne(this) + BlockType.TWO_BY_TWO -> twoByTwo(this) + BlockType.L_3X3_0 -> bigL(this) + else -> bigL(this) } this.scale(0.5) + var closeable: DraggableCloseable? = null - closeable = this.draggableCloseable { - if (it.start) { + closeable = this.draggableCloseable { it -> + //println("viewNextX: ${round(master!!.getPositionRelativeTo(first!!).x).toInt()}, viewNextY: ${round(master!!.getPositionRelativeTo(first!!).y).toInt()}") + if (it.start) { + println("master: $master") println(this.zIndex) this.zIndex(99) @@ -84,18 +123,17 @@ class Block(private var color: RGBA, blockType: BlockType, startPosition: StartP if (it.end) { this.zIndex(0) println("dragging ended: snapping!") - println("viewNextX: ${round(it.viewNextX).toInt()}, viewNextY: ${round(it.viewNextY).toInt()}") - + println("viewNextX: ${master.globalPos.x}, viewNextY: ${master.globalPos.y}") val blockPosition1 = Point( - convertToCoordX(round(it.view.globalPos.x).toInt()).toInt(), convertToCoordY( - round(it.view.globalPos.y).toInt() - ).toInt() + convertToCoordinateX(round(master.globalPos.x).toInt()), convertToCoordinateY( + round(master.globalPos.y).toInt() + ) ) for (field in fields) { val fieldPosition = Point( - convertToCoordX(round(field.globalPos.x).toInt()).toInt(), convertToCoordY( + convertToCoordinateX(round(field.globalPos.x).toInt()), convertToCoordinateY( round(field.globalPos.y).toInt() - ).toInt() + ) ) //println("Block position converted ${blockPosition1.x}, ${blockPosition1.y}") @@ -103,12 +141,14 @@ class Block(private var color: RGBA, blockType: BlockType, startPosition: StartP if (blockPosition1 == fieldPosition && checkIfCorrectlyPlaced(this)) { println("Placed correctly snapping:") - it.view.position(field.globalPos) + master.globalPos = field.globalPos + println("this global: ${this.globalPos}") this.forEachChild { - sContainer!!.placedBlock(color, convertToCoordX(it.globalPos.x.toInt()), convertToCoordY(it.globalPos.y.toInt())) - //var oc = occupiedFields.find { it.fieldX == convertToCoordX(it.globalPos.x.toInt())&& it.fieldY == convertToCoordY(it.globalPos.y.toInt()) } - //occupiedFields.remove(oc) - //println("removing $oc") + sContainer.placedBlock( + color, + convertToCoordinateX(it.globalPos.x.toInt()), + convertToCoordinateY(it.globalPos.y.toInt()) + ) } placed = true closeable!!.close() @@ -119,8 +159,9 @@ class Block(private var color: RGBA, blockType: BlockType, startPosition: StartP } //println("Left: $leftOccupied, middle: $middleOccupied, right: $rightOccupied") addNewPieces() - allblocks.remove(this) - println("count:"+ occupiedFields.count()) + allBlocks.remove(this) + println("count:" + occupiedFields.count()) + master.removeFromParent() this.removeFromParent() checkForBlast() @@ -129,10 +170,11 @@ class Block(private var color: RGBA, blockType: BlockType, startPosition: StartP } if (!placed) { + this.scale(0.5) when (startPosition) { - StartPosition.LEFT -> this.position(-40, 680) - StartPosition.MIDDLE -> this.position(170, 680) - StartPosition.RIGHT -> this.position(380, 680) + StartPosition.LEFT -> this.position(windowWidth * 0.2, windowHeight * 0.8) + StartPosition.MIDDLE -> this.position(windowWidth * 0.4, windowHeight * 0.8) + StartPosition.RIGHT -> this.position(windowWidth * 0.6, windowHeight * 0.8) } } } @@ -141,24 +183,75 @@ class Block(private var color: RGBA, blockType: BlockType, startPosition: StartP } } - private fun twobytwo(container: Container) { + private fun oneByOne(container: Container) { val one = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color) + master = one + } + + private fun twoByTwo(container: Container) { + val one = container.roundRect(Size(cs, cs), RectCorners(5f), fill = Colors.RED) + master = one container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(one) val three = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignTopToBottomOf(one) container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(three) .alignTopToBottomOf(one) } + private fun bigL(container: Container) { - val one = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color) - val two = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignTopToBottomOf(one) - val three = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignTopToBottomOf(two) - val four = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(three) - .alignTopToBottomOf(two) - container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(four) - .alignTopToBottomOf(two) + val rotation = random.get(range = 0..3) + println("Rotation: $rotation") + container.size = Size(cs * 3, cs * 3) + + + when (rotation) { + 0 -> { + // Original: vertical line + rightward tail + val one = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color) + val two = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignTopToBottomOf(one) + val three = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignTopToBottomOf(two) + val four = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(three) + container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(four) + master = three + } + + 1 -> { + // 90°: horizontal line + upward tail + val one = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color) + val two = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(one) + container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(two) + val four = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignTopToBottomOf(two) + container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignTopToBottomOf(four) + master = two + } + + 2 -> { + // 180°: vertical line + leftward tail + val one = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color) + val two = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignTopToBottomOf(one) + val three = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignTopToBottomOf(two) + val four = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignRightToLeftOf(one) + container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignRightToLeftOf(four) + master = three + } + + 3 -> { + // 270°: horizontal line + downward tail + val one = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color) + val two = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(one) + val three = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignLeftToRightOf(two) + val four = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignBottomToTopOf(two) + val five = container.roundRect(Size(cs, cs), RectCorners(5f), fill = color).alignBottomToTopOf(four) + master = one + master.color = Colors.CHOCOLATE + } + + + } + //master!!.color = Colors.RED } + } fun checkIfCorrectlyPlaced(wholeBlock: Block): Boolean { @@ -168,13 +261,13 @@ fun checkIfCorrectlyPlaced(wholeBlock: Block): Boolean { for (block in wholeBlock.children) { val blockPosition1 = Point( - convertToCoordX(round(block.globalPos.x).toInt()), convertToCoordY( + convertToCoordinateX(round(block.globalPos.x).toInt()), convertToCoordinateY( round(block.globalPos.y).toInt() ) ) for (field in fields) { val fieldPosition = Point( - convertToCoordX(round(field.globalPos.x).toInt()), convertToCoordY( + convertToCoordinateX(round(field.globalPos.x).toInt()), convertToCoordinateY( round(field.globalPos.y).toInt() ) ) @@ -194,7 +287,7 @@ fun checkIfCorrectlyPlaced(wholeBlock: Block): Boolean { field.occupied = true } } - println("test passed: ${testsPassed==testsToPass}") + println("test passed: ${testsPassed == testsToPass}") return testsPassed == testsToPass } diff --git a/src/commonMain/kotlin/main.kt b/src/commonMain/kotlin/main.kt index 09cf272..aa881d9 100644 --- a/src/commonMain/kotlin/main.kt +++ b/src/commonMain/kotlin/main.kt @@ -1,3 +1,4 @@ +import korlibs.crypto.* import korlibs.image.color.* import korlibs.image.font.* import korlibs.image.paint.* @@ -10,30 +11,39 @@ import korlibs.korge.view.align.* import korlibs.math.geom.* import kotlin.math.* import kotlin.properties.* +import kotlin.random.* val rows = mutableListOf>>() var font: BitmapFont by Delegates.notNull() -var backgroundField: RoundRect? = null +var backgroundField: RoundRect by Delegates.notNull() var fields = mutableListOf() -var fieldSize = Size(560, 560) +var windowWidth = (1080/4 * 1.9).toInt() +var windowHeight = (1920/4 * 1.9).toInt() +var fieldSize = Size(windowWidth / 1.4, windowWidth / 1.4) var cs = fieldSize.height / 8 var leftOccupied = false var middleOccupied = false var rightOccupied = false -var sContainer: Container? = null +var sContainer: Container by Delegates.notNull() val occupiedFields = mutableListOf() -val allblocks = mutableListOf() +val allBlocks = mutableListOf() var placedBlocks = mutableListOf() +val random: Random = SecureRandom +var first: Field? = null +var leftStart:RoundRect by Delegates.notNull() +val middleStart:RoundRect by Delegates.notNull() +val rightStart: RoundRect by Delegates.notNull() suspend fun main() = Korge( - virtualSize = Size(480, 853), - + //windowHeight = windowHeight, + windowSize = Size(windowWidth, windowHeight), + //windowWidth = windowWidth, title = "Block Smash", bgcolor = Colors["#4c65a4"], /** `gameId` is associated with the location of storage, which contains `history` and `best`. see [Views.realSettingsFolder] */ - gameId = "io.github.sauronbach.blockSmash", + gameId = "de.sauronbach.blockSmash", forceRenderEveryFrame = false, // Optimization to reduce battery usage! ) { val background = LinearGradientPaint( @@ -49,13 +59,17 @@ suspend fun main() = Korge( sContainer = this backgroundField = roundRect(fieldSize, RectCorners(5f), Colors["#202443"]) - backgroundField!!.centerOnStage() - backgroundField!!.y -= 70 - convertToRealX(5) + backgroundField.centerOnStage() + + + //backgroundField!!.y -= 70 populateField(this) + leftStart = roundRect(Size(cs*1.5, cs*1.5), RectCorners(5f), Colors.PURPLE) + .position(windowWidth*0.2, windowHeight*0.8) //val testBlock = block(BlockColors.Red, BlockType.TWObyTWO, StartPosition.LEFT) createPieces(this) + } @@ -69,44 +83,43 @@ fun populateField(container: Container) { fields.add(f) f.onClick { - println("YOU CLICKED ON ${f.fieldX} ${f.fieldY}, with the real coords: ${f.realX} ${f.realY}") - println("Converted to realX: ${convertToCoordX(f.fieldX)}, realY: ${convertToCoordY(f.fieldY)}") + println("YOU CLICKED ON ${f.fieldX} ${f.fieldY}, with the real Coordinates: ${f.realX} ${f.realY}") + println("Converted to realX: ${convertToCoordinateX(f.fieldX)}, realY: ${convertToCoordinateY(f.fieldY)}") } } } for (field in fields) { - // Ensure that the rows list has enough sublists to accommodate all Y values while (rows.size <= field.fieldY) { rows.add(mutableListOf()) } - // Ensure that each row has enough sublists to accommodate all X values while (rows[field.fieldY].size <= field.fieldX) { rows[field.fieldY].add(mutableListOf()) } rows[field.fieldY][field.fieldX].add(field) } + first = fields[0] println(rows) } fun convertToRealX(fieldCoordinate: Int): Number { - return backgroundField!!.x + cs * fieldCoordinate + return backgroundField.x + cs * fieldCoordinate } fun convertToRealY(fieldCoordinate: Int): Number { - return backgroundField!!.y + cs * fieldCoordinate + return backgroundField.y + cs * fieldCoordinate } -fun convertToCoordX(realX: Int): Int { - return round((realX - backgroundField!!.x) / cs).toInt() +fun convertToCoordinateX(realX: Int): Int { + return round((realX - backgroundField.x) / cs).toInt() } -fun convertToCoordY(realY: Int): Int { - return round((realY - backgroundField!!.y) / cs).toInt() +fun convertToCoordinateY(realY: Int): Int { + return round((realY - backgroundField.y) / cs).toInt() } fun createPieces(container: Container) { @@ -130,14 +143,14 @@ fun createPieces(container: Container) { } } val color = BlockColors.getRandomColor() - var c = container.block(color, BlockTypeHelper.getRandomBlockType(), location!!, BlockRotationHelper.getRandomRotation()) - allblocks.add(c) + val c = container.block(color, BlockTypeHelper.getRandomBlockType(), location!!) + allBlocks.add(c) } } fun addNewPieces() { - if (!leftOccupied && !middleOccupied && !rightOccupied) createPieces(sContainer!!) + if (!leftOccupied && !middleOccupied && !rightOccupied) createPieces(sContainer) } @@ -154,7 +167,31 @@ fun checkForBlast() { println("Row: $rowY, counter: $counter") if (counter == 8) { for (block in checkedBlocks) { - var occupiedField = fields.find { it.pos == block.pos } + val occupiedField = fields.find { it.pos == block.pos } + //println("Removing occupied field:$occupiedField") + block.removeFromParent() + occupiedFields.remove(occupiedField) + placedBlocks.remove(block) + occupiedField?.occupied = false + + } + + } + checkedBlocks.clear() + } + for (columnX in 0 until 8) { + var counter = 0 + val checkedBlocks = mutableListOf() + for (placedBlock in placedBlocks) { + if (placedBlock.fieldX == columnX) { + checkedBlocks.add(placedBlock) + counter++ + } + } + println("Row: $columnX, counter: $counter") + if (counter == 8) { + for (block in checkedBlocks) { + val occupiedField = fields.find { it.pos == block.pos } //println("Removing occupied field:$occupiedField") block.removeFromParent() occupiedFields.remove(occupiedField) @@ -164,7 +201,6 @@ fun checkForBlast() { } } - //println("Current row: $rowY, counter:$counter ${checkedBlocks.count()}") checkedBlocks.clear() }