1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
// 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 <https://www.gnu.org/licenses/>.
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.5f
var cameraY = 0.0f
var sightX = 5.0f
var sightY = 5.0f
val scaledWidth: Int
get() = width / (sightX - cameraX).toInt()
val scaledHeight: Int
get() = height / (sightY - 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 - cameraX).toInt() + 1
val howManyY = (sightY - cameraY).toInt() + 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
)
}
}
}
fun toGridCoordinates(x: Int, y: Int) = Pair(
(x + (scaledWidth * (cameraX % 1)).toInt()) / scaledWidth + cameraX.toInt(),
(y + (scaledHeight * (cameraY % 1)).toInt()) / scaledHeight + cameraY.toInt()
)
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
grid?.let {
drawGrid(canvas, it)
}
}
}
|