// Mines is free software: you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the Free Software // Foundation, either version 3 of the License, or (at your option) any later // version. // Mines is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR // A PARTICULAR PURPOSE. See the GNU General Public License for more details. // You should have received a copy of the GNU General Public License along with // Mines. If not, see . package space.jakob.mines import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Canvas import android.graphics.Rect import android.graphics.Paint import android.util.AttributeSet import android.view.View import android.util.Log const val atlasWidth = 3 const val tileSpacing = 2.0 / 27.0 enum class AtlasEntry { BLANK, MASKED, UNMASKED, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, FLAG, UNKNOWN, MINE, TRIPPED, } class GameView(context: Context, attrs: AttributeSet) : View(context, attrs) { val atlas = BitmapFactory.decodeResource(context.resources, R.drawable.atlas); val tileWidth = atlas.width / 3 var grid: Grid? = null var cameraX = 0.0 var cameraY = 0.0 var sightX = 5.0 var sightY = 5.0 val maxCameraX: Double get() = grid?.let { it.width - sightX } ?: 0.0 val maxCameraY: Double get() = grid?.let { it.height - sightY } ?: 0.0 // The size, in pixels, of an individual tile based on the current scale // factor. val scaledWidth: Int get() = width / sightX.toInt() val scaledHeight: Int get() = height / sightY.toInt() /** * Returns the grid coordinates for the tile at the given screen coordinates. */ fun toGridCoordinates(x: Int, y: Int) = Pair( (x + (scaledWidth * (cameraX % 1)).toInt()) / scaledWidth + cameraX.toInt(), (y + (scaledHeight * (cameraY % 1)).toInt()) / scaledHeight + cameraY.toInt() ) private fun atlasRect(entry: AtlasEntry): Rect { val x = (entry.ordinal % atlasWidth) * tileWidth val y = (entry.ordinal / atlasWidth) * tileWidth return Rect(x, y, x + tileWidth, y + tileWidth) } private fun drawTile(canvas: Canvas, tile: Tile, x: Int, y: Int) { val xSpacing = (scaledWidth * tileSpacing).toInt() val ySpacing = (scaledWidth * tileSpacing).toInt() val dst = Rect( x + xSpacing, y + ySpacing, x + scaledWidth - xSpacing, y + scaledHeight - ySpacing ) if (tile.masked) { canvas.drawBitmap(atlas, atlasRect(AtlasEntry.MASKED), dst, null) } else { canvas.drawBitmap(atlas, atlasRect(AtlasEntry.UNMASKED), dst, null) val overlay = when { tile.mine -> AtlasEntry.MINE tile.adjacentMines == 1 -> AtlasEntry.ONE tile.adjacentMines == 2 -> AtlasEntry.TWO tile.adjacentMines == 3 -> AtlasEntry.THREE tile.adjacentMines == 4 -> AtlasEntry.FOUR tile.adjacentMines == 5 -> AtlasEntry.FIVE tile.adjacentMines == 6 -> AtlasEntry.SIX tile.adjacentMines == 7 -> AtlasEntry.SEVEN tile.adjacentMines == 8 -> AtlasEntry.EIGHT else -> AtlasEntry.BLANK } canvas.drawBitmap(atlas, atlasRect(overlay), dst, null) } } private fun drawGrid(canvas: Canvas, grid: Grid) { val startX = cameraX.toInt() // Truncates the fractional component. val startY = cameraY.toInt() val howManyX = (sightX.toInt() + 1).coerceAtMost(grid.width - startX - 1) val howManyY = (sightY.toInt() + 1).coerceAtMost(grid.height - startY - 1) for (i in 0..howManyX) { for (j in 0..howManyY) { val tile = grid[startX + i, startY + j] val xOffset = (scaledWidth * (cameraX % 1)).toInt() val yOffset = (scaledHeight * (cameraY % 1)).toInt() drawTile( canvas, tile, i * scaledWidth - xOffset, j * scaledHeight - yOffset ) } } } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) grid?.let { drawGrid(canvas, it) } } }