├── .gitignore ├── LICENSE ├── LevelMaker ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── fslm │ └── distraction │ └── com │ └── levelmaker │ ├── GridPanel.kt │ ├── LevelMaker.kt │ └── TilePanel.kt ├── android ├── AndroidManifest.xml ├── assets │ ├── sandboxpack.atlas │ └── sandboxpack.png ├── build.gradle ├── ic_launcher-web.png ├── proguard-rules.pro ├── project.properties ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ ├── drawable-xxxhdpi │ │ └── ic_launcher.png │ └── values │ │ ├── strings.xml │ │ └── styles.xml └── src │ └── com │ └── distraction │ └── sandbox │ └── AndroidLauncher.java ├── build.gradle ├── core ├── build.gradle └── src │ └── com │ └── distraction │ └── sandbox │ ├── Animation.kt │ ├── AnimationSet.kt │ ├── Background.kt │ ├── Constants.kt │ ├── Context.kt │ ├── HUD.kt │ ├── MainGame.kt │ ├── NumberFont.kt │ ├── ScoreHandler.kt │ ├── Utils.kt │ ├── states │ ├── GSM.kt │ ├── GameState.kt │ ├── LevelFinishState.kt │ ├── LevelSelectState.kt │ ├── PlayState.kt │ ├── TitleState.kt │ └── TransitionState.kt │ └── tilemap │ ├── TileMap.kt │ ├── TileMapData.kt │ ├── TileObject.kt │ └── tileobjects │ ├── Arrow.kt │ ├── Player.kt │ ├── SuperJump.kt │ ├── Teleport.kt │ └── TileLight.kt ├── desktop ├── build.gradle └── src │ └── com │ └── distraction │ └── sandbox │ └── desktop │ └── DesktopLauncher.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | ## Java 2 | 3 | *.class 4 | *.war 5 | *.ear 6 | hs_err_pid* 7 | 8 | ## Robovm 9 | /ios/robovm-build/ 10 | 11 | ## GWT 12 | /html/war/ 13 | /html/gwt-unitCache/ 14 | .apt_generated/ 15 | .gwt/ 16 | gwt-unitCache/ 17 | www-test/ 18 | .gwt-tmp/ 19 | 20 | ## Android Studio and Intellij and Android in general 21 | /android/libs/armeabi/ 22 | /android/libs/armeabi-v7a/ 23 | /android/libs/arm64-v8a/ 24 | /android/libs/x86/ 25 | /android/libs/x86_64/ 26 | /android/gen/ 27 | .idea/ 28 | *.ipr 29 | *.iws 30 | *.iml 31 | /android/out/ 32 | com_crashlytics_export_strings.xml 33 | 34 | ## Eclipse 35 | 36 | .classpath 37 | .project 38 | .metadata/ 39 | /android/bin/ 40 | /core/bin/ 41 | /desktop/bin/ 42 | /html/bin/ 43 | /ios/bin/ 44 | /ios-moe/bin/ 45 | *.tmp 46 | *.bak 47 | *.swp 48 | *~.nib 49 | .settings/ 50 | .loadpath 51 | .externalToolBuilders/ 52 | *.launch 53 | 54 | ## NetBeans 55 | 56 | /nbproject/private/ 57 | /android/nbproject/private/ 58 | /core/nbproject/private/ 59 | /desktop/nbproject/private/ 60 | /html/nbproject/private/ 61 | /ios/nbproject/private/ 62 | /ios-moe/nbproject/private/ 63 | 64 | /build/ 65 | /android/build/ 66 | /core/build/ 67 | /desktop/build/ 68 | /html/build/ 69 | /ios/build/ 70 | /ios-moe/build/ 71 | 72 | /nbbuild/ 73 | /android/nbbuild/ 74 | /core/nbbuild/ 75 | /desktop/nbbuild/ 76 | /html/nbbuild/ 77 | /ios/nbbuild/ 78 | /ios-moe/nbbuild/ 79 | 80 | /dist/ 81 | /android/dist/ 82 | /core/dist/ 83 | /desktop/dist/ 84 | /html/dist/ 85 | /ios/dist/ 86 | /ios-moe/dist/ 87 | 88 | /nbdist/ 89 | /android/nbdist/ 90 | /core/nbdist/ 91 | /desktop/nbdist/ 92 | /html/nbdist/ 93 | /ios/nbdist/ 94 | /ios-moe/nbdist/ 95 | 96 | nbactions.xml 97 | nb-configuration.xml 98 | 99 | ## Gradle 100 | 101 | /local.properties 102 | .gradle/ 103 | gradle-app.setting 104 | /build/ 105 | /android/build/ 106 | /core/build/ 107 | /desktop/build/ 108 | /html/build/ 109 | /ios/build/ 110 | /ios-moe/build/ 111 | 112 | ## OS Specific 113 | .DS_Store 114 | Thumbs.db 115 | 116 | ## iOS 117 | /ios/xcode/*.xcodeproj/* 118 | !/ios/xcode/*.xcodeproj/xcshareddata 119 | !/ios/xcode/*.xcodeproj/project.pbxproj 120 | /ios/xcode/native/ 121 | 122 | /ios-moe/xcode/*.xcodeproj/* 123 | !/ios-moe/xcode/*.xcodeproj/xcshareddata 124 | !/ios-moe/xcode/*.xcodeproj/project.pbxproj 125 | /ios-moe/xcode/native/ 126 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Mike S 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LevelMaker/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /LevelMaker/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | apply plugin: 'kotlin' 3 | 4 | dependencies { 5 | implementation fileTree(dir: 'libs', include: ['*.jar']) 6 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" 7 | runtimeClasspath files(compileKotlin.destinationDir) 8 | } 9 | 10 | sourceCompatibility = "1.6" 11 | targetCompatibility = "1.6" 12 | -------------------------------------------------------------------------------- /LevelMaker/src/main/java/fslm/distraction/com/levelmaker/GridPanel.kt: -------------------------------------------------------------------------------- 1 | package fslm.distraction.com.levelmaker 2 | 3 | import fslm.distraction.com.levelmaker.Tile.TileObject.* 4 | import java.awt.* 5 | import java.awt.event.MouseAdapter 6 | import java.awt.event.MouseEvent 7 | import javax.swing.JPanel 8 | import javax.swing.SwingUtilities 9 | 10 | class TileObjectData(val tileObject: Tile.TileObject, val row: Int, val col: Int, var row2: Int = -1, var col2: Int = -1) 11 | 12 | class Tile(var row: Int, var col: Int, val rect: Rectangle = Rectangle(), tile: Boolean = false, active: Boolean = false, val objects: ArrayList = arrayListOf()) { 13 | enum class TileObject { 14 | RIGHT, 15 | UP, 16 | DOWN, 17 | LEFT, 18 | JUMP, 19 | TELEPORT; 20 | 21 | fun isArrow() = this == RIGHT || this == UP || this == DOWN || this == LEFT 22 | } 23 | 24 | var tele: TileObjectData? = null 25 | var hasTele = false 26 | 27 | var tile = tile 28 | set(value) { 29 | if (!value) { 30 | active = false 31 | objects.clear() 32 | } 33 | field = value 34 | } 35 | 36 | var active = active 37 | set(value) { 38 | if (tile) { 39 | field = value 40 | } 41 | } 42 | 43 | val inactiveColor = Color(0, 40, 0) 44 | val activeColor = Color(0, 220, 0) 45 | val arrowColor = Color(40, 100, 250) 46 | val jumpColor = Color(250, 250, 40) 47 | val teleportColor = Color(50, 150, 255) 48 | val stroke3 = BasicStroke(3f) 49 | 50 | fun tileObject(tileObject: TileObject) { 51 | if (!tile) { 52 | return 53 | } 54 | if (objects.contains(tileObject)) { 55 | objects.remove(tileObject) 56 | return 57 | } 58 | 59 | when { 60 | tileObject.isArrow() -> objects.removeAll { 61 | it.isArrow() || it == TELEPORT 62 | } 63 | tileObject == JUMP -> objects.removeAll { 64 | it == TELEPORT 65 | } 66 | tileObject == TELEPORT -> objects.removeAll { 67 | it.isArrow() || it == JUMP 68 | } 69 | } 70 | val index = if (tileObject.isArrow()) objects.size else 0 71 | objects.add(index, tileObject) 72 | hasTele = false 73 | } 74 | 75 | fun removeTeleport() { 76 | tele = null 77 | objects.removeAll { 78 | it == TELEPORT 79 | } 80 | } 81 | 82 | fun teleportObject(row: Int, col: Int) { 83 | if (!tile) { 84 | return 85 | } 86 | tele?.let { 87 | it.row2 = row 88 | it.col2 = col 89 | } ?: run { 90 | tele = TileObjectData(TELEPORT, row, col) 91 | } 92 | } 93 | 94 | fun draw(g: Graphics2D) { 95 | g.translate(rect.x, rect.y) 96 | if (tile) { 97 | g.color = if (active) activeColor else inactiveColor 98 | g.fillRect(0, 0, 32, 32) 99 | } else { 100 | g.color = Color.GRAY 101 | g.fillRect(0, 0, 32, 32) 102 | } 103 | val c = g.color 104 | val s = g.stroke 105 | g.stroke = stroke3 106 | for (tileObject in objects) { 107 | when (tileObject) { 108 | LEFT -> { 109 | g.color = arrowColor 110 | g.drawLine(rect.width / 4, rect.height / 2, 3 * rect.width / 4, 3 * rect.height / 4) 111 | g.drawLine(rect.width / 4, rect.height / 2, 3 * rect.width / 4, rect.height / 4) 112 | } 113 | UP -> { 114 | g.color = arrowColor 115 | g.drawLine(rect.width / 2, rect.height / 4, rect.width / 4, 3 * rect.height / 4) 116 | g.drawLine(rect.width / 2, rect.height / 4, 3 * rect.width / 4, 3 * rect.height / 4) 117 | } 118 | RIGHT -> { 119 | g.color = arrowColor 120 | g.drawLine(3 * rect.width / 4, rect.height / 2, rect.width / 4, 3 * rect.height / 4) 121 | g.drawLine(3 * rect.width / 4, rect.height / 2, rect.width / 4, rect.height / 4) 122 | } 123 | DOWN -> { 124 | g.color = arrowColor 125 | g.drawLine(rect.width / 2, 3 * rect.height / 4, rect.width / 4, rect.height / 4) 126 | g.drawLine(rect.width / 2, 3 * rect.height / 4, 3 * rect.width / 4, rect.height / 4) 127 | } 128 | JUMP -> { 129 | g.color = jumpColor 130 | g.drawRect(rect.width / 4, rect.height / 4, rect.width / 2, rect.height / 2) 131 | } 132 | else -> { 133 | } 134 | } 135 | } 136 | g.color = c 137 | g.stroke = s 138 | g.translate(-rect.x, -rect.y) 139 | } 140 | 141 | fun drawTeleports(g: Graphics2D) { 142 | g.translate(rect.x, rect.y) 143 | val c = g.color 144 | val s = g.stroke 145 | g.stroke = stroke3 146 | for (tileObject in objects) { 147 | when (tileObject) { 148 | TELEPORT -> { 149 | g.color = teleportColor 150 | g.drawOval(rect.width / 4, rect.height / 4, rect.width / 2, rect.height / 2) 151 | tele?.let { 152 | if (it.row2 >= 0 && it.col2 >= 0) { 153 | val xdiff = (it.col2 - it.col) * rect.width 154 | val ydiff = (it.row2 - it.row) * rect.height 155 | g.drawOval( 156 | rect.width / 4 + xdiff, 157 | rect.height / 4 + ydiff, 158 | rect.width / 2, 159 | rect.height / 2) 160 | g.drawLine(rect.width / 2, rect.height / 2, rect.width / 2 + xdiff, rect.height / 2 + ydiff) 161 | } 162 | } 163 | } 164 | else -> { 165 | } 166 | } 167 | } 168 | g.color = c 169 | g.stroke = s 170 | g.translate(-rect.x, -rect.y) 171 | } 172 | } 173 | 174 | data class Vector2(var x: Int = 0, var y: Int = 0) 175 | 176 | fun JPanel.paintImmediately() = paintImmediately(0, 0, width, height) 177 | 178 | class GridPanel : JPanel() { 179 | var clickType = TilePanel.ClickType.TILE 180 | set(value) { 181 | if (value != TilePanel.ClickType.TELEPORT) { 182 | gridTele?.let { 183 | val index = tileToIndex(it.row, it.col) 184 | tiles[index].removeTeleport() 185 | val index2 = tileToIndex(it.row2, it.col2) 186 | if (index2 > 0) { 187 | tiles[index2].hasTele = false 188 | } 189 | } 190 | gridTele = null 191 | paintImmediately() 192 | } 193 | 194 | if (value == TilePanel.ClickType.CLEAR) { 195 | for (tile in tiles) { 196 | tile.tile = false 197 | } 198 | moveCount = -1 199 | paintImmediately() 200 | } else if (value == TilePanel.ClickType.DEACTIVATE) { 201 | for (tile in tiles) { 202 | tile.active = false 203 | } 204 | moveCount = -1 205 | paintImmediately() 206 | } else { 207 | field = value 208 | } 209 | } 210 | 211 | val size = 32 212 | val numRows = 24 213 | val numCols = 24 214 | val totalTiles = numRows * numCols 215 | val tiles = Array(totalTiles) { 216 | val (row, col) = indexToTile(it) 217 | Tile(row, col).apply { 218 | val (x, y) = tileToPosition(row, col) 219 | rect.setBounds(x, y, size, size) 220 | } 221 | } 222 | var moveCount = -1 223 | 224 | var gridTele: TileObjectData? = null 225 | 226 | init { 227 | preferredSize = Dimension(size * numCols, size * numRows) 228 | addMouseListener(object : MouseAdapter() { 229 | override fun mousePressed(e: MouseEvent?) { 230 | e?.let { 231 | if (SwingUtilities.isRightMouseButton(e)) { 232 | moveCount-- 233 | paintImmediately() 234 | return 235 | } 236 | val (row, col) = positionToTile(e.x, e.y) 237 | val index = tileToIndex(row, col) 238 | with(tiles[index]) { 239 | when (clickType) { 240 | TilePanel.ClickType.TILE -> tile = !tile 241 | TilePanel.ClickType.ACTIVE -> { 242 | if (tile) { 243 | active = !active 244 | if (!e.isControlDown) { 245 | moveCount++ 246 | } 247 | } 248 | 249 | } 250 | TilePanel.ClickType.RIGHT -> tileObject(RIGHT) 251 | TilePanel.ClickType.UP -> tileObject(UP) 252 | TilePanel.ClickType.DOWN -> tileObject(DOWN) 253 | TilePanel.ClickType.LEFT -> tileObject(LEFT) 254 | TilePanel.ClickType.JUMP -> tileObject(JUMP) 255 | TilePanel.ClickType.TELEPORT -> { 256 | gridTele?.let { 257 | if (tile) { 258 | val index2 = tileToIndex(it.row, it.col) 259 | tiles[index2].teleportObject(row, col) 260 | hasTele = true 261 | gridTele = null 262 | } 263 | } ?: run { 264 | if (tile) { 265 | gridTele = TileObjectData(TELEPORT, row, col) 266 | tileObject(TELEPORT) 267 | teleportObject(row, col) 268 | } 269 | } 270 | } 271 | else -> { 272 | } 273 | } 274 | } 275 | paintImmediately() 276 | } 277 | } 278 | }) 279 | isFocusable = true 280 | } 281 | 282 | override fun paintComponent(g: Graphics?) { 283 | super.paintComponent(g) 284 | val g2 = g as Graphics2D 285 | for (tile in tiles) { 286 | tile.draw(g2) 287 | } 288 | for (tile in tiles) { 289 | tile.drawTeleports(g2) 290 | } 291 | val c = g2.color 292 | g2.color = Color.BLACK 293 | for (i in 0..size) { 294 | g2.drawLine(0, i * size, size * numCols, i * size) 295 | g2.drawLine(i * size, 0, i * size, size * numRows) 296 | } 297 | g2.color = Color.WHITE 298 | g2.fillRect(0, 0, 100, 20) 299 | g2.color = Color.BLACK 300 | g2.drawString("move count: $moveCount", 5, 15) 301 | g2.color = c 302 | } 303 | 304 | fun positionToTile(x: Int, y: Int) = Vector2(y / size, x / size) 305 | fun tileToPosition(row: Int, col: Int) = Vector2(col * size, row * size) 306 | fun indexToTile(index: Int) = Vector2(index / numCols, index % numCols) 307 | fun tileToIndex(row: Int, col: Int) = row * numCols + col 308 | 309 | fun createLevelText(active: Boolean = false): String { 310 | val sb = StringBuilder() 311 | 312 | var minRow = numRows 313 | var minCol = numCols 314 | var maxRow = 0 315 | var maxCol = 0 316 | for (index in 0 until totalTiles) { 317 | if (tiles[index].tile) { 318 | val (row, col) = indexToTile(index) 319 | if (row < minRow) { 320 | minRow = row 321 | } 322 | if (col < minCol) { 323 | minCol = col 324 | } 325 | if (row > maxRow) { 326 | maxRow = row 327 | } 328 | if (col > maxCol) { 329 | maxCol = col 330 | } 331 | } 332 | } 333 | 334 | val gridRows = maxRow - minRow + 1 335 | val gridCols = maxCol - minCol + 1 336 | val minIndex = tileToIndex(minRow, minCol) 337 | val grid = ArrayList(gridRows * gridCols) 338 | val objects = ArrayList() 339 | 340 | for (row in minRow..maxRow) { 341 | for (col in minCol..maxCol) { 342 | val index = tileToIndex(row, col) 343 | val tile = tiles[index] 344 | val arow = row - minRow 345 | val acol = col - minCol 346 | grid.add(if (tile.tile) { if (active && tile.active) 2 else 1 } else 0) 347 | for (tileObject in tile.objects) { 348 | if (tileObject == TELEPORT) { 349 | tile.tele?.let { 350 | val arow2 = it.row2 - minRow 351 | val acol2 = it.col2 - minCol 352 | objects.add(TileObjectData(tileObject, arow, acol, arow2, acol2)) 353 | } 354 | } else { 355 | objects.add(TileObjectData(tileObject, arow, acol)) 356 | } 357 | } 358 | } 359 | } 360 | objects.sortWith(Comparator { t1, t2 -> 361 | if (t1.tileObject.isArrow()) -1 else 1 362 | }) 363 | 364 | sb.append("TileMapDataModel($gridRows, $gridCols, intArrayOf(\n") 365 | sb.append("\t${grid.joinToString(", ", "\n", gridCols)}\n)${if (objects.size > 0) ", arrayOf(\n" else ")"}") 366 | if (objects.size > 0) { 367 | sb.append("\t\t${objects.joinToString(",\n", transform = { 368 | when (it.tileObject) { 369 | RIGHT -> "arrowRight(${it.row}, ${it.col})" 370 | UP -> "arrowUp(${it.row}, ${it.col})" 371 | DOWN -> "arrowDown(${it.row}, ${it.col})" 372 | LEFT -> "arrowLeft(${it.row}, ${it.col})" 373 | JUMP -> "superJump(${it.row}, ${it.col})" 374 | TELEPORT -> "teleport(${it.row}, ${it.col}, ${it.row2}, ${it.col2})" 375 | } 376 | })}))") 377 | } 378 | return sb.toString() 379 | } 380 | } 381 | 382 | fun Iterable.joinToString(separator: CharSequence = ", ", separator2: CharSequence = "", separator2interval: Int = 0, prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { 383 | return joinTo(StringBuilder(), separator, separator2, separator2interval, prefix, postfix, limit, truncated, transform).toString() 384 | } 385 | 386 | fun Iterable.joinTo(buffer: A, separator: CharSequence = ", ", separator2: CharSequence = "", separator2interval: Int = 0, prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): A { 387 | buffer.append(prefix) 388 | var count = 0 389 | var count2 = 0 390 | for (element in this) { 391 | if (++count > 1) buffer.append(separator) 392 | if (++count2 > separator2interval) { 393 | count2 = 1 394 | buffer.append(separator2) 395 | } 396 | if (limit < 0 || count <= limit) { 397 | buffer.appendElement(element, transform) 398 | } else break 399 | } 400 | if (limit in 0..(count - 1)) buffer.append(truncated) 401 | buffer.append(postfix) 402 | return buffer 403 | } 404 | 405 | fun Appendable.appendElement(element: T, transform: ((T) -> CharSequence)?) { 406 | when { 407 | transform != null -> append(transform(element)) 408 | element is CharSequence? -> append(element) 409 | element is Char -> append(element) 410 | else -> append(element.toString()) 411 | } 412 | } 413 | -------------------------------------------------------------------------------- /LevelMaker/src/main/java/fslm/distraction/com/levelmaker/LevelMaker.kt: -------------------------------------------------------------------------------- 1 | package fslm.distraction.com.levelmaker 2 | 3 | import java.awt.Toolkit 4 | import java.awt.datatransfer.StringSelection 5 | import java.awt.event.ActionEvent 6 | import java.awt.event.ActionListener 7 | import java.awt.event.KeyEvent 8 | import javax.swing.* 9 | 10 | fun main(args: Array) { 11 | LevelMaker() 12 | } 13 | 14 | class LevelMaker : ClickTypeListener, ActionListener { 15 | val frame = JFrame() 16 | val gridPanel = GridPanel() 17 | val tilePanel = TilePanel(this) 18 | 19 | init { 20 | 21 | frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE 22 | 23 | val menubar = JMenuBar() 24 | val fileMenu = JMenu("File") 25 | menubar.add(fileMenu) 26 | 27 | fileMenu.add(createMenuItem("Export", KeyEvent.VK_E)) 28 | fileMenu.add(createMenuItem("Export active", KeyEvent.VK_A)) 29 | frame.jMenuBar = menubar 30 | 31 | frame.contentPane = JPanel().apply { 32 | layout = BoxLayout(this, BoxLayout.Y_AXIS) 33 | } 34 | frame.contentPane.add(gridPanel) 35 | frame.contentPane.add(tilePanel) 36 | frame.pack() 37 | frame.setLocationRelativeTo(null) 38 | frame.isVisible = true 39 | } 40 | 41 | override fun onClickType(clickType: TilePanel.ClickType) { 42 | gridPanel.clickType = clickType 43 | } 44 | 45 | override fun actionPerformed(e: ActionEvent?) { 46 | e?.let { 47 | when (e.actionCommand) { 48 | "Export" -> { 49 | val str = gridPanel.createLevelText() 50 | JOptionPane.showMessageDialog(frame, str) 51 | Toolkit.getDefaultToolkit().systemClipboard.setContents(StringSelection(str), null) 52 | } 53 | "Export active" -> { 54 | val str = gridPanel.createLevelText(true) 55 | JOptionPane.showMessageDialog(frame, str) 56 | Toolkit.getDefaultToolkit().systemClipboard.setContents(StringSelection(str), null) 57 | } 58 | } 59 | } 60 | } 61 | 62 | fun createMenuItem(text: String, key: Int) = JMenuItem(text).apply { 63 | accelerator = KeyStroke.getKeyStroke(key, ActionEvent.CTRL_MASK) 64 | actionCommand = text 65 | addActionListener(this@LevelMaker) 66 | } 67 | } -------------------------------------------------------------------------------- /LevelMaker/src/main/java/fslm/distraction/com/levelmaker/TilePanel.kt: -------------------------------------------------------------------------------- 1 | package fslm.distraction.com.levelmaker 2 | 3 | import java.awt.Color 4 | import java.awt.Dimension 5 | import java.awt.Graphics 6 | import java.awt.event.ActionEvent 7 | import java.awt.event.ActionListener 8 | import javax.swing.JButton 9 | import javax.swing.JLabel 10 | import javax.swing.JOptionPane 11 | import javax.swing.JPanel 12 | 13 | interface ClickTypeListener { 14 | fun onClickType(clickType: TilePanel.ClickType) 15 | } 16 | 17 | class TilePanel(val clickTypeListener: ClickTypeListener) : JPanel(), ActionListener { 18 | enum class ClickType(val tileType: Boolean = true) { 19 | TILE, 20 | ACTIVE, 21 | RIGHT, 22 | UP, 23 | DOWN, 24 | LEFT, 25 | JUMP, 26 | TELEPORT, 27 | CLEAR(false), 28 | DEACTIVATE(false) 29 | } 30 | 31 | val label = JLabel(ClickType.TILE.name) 32 | 33 | override fun actionPerformed(e: ActionEvent?) { 34 | e?.let { 35 | val clickType = ClickType.valueOf(e.actionCommand) 36 | if (!clickType.tileType) { 37 | if (JOptionPane.showConfirmDialog(null, clickType.name, "", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) { 38 | return 39 | } 40 | } 41 | clickTypeListener.onClickType(clickType) 42 | if (clickType.tileType) { 43 | label.text = e.actionCommand 44 | } 45 | } 46 | } 47 | 48 | init { 49 | preferredSize = Dimension(300, 100) 50 | isFocusable = true 51 | 52 | for (clickType in ClickType.values()) { 53 | addButton(clickType.name) 54 | } 55 | add(label) 56 | } 57 | 58 | fun addButton(text: String) { 59 | add(JButton(text).apply { 60 | addActionListener(this@TilePanel) 61 | actionCommand = text 62 | }) 63 | } 64 | 65 | override fun paintComponent(g: Graphics?) { 66 | super.paintComponent(g) 67 | g?.let { 68 | val c = g.color 69 | g.color = Color.BLACK 70 | g.fillRect(0, 0, width, height) 71 | g.color = c 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /android/assets/sandboxpack.atlas: -------------------------------------------------------------------------------- 1 | 2 | sandboxpack.png 3 | size: 512,64 4 | format: RGBA8888 5 | filter: Nearest,Nearest 6 | repeat: none 7 | 0 8 | rotate: false 9 | xy: 87, 12 10 | size: 5, 7 11 | orig: 5, 7 12 | offset: 0, 0 13 | index: -1 14 | 1 15 | rotate: false 16 | xy: 265, 22 17 | size: 3, 7 18 | orig: 3, 7 19 | offset: 0, 0 20 | index: -1 21 | 2 22 | rotate: false 23 | xy: 105, 32 24 | size: 5, 7 25 | orig: 5, 7 26 | offset: 0, 0 27 | index: -1 28 | 3 29 | rotate: false 30 | xy: 109, 41 31 | size: 5, 7 32 | orig: 5, 7 33 | offset: 0, 0 34 | index: -1 35 | 4 36 | rotate: false 37 | xy: 112, 32 38 | size: 5, 7 39 | orig: 5, 7 40 | offset: 0, 0 41 | index: -1 42 | 5 43 | rotate: false 44 | xy: 65, 3 45 | size: 5, 7 46 | orig: 5, 7 47 | offset: 0, 0 48 | index: -1 49 | 6 50 | rotate: false 51 | xy: 372, 55 52 | size: 5, 7 53 | orig: 5, 7 54 | offset: 0, 0 55 | index: -1 56 | 7 57 | rotate: false 58 | xy: 94, 12 59 | size: 5, 7 60 | orig: 5, 7 61 | offset: 0, 0 62 | index: -1 63 | 8 64 | rotate: false 65 | xy: 105, 23 66 | size: 5, 7 67 | orig: 5, 7 68 | offset: 0, 0 69 | index: -1 70 | 9 71 | rotate: false 72 | xy: 112, 23 73 | size: 5, 7 74 | orig: 5, 7 75 | offset: 0, 0 76 | index: -1 77 | arrow 78 | rotate: false 79 | xy: 52, 3 80 | size: 11, 7 81 | orig: 11, 7 82 | offset: 0, 0 83 | index: -1 84 | arrowbutton 85 | rotate: false 86 | xy: 336, 36 87 | size: 17, 17 88 | orig: 17, 17 89 | offset: 0, 0 90 | index: -1 91 | back 92 | rotate: false 93 | xy: 2, 2 94 | size: 48, 15 95 | orig: 48, 15 96 | offset: 0, 0 97 | index: -1 98 | best 99 | rotate: false 100 | xy: 337, 55 101 | size: 22, 7 102 | orig: 22, 7 103 | offset: 0, 0 104 | index: -1 105 | bgs 106 | rotate: false 107 | xy: 361, 53 108 | size: 9, 9 109 | orig: 9, 9 110 | offset: 0, 0 111 | index: -1 112 | complete 113 | rotate: false 114 | xy: 2, 36 115 | size: 82, 12 116 | orig: 82, 12 117 | offset: 0, 0 118 | index: -1 119 | dot 120 | rotate: false 121 | xy: 116, 47 122 | size: 1, 1 123 | orig: 1, 1 124 | offset: 0, 0 125 | index: -1 126 | goal 127 | rotate: false 128 | xy: 86, 41 129 | size: 21, 7 130 | orig: 21, 7 131 | offset: 0, 0 132 | index: -1 133 | levelcheck 134 | rotate: false 135 | xy: 271, 22 136 | size: 14, 11 137 | orig: 14, 11 138 | offset: 0, 0 139 | index: -1 140 | levelicon 141 | rotate: false 142 | xy: 211, 22 143 | size: 23, 23 144 | orig: 23, 23 145 | offset: 0, 0 146 | index: -1 147 | levelselect 148 | rotate: false 149 | xy: 2, 50 150 | size: 115, 12 151 | orig: 115, 12 152 | offset: 0, 0 153 | index: -1 154 | levelselectarrow 155 | rotate: false 156 | xy: 287, 22 157 | size: 10, 11 158 | orig: 10, 11 159 | offset: 0, 0 160 | index: -1 161 | moves 162 | rotate: false 163 | xy: 236, 22 164 | size: 27, 7 165 | orig: 27, 7 166 | offset: 0, 0 167 | index: -1 168 | newrecord 169 | rotate: false 170 | xy: 232, 55 171 | size: 53, 7 172 | orig: 53, 7 173 | offset: 0, 0 174 | index: -1 175 | next 176 | rotate: false 177 | xy: 2, 19 178 | size: 48, 15 179 | orig: 48, 15 180 | offset: 0, 0 181 | index: -1 182 | numbers 183 | rotate: false 184 | xy: 287, 55 185 | size: 48, 7 186 | orig: 48, 7 187 | offset: 0, 0 188 | index: -1 189 | playercrouch 190 | rotate: false 191 | xy: 87, 21 192 | size: 16, 18 193 | orig: 16, 18 194 | offset: 0, 0 195 | index: -1 196 | playercrouchr 197 | rotate: false 198 | xy: 264, 2 199 | size: 16, 18 200 | orig: 16, 18 201 | offset: 0, 0 202 | index: -1 203 | playeridle 204 | rotate: false 205 | xy: 271, 35 206 | size: 32, 18 207 | orig: 32, 18 208 | offset: 0, 0 209 | index: -1 210 | playeridler 211 | rotate: false 212 | xy: 211, 2 213 | size: 32, 18 214 | orig: 32, 18 215 | offset: 0, 0 216 | index: -1 217 | playerjump 218 | rotate: false 219 | xy: 297, 2 220 | size: 13, 18 221 | orig: 13, 18 222 | offset: 0, 0 223 | index: -1 224 | playerjumpr 225 | rotate: false 226 | xy: 282, 2 227 | size: 13, 18 228 | orig: 13, 18 229 | offset: 0, 0 230 | index: -1 231 | restart 232 | rotate: false 233 | xy: 182, 47 234 | size: 48, 15 235 | orig: 48, 15 236 | offset: 0, 0 237 | index: -1 238 | superjump 239 | rotate: false 240 | xy: 305, 38 241 | size: 29, 15 242 | orig: 29, 15 243 | offset: 0, 0 244 | index: -1 245 | teleport 246 | rotate: false 247 | xy: 245, 2 248 | size: 17, 18 249 | orig: 17, 18 250 | offset: 0, 0 251 | index: -1 252 | tile 253 | rotate: false 254 | xy: 52, 12 255 | size: 33, 22 256 | orig: 33, 22 257 | offset: 0, 0 258 | index: -1 259 | tilea 260 | rotate: false 261 | xy: 236, 31 262 | size: 33, 22 263 | orig: 33, 22 264 | offset: 0, 0 265 | index: -1 266 | tilelight 267 | rotate: false 268 | xy: 182, 16 269 | size: 27, 29 270 | orig: 27, 29 271 | offset: 0, 0 272 | index: -1 273 | title 274 | rotate: false 275 | xy: 119, 12 276 | size: 61, 50 277 | orig: 61, 50 278 | offset: 0, 0 279 | index: -1 280 | -------------------------------------------------------------------------------- /android/assets/sandboxpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreignguymike/Sandbox/526a5c4e0096a0bd7cbd959eb394921ba48912a8/android/assets/sandboxpack.png -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | android { 2 | buildToolsVersion "28.0.3" 3 | compileSdkVersion 28 4 | sourceSets { 5 | main { 6 | manifest.srcFile 'AndroidManifest.xml' 7 | java.srcDirs = ['src'] 8 | aidl.srcDirs = ['src'] 9 | renderscript.srcDirs = ['src'] 10 | res.srcDirs = ['res'] 11 | assets.srcDirs = ['assets'] 12 | jniLibs.srcDirs = ['libs'] 13 | } 14 | 15 | } 16 | packagingOptions { 17 | exclude 'META-INF/robovm/ios/robovm.xml' 18 | } 19 | defaultConfig { 20 | applicationId "com.distraction.flippyslime" 21 | minSdkVersion 9 22 | targetSdkVersion 28 23 | versionCode 3 24 | versionName "1.2" 25 | } 26 | buildTypes { 27 | release { 28 | minifyEnabled false 29 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 30 | } 31 | } 32 | } 33 | 34 | 35 | // called every time gradle gets executed, takes the native dependencies of 36 | // the natives configuration, and extracts them to the proper libs/ folders 37 | // so they get packed with the APK. 38 | task copyAndroidNatives { 39 | doFirst { 40 | file("libs/armeabi/").mkdirs() 41 | file("libs/armeabi-v7a/").mkdirs() 42 | file("libs/arm64-v8a/").mkdirs() 43 | file("libs/x86_64/").mkdirs() 44 | file("libs/x86/").mkdirs() 45 | 46 | configurations.natives.files.each { jar -> 47 | def outputDir = null 48 | if (jar.name.endsWith("natives-arm64-v8a.jar")) outputDir = file("libs/arm64-v8a") 49 | if (jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a") 50 | if(jar.name.endsWith("natives-armeabi.jar")) outputDir = file("libs/armeabi") 51 | if(jar.name.endsWith("natives-x86_64.jar")) outputDir = file("libs/x86_64") 52 | if(jar.name.endsWith("natives-x86.jar")) outputDir = file("libs/x86") 53 | if(outputDir != null) { 54 | copy { 55 | from zipTree(jar) 56 | into outputDir 57 | include "*.so" 58 | } 59 | } 60 | } 61 | } 62 | } 63 | 64 | tasks.whenTaskAdded { packageTask -> 65 | if (packageTask.name.contains("package")) { 66 | packageTask.dependsOn 'copyAndroidNatives' 67 | } 68 | } 69 | 70 | task run(type: Exec) { 71 | def path 72 | def localProperties = project.file("../local.properties") 73 | if (localProperties.exists()) { 74 | Properties properties = new Properties() 75 | localProperties.withInputStream { instr -> 76 | properties.load(instr) 77 | } 78 | def sdkDir = properties.getProperty('sdk.dir') 79 | if (sdkDir) { 80 | path = sdkDir 81 | } else { 82 | path = "$System.env.ANDROID_HOME" 83 | } 84 | } else { 85 | path = "$System.env.ANDROID_HOME" 86 | } 87 | 88 | def adb = path + "/platform-tools/adb" 89 | commandLine "$adb", 'shell', 'am', 'start', '-n', 'com.distraction.sandbox/com.distraction.sandbox.AndroidLauncher' 90 | } 91 | 92 | // sets up the Android Eclipse project, using the old Ant based build. 93 | eclipse { 94 | // need to specify Java source sets explicitly, SpringSource Gradle Eclipse plugin 95 | // ignores any nodes added in classpath.file.withXml 96 | sourceSets { 97 | main { 98 | java.srcDirs "src", 'gen' 99 | } 100 | } 101 | 102 | jdt { 103 | sourceCompatibility = 1.6 104 | targetCompatibility = 1.6 105 | } 106 | 107 | classpath { 108 | plusConfigurations += [ project.configurations.compile ] 109 | containers 'com.android.ide.eclipse.adt.ANDROID_FRAMEWORK', 'com.android.ide.eclipse.adt.LIBRARIES' 110 | } 111 | 112 | project { 113 | name = appName + "-android" 114 | natures 'com.android.ide.eclipse.adt.AndroidNature' 115 | buildCommands.clear(); 116 | buildCommand "com.android.ide.eclipse.adt.ResourceManagerBuilder" 117 | buildCommand "com.android.ide.eclipse.adt.PreCompilerBuilder" 118 | buildCommand "org.eclipse.jdt.core.javabuilder" 119 | buildCommand "com.android.ide.eclipse.adt.ApkBuilder" 120 | } 121 | } 122 | 123 | // sets up the Android Idea project, using the old Ant based build. 124 | idea { 125 | module { 126 | sourceDirs += file("src"); 127 | scopes = [ COMPILE: [plus:[project.configurations.compile]]] 128 | 129 | iml { 130 | withXml { 131 | def node = it.asNode() 132 | def builder = NodeBuilder.newInstance(); 133 | builder.current = node; 134 | builder.component(name: "FacetManager") { 135 | facet(type: "android", name: "Android") { 136 | configuration { 137 | option(name: "UPDATE_PROPERTY_FILES", value:"true") 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /android/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreignguymike/Sandbox/526a5c4e0096a0bd7cbd959eb394921ba48912a8/android/ic_launcher-web.png -------------------------------------------------------------------------------- /android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | 22 | -verbose 23 | 24 | -dontwarn android.support.** 25 | -dontwarn com.badlogic.gdx.backends.android.AndroidFragmentApplication 26 | -dontwarn com.badlogic.gdx.utils.GdxBuild 27 | -dontwarn com.badlogic.gdx.physics.box2d.utils.Box2DBuild 28 | -dontwarn com.badlogic.gdx.jnigen.BuildTarget* 29 | -dontwarn com.badlogic.gdx.graphics.g2d.freetype.FreetypeBuild 30 | 31 | -keep class com.badlogic.gdx.controllers.android.AndroidControllers 32 | 33 | -keepclassmembers class com.badlogic.gdx.backends.android.AndroidInput* { 34 | (com.badlogic.gdx.Application, android.content.Context, java.lang.Object, com.badlogic.gdx.backends.android.AndroidApplicationConfiguration); 35 | } 36 | 37 | -keepclassmembers class com.badlogic.gdx.physics.box2d.World { 38 | boolean contactFilter(long, long); 39 | void beginContact(long); 40 | void endContact(long); 41 | void preSolve(long, long); 42 | void postSolve(long, long); 43 | boolean reportFixture(long); 44 | float reportRayFixture(long, float, float, float, float, float); 45 | } 46 | -------------------------------------------------------------------------------- /android/project.properties: -------------------------------------------------------------------------------- 1 | # This file is used by the Eclipse ADT plugin. It is unnecessary for IDEA and Android Studio projects, which 2 | # configure Proguard and the Android target via the build.gradle file. 3 | 4 | # To enable ProGuard to work with Eclipse ADT, uncomment this (available properties: sdk.dir, user.home) 5 | # and ensure proguard.jar in the Android SDK is up to date (or alternately reduce the android target to 23 or lower): 6 | # proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-rules.pro 7 | 8 | # Project target. 9 | target=android-19 10 | -------------------------------------------------------------------------------- /android/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreignguymike/Sandbox/526a5c4e0096a0bd7cbd959eb394921ba48912a8/android/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreignguymike/Sandbox/526a5c4e0096a0bd7cbd959eb394921ba48912a8/android/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreignguymike/Sandbox/526a5c4e0096a0bd7cbd959eb394921ba48912a8/android/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreignguymike/Sandbox/526a5c4e0096a0bd7cbd959eb394921ba48912a8/android/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreignguymike/Sandbox/526a5c4e0096a0bd7cbd959eb394921ba48912a8/android/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Flippy Slime 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/src/com/distraction/sandbox/AndroidLauncher.java: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.badlogic.gdx.backends.android.AndroidApplication; 6 | import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; 7 | 8 | public class AndroidLauncher extends AndroidApplication { 9 | @Override 10 | protected void onCreate (Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); 13 | initialize(new MainGame(), config); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlinVersion = '1.2.60' 3 | 4 | repositories { 5 | mavenLocal() 6 | mavenCentral() 7 | maven { url "https://plugins.gradle.org/m2/" } 8 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } 9 | jcenter() 10 | google() 11 | } 12 | 13 | dependencies { 14 | classpath 'com.android.tools.build:gradle:3.2.1' 15 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" 16 | } 17 | } 18 | 19 | allprojects { 20 | apply plugin: "eclipse" 21 | apply plugin: "idea" 22 | 23 | version = '1.0' 24 | ext { 25 | appName = "Sandbox" 26 | gdxVersion = '1.9.8' 27 | roboVMVersion = '2.3.5' 28 | box2DLightsVersion = '1.4' 29 | ashleyVersion = '1.7.0' 30 | aiVersion = '1.8.0' 31 | } 32 | 33 | repositories { 34 | mavenLocal() 35 | jcenter() 36 | google() 37 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } 38 | maven { url "https://oss.sonatype.org/content/repositories/releases/" } 39 | } 40 | } 41 | 42 | project(":desktop") { 43 | apply plugin: "kotlin" 44 | 45 | dependencies { 46 | implementation project(":core") 47 | implementation "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion" 48 | implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" 49 | implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop" 50 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 51 | } 52 | } 53 | 54 | project(":android") { 55 | apply plugin: "android" 56 | apply plugin: "kotlin-android" 57 | 58 | configurations { natives } 59 | 60 | dependencies { 61 | implementation project(":core") 62 | implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion" 63 | natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi" 64 | natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a" 65 | natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a" 66 | natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86" 67 | natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64" 68 | 69 | implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" 70 | natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi" 71 | natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a" 72 | natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a" 73 | natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86" 74 | natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64" 75 | 76 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 77 | } 78 | } 79 | 80 | project(":core") { 81 | apply plugin: "kotlin" 82 | 83 | dependencies { 84 | implementation "com.badlogicgames.gdx:gdx:$gdxVersion" 85 | implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" 86 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 87 | } 88 | } 89 | 90 | tasks.eclipse.doLast { 91 | delete ".project" 92 | } -------------------------------------------------------------------------------- /core/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "kotlin" 2 | 3 | sourceCompatibility = 1.6 4 | [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' 5 | 6 | sourceSets.main.java.srcDirs = [ "src/" ] 7 | 8 | 9 | eclipse.project { 10 | name = appName + "-core" 11 | } 12 | -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/Animation.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | import com.badlogic.gdx.graphics.g2d.TextureRegion 4 | 5 | class Animation( 6 | val sprites: Array, 7 | val delay: Float = 1f/60) { 8 | 9 | private var time = 0f 10 | private var frameIndex = 0 11 | private var playCount = 0 12 | 13 | fun reset() { 14 | time = 0f 15 | frameIndex = 0 16 | playCount = 0 17 | } 18 | 19 | fun update(dt: Float) { 20 | if (delay < 0) { 21 | return 22 | } 23 | time += dt 24 | while (time >= delay) { 25 | time -= delay 26 | frameIndex++ 27 | if (frameIndex >= sprites.size) { 28 | frameIndex = 0 29 | playCount++ 30 | } 31 | } 32 | } 33 | 34 | fun getImage() = sprites[frameIndex] 35 | 36 | fun hasPlayedOnce() = playCount > 0 37 | 38 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/AnimationSet.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | class AnimationSet { 4 | 5 | val set = hashMapOf() 6 | var currentAnimationKey: String? = null 7 | var currentAnimation: Animation? = null 8 | 9 | fun addAnimation(key: String, value: Animation) { 10 | set.put(key, value) 11 | } 12 | 13 | fun setAnimation(key: String) { 14 | if (key.equals(currentAnimationKey)) { 15 | return 16 | } 17 | currentAnimationKey = key 18 | currentAnimation = set[key] 19 | currentAnimation?.reset() 20 | } 21 | 22 | fun update(dt: Float) = currentAnimation?.update(dt) 23 | 24 | fun getImage() = currentAnimation?.getImage() 25 | 26 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/Background.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | import com.badlogic.gdx.graphics.Color 4 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 5 | import com.badlogic.gdx.math.MathUtils 6 | import com.badlogic.gdx.math.Vector3 7 | 8 | class Background(val context: Context, var color: Color = Color.valueOf("4CB0DB")) { 9 | 10 | private val dot = context.assets.getAtlas().findRegion("dot") 11 | private val image = context.assets.getAtlas().findRegion("bgs") 12 | 13 | private val bgs = arrayListOf() 14 | private val speed = 5f 15 | private val interval = 5f 16 | private var time = interval 17 | private var time2 = 0f 18 | private var rot = 0f 19 | 20 | init { 21 | for (row in 0..5) { 22 | for (col in -4..4) { 23 | bgs.add(Vector3(1f * col * Constants.WIDTH / 4 + (row + 1) * speed * interval, row * speed * interval, 0f)) 24 | } 25 | } 26 | } 27 | 28 | fun update(dt: Float) { 29 | time += dt 30 | time2 += dt 31 | while (time > interval) { 32 | time -= interval 33 | for (i in -4..4) { 34 | bgs.add(Vector3(1f * i * Constants.WIDTH / 4, -speed * interval, 0f)) 35 | } 36 | } 37 | rot = MathUtils.sin(time2) 38 | bgs.forEach { 39 | it.x += speed * dt 40 | it.y += speed * dt 41 | it.z = rot 42 | } 43 | bgs.removeAll { 44 | it.x > Constants.WIDTH && it.y > Constants.HEIGHT 45 | } 46 | } 47 | 48 | fun render(sb: SpriteBatch) { 49 | val c = sb.color 50 | sb.color = color 51 | sb.draw(dot, 0f, 0f, Constants.WIDTH, Constants.HEIGHT) 52 | sb.color = Color.WHITE 53 | bgs.forEach { 54 | sb.draw(image, it.x - rot * image.regionWidth / 2, it.y, rot * image.regionWidth, 1f * image.regionHeight) 55 | } 56 | sb.color = c 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | class Constants { 4 | 5 | companion object { 6 | const val WIDTH = 1920f / 8f 7 | const val HEIGHT = 1080f / 8f 8 | 9 | const val DESKTOP_WIDTH = 1920 / 2 10 | const val DESKTOP_HEIGHT = 1080 / 2 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/Context.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | import com.badlogic.gdx.assets.AssetManager 4 | import com.distraction.sandbox.states.GSM 5 | 6 | class Context { 7 | lateinit var assets: AssetManager 8 | lateinit var gsm: GSM 9 | lateinit var scoreHandler: ScoreHandler 10 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/HUD.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | import com.badlogic.gdx.Gdx 4 | import com.badlogic.gdx.graphics.Color 5 | import com.badlogic.gdx.graphics.OrthographicCamera 6 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 7 | import com.badlogic.gdx.graphics.g2d.TextureRegion 8 | import com.badlogic.gdx.math.Rectangle 9 | import com.badlogic.gdx.math.Vector2 10 | import com.badlogic.gdx.math.Vector3 11 | import com.distraction.sandbox.ButtonListener.ButtonType.* 12 | 13 | interface ButtonListener { 14 | enum class ButtonType { 15 | UP, 16 | LEFT, 17 | DOWN, 18 | RIGHT, 19 | RESTART, 20 | BACK 21 | } 22 | 23 | fun onButtonPressed(type: ButtonType) 24 | } 25 | 26 | open class Button(val image: TextureRegion, val rect: Rectangle, val color: Color = Color(1f, 1f, 1f, 1f), val centered: Boolean = false) { 27 | constructor(image: TextureRegion, x: Float = 0f, y: Float = 0f, color: Color = Color(1f, 1f, 1f, 1f), centered: Boolean = false) : 28 | this( 29 | image, 30 | Rectangle(if (centered) (Constants.WIDTH - image.regionWidth) / 2f else x, y, 1f * image.regionWidth, 1f * image.regionHeight), 31 | color, 32 | centered) 33 | } 34 | 35 | class NumberLabel(context: Context, val image: TextureRegion, val pos: Vector2, var num: Int) { 36 | private val numberFont = NumberFont(context) 37 | fun render(sb: SpriteBatch) { 38 | sb.draw(image, pos.x, pos.y) 39 | numberFont.render(sb, pos.x + image.regionWidth + 5, pos.y, num) 40 | } 41 | } 42 | 43 | class HUD(context: Context, private val buttonListener: ButtonListener) { 44 | private val touchPoint = Vector3() 45 | private val alpha = 0.5f 46 | 47 | private val buttons = hashMapOf( 48 | LEFT to 49 | Button(context.assets.getAtlas().findRegion("arrowbutton"), 50 | 6f, 26f, 51 | Color(1f, 1f, 1f, alpha)), 52 | UP to 53 | Button(context.assets.getAtlas().findRegion("arrowbutton"), 54 | 21f, 41f, 55 | Color(1f, 1f, 1f, alpha)), 56 | RIGHT to 57 | Button(context.assets.getAtlas().findRegion("arrowbutton"), 58 | 36f, 26f, 59 | Color(1f, 1f, 1f, alpha)), 60 | DOWN to 61 | Button(context.assets.getAtlas().findRegion("arrowbutton"), 62 | 21f, 11f, 63 | Color(1f, 1f, 1f, alpha)), 64 | BACK to 65 | Button(context.assets.getAtlas().findRegion("back"), 66 | 5f, 115f), 67 | RESTART to 68 | Button(context.assets.getAtlas().findRegion("restart"), 69 | 5f, 98f)) 70 | 71 | private val labels = arrayOf( 72 | NumberLabel( 73 | context, 74 | context.assets.getAtlas().findRegion("goal"), 75 | Vector2(Constants.WIDTH - 50f, Constants.HEIGHT - 16f), 76 | 0), 77 | NumberLabel( 78 | context, 79 | context.assets.getAtlas().findRegion("best"), 80 | Vector2(Constants.WIDTH - 50f, Constants.HEIGHT - 25f), 81 | 0), 82 | NumberLabel( 83 | context, 84 | context.assets.getAtlas().findRegion("moves"), 85 | Vector2(Constants.WIDTH - 55f, Constants.HEIGHT - 34f), 86 | 0)) 87 | 88 | fun setGoal(goal: Int) { 89 | labels[0].num = goal 90 | } 91 | fun setBest(best: Int) { 92 | labels[1].num = best 93 | } 94 | 95 | fun getBest() = labels[1].num 96 | fun incrementMoves() = labels[2].num++ 97 | fun getMoves() = labels[2].num 98 | 99 | private val cam = OrthographicCamera().apply { 100 | setToOrtho(false, Constants.WIDTH, Constants.HEIGHT) 101 | } 102 | private val fontCam = OrthographicCamera().apply { 103 | setToOrtho(false, Constants.WIDTH * 2f, Constants.HEIGHT * 2f) 104 | } 105 | 106 | fun update(dt: Float) { 107 | if (Gdx.input.isTouched) { 108 | touchPoint.set(1f * Gdx.input.x, 1f * Gdx.input.y, 0f) 109 | cam.unproject(touchPoint) 110 | 111 | buttons.forEach { (key, value) -> 112 | if (value.rect.contains(touchPoint)) { 113 | buttonListener.onButtonPressed(key) 114 | } 115 | } 116 | } 117 | } 118 | 119 | fun render(sb: SpriteBatch) { 120 | sb.projectionMatrix = fontCam.combined 121 | sb.projectionMatrix = cam.combined 122 | buttons.forEach { (key, value) -> 123 | val c = sb.color 124 | sb.color = value.color 125 | when (key) { 126 | LEFT -> sb.drawRotated(value.image, value.rect.x, value.rect.y, 90f) 127 | DOWN -> sb.draw(value.image, value.rect.x, value.rect.y + value.image.regionHeight, 1f * value.image.regionWidth, 1f * -value.image.regionHeight) 128 | RIGHT -> sb.drawRotated(value.image, value.rect.x, value.rect.y, -90f) 129 | else -> sb.draw(value.image, value.rect.x, value.rect.y) 130 | } 131 | sb.color = c 132 | } 133 | labels.forEach { 134 | it.render(sb) 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/MainGame.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | import com.badlogic.gdx.ApplicationAdapter 4 | import com.badlogic.gdx.Gdx 5 | import com.badlogic.gdx.assets.AssetManager 6 | import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver 7 | import com.badlogic.gdx.graphics.g2d.BitmapFont 8 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 9 | import com.badlogic.gdx.graphics.g2d.TextureAtlas 10 | import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator 11 | import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGeneratorLoader 12 | import com.badlogic.gdx.graphics.g2d.freetype.FreetypeFontLoader 13 | import com.distraction.sandbox.states.GSM 14 | import com.distraction.sandbox.states.TitleState 15 | 16 | class MainGame : ApplicationAdapter() { 17 | private lateinit var sb: SpriteBatch 18 | private lateinit var gsm: GSM 19 | 20 | override fun create() { 21 | val assets = AssetManager() 22 | gsm = GSM() 23 | val context = Context() 24 | context.assets = assets 25 | context.gsm = gsm 26 | context.scoreHandler = ScoreHandler().apply { load() } 27 | 28 | val resolver = InternalFileHandleResolver() 29 | assets.setLoader(FreeTypeFontGenerator::class.java, FreeTypeFontGeneratorLoader(resolver)) 30 | assets.setLoader(BitmapFont::class.java, ".ttf", FreetypeFontLoader(resolver)) 31 | 32 | assets.load("sandboxpack.atlas", TextureAtlas::class.java) 33 | 34 | assets.finishLoading() 35 | 36 | sb = SpriteBatch() 37 | gsm.push(TitleState(context)) 38 | } 39 | 40 | override fun render() { 41 | clearScreen() 42 | 43 | gsm.update(Gdx.graphics.deltaTime) 44 | gsm.render(sb) 45 | } 46 | 47 | override fun dispose() { 48 | sb.dispose() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/NumberFont.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 4 | 5 | fun Char.intValue(): Int = if (this !in '0'..'9') throw NumberFormatException() else toInt() - '0'.toInt() 6 | 7 | class NumberFont(context: Context, var centered: Boolean = false) { 8 | private val images = Array(10) { 9 | context.assets.getAtlas().findRegion(it.toString()) 10 | } 11 | private var length = 0 12 | 13 | var num = 0 14 | set(value) { 15 | val s = value.toString() 16 | length = 0 17 | for (c in s) { 18 | val n = c.intValue() 19 | length += images[n].regionWidth 20 | } 21 | field = value 22 | } 23 | 24 | fun render(sb: SpriteBatch, x: Float, y: Float, num: Int = this.num) { 25 | val s = num.toString() 26 | var offset = 0 27 | if (centered) { 28 | for (c in s) { 29 | val n = c.intValue() 30 | sb.draw(images[n], x + offset - length / 2, y) 31 | offset += images[n].regionWidth 32 | } 33 | } else { 34 | for (c in s) { 35 | val n = c.intValue() 36 | sb.draw(images[n], x + offset, y) 37 | offset += images[n].regionWidth 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/ScoreHandler.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | import com.badlogic.gdx.Gdx 4 | import com.distraction.sandbox.tilemap.TileMapData 5 | 6 | class ScoreHandler { 7 | val scores = IntArray(TileMapData.levelData.size) { 0 } 8 | 9 | fun getPreferences() = Gdx.app.getPreferences("scores") 10 | 11 | fun init() { 12 | with(getPreferences()) { 13 | for (i in 0 until scores.size) { 14 | if (!contains(i.toString())) { 15 | putInteger(i.toString(), 0) 16 | } 17 | } 18 | flush() 19 | } 20 | } 21 | 22 | fun load() { 23 | with(getPreferences()) { 24 | for (i in 0 until scores.size) { 25 | if (!contains(i.toString())) { 26 | init() 27 | } 28 | scores[i] = getInteger(i.toString(), 0) 29 | } 30 | } 31 | } 32 | 33 | fun saveScore(index: Int, score: Int) { 34 | with(getPreferences()) { 35 | putInteger(index.toString(), score) 36 | scores[index] = score 37 | flush() 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/Utils.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox 2 | 3 | import com.badlogic.gdx.Gdx 4 | import com.badlogic.gdx.assets.AssetManager 5 | import com.badlogic.gdx.graphics.GL20 6 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 7 | import com.badlogic.gdx.graphics.g2d.TextureAtlas 8 | import com.badlogic.gdx.graphics.g2d.TextureRegion 9 | import com.badlogic.gdx.math.Rectangle 10 | import com.badlogic.gdx.math.Vector3 11 | 12 | class Utils { 13 | companion object { 14 | fun abs(f: Float) = if (f < 0) f * -1 else f 15 | fun dist(x1: Float, y1: Float, x2: Float, y2: Float) = Math.sqrt(1.0 * (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)).toFloat() 16 | fun max(f1: Float, f2: Float) = if (f2 > f1) f2 else f1 17 | } 18 | } 19 | 20 | fun AssetManager.getAtlas(str: String = "sandboxpack.atlas") = get(str, TextureAtlas::class.java) 21 | 22 | fun log(str: String) = Gdx.app.log("tag", str) 23 | 24 | inline fun SpriteBatch.use(action: () -> Unit) { 25 | begin() 26 | action() 27 | end() 28 | } 29 | 30 | fun SpriteBatch.drawRotated(region: TextureRegion, x: Float, y: Float, rotation: Float) { 31 | draw(region, x, y, region.regionWidth / 2f, region.regionHeight / 2f, 1f * region.regionWidth, 1f * region.regionHeight, 1f, 1f, rotation) 32 | } 33 | 34 | fun SpriteBatch.drawButton(button: Button, hflip: Boolean = false) { 35 | if (hflip) { 36 | draw(button.image, button.rect.x + button.image.regionWidth, button.rect.y, -button.rect.width, button.rect.height) 37 | } else { 38 | draw(button.image, button.rect.x, button.rect.y, button.rect.width, button.rect.height) 39 | } 40 | } 41 | 42 | fun clearScreen(r: Int = 255, g: Int = 255, b: Int = 255, a: Int = 255) { 43 | Gdx.gl.glClearColor(r / 255f, g / 255f, b / 255f, a / 255f) 44 | Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) 45 | } 46 | 47 | fun Vector3.lerp(x: Float, y: Float, z: Float, amount: Float): Vector3 { 48 | this.x += amount * (x - this.x) 49 | this.y += amount * (y - this.y) 50 | this.z += amount * (z - this.z) 51 | return this 52 | } 53 | 54 | fun Rectangle.contains(v: Vector3) = contains(v.x, v.y) -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/states/GSM.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.states 2 | 3 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 4 | import java.util.* 5 | 6 | class GSM { 7 | 8 | private var states = Stack() 9 | var depth = 1 10 | 11 | fun push(state: GameState) { 12 | states.push(state) 13 | } 14 | 15 | fun pop(): GameState { 16 | return states.pop() 17 | } 18 | 19 | fun replace(state: GameState): GameState { 20 | val s = states.pop() 21 | states.push(state) 22 | return s 23 | } 24 | 25 | fun update(dt: Float) { 26 | for (i in states.size - depth until states.size) { 27 | states[i].update(dt) 28 | } 29 | } 30 | 31 | fun render(sb: SpriteBatch) { 32 | for (i in states.size - depth until states.size) { 33 | states[i].render(sb) 34 | } 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/states/GameState.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.states 2 | 3 | import com.badlogic.gdx.graphics.OrthographicCamera 4 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 5 | import com.badlogic.gdx.math.Vector3 6 | import com.distraction.sandbox.Constants 7 | import com.distraction.sandbox.Context 8 | 9 | abstract class GameState(protected val context: Context) { 10 | var ignoreInput = false 11 | val touchPoint = Vector3() 12 | protected val camera = OrthographicCamera().apply { 13 | setToOrtho(false, Constants.WIDTH, Constants.HEIGHT) 14 | } 15 | 16 | abstract fun update(dt: Float) 17 | abstract fun render(sb: SpriteBatch) 18 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/states/LevelFinishState.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.states 2 | 3 | import com.badlogic.gdx.Gdx 4 | import com.badlogic.gdx.graphics.Color 5 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 6 | import com.badlogic.gdx.math.Vector2 7 | import com.distraction.sandbox.* 8 | import com.distraction.sandbox.tilemap.TileMapData 9 | 10 | class LevelFinishState(context: Context, val level: Int, val moves: Int, val best: Int) : GameState(context) { 11 | private val dot = context.assets.getAtlas().findRegion("dot") 12 | private val dimColor = Color(0f, 0f, 0f, 0f) 13 | 14 | private val completeImage = Button(context.assets.getAtlas().findRegion("complete"), 0f, 80f, centered = true) 15 | private val bestLabel = NumberLabel(context, context.assets.getAtlas().findRegion("best"), Vector2(Constants.WIDTH / 2 - 20f, Constants.HEIGHT / 2f), best) 16 | private val movesLabel = NumberLabel(context, context.assets.getAtlas().findRegion("moves"), Vector2(Constants.WIDTH / 2 - 20f, Constants.HEIGHT / 2f - 10), moves) 17 | private val newRecordImage = Button(context.assets.getAtlas().findRegion("newrecord"), 0f, 40f, centered = true) 18 | 19 | private val restartButton = Button(context.assets.getAtlas().findRegion("restart"), 5f, 98f) 20 | private val backButton = Button(context.assets.getAtlas().findRegion("back"),5f, 115f) 21 | private val nextButton = Button(context.assets.getAtlas().findRegion("next"), 0f, 15f, centered = true) 22 | 23 | init { 24 | context.gsm.depth++ 25 | } 26 | 27 | override fun update(dt: Float) { 28 | if (!ignoreInput) { 29 | if (Gdx.input.justTouched()) { 30 | touchPoint.set(1f * Gdx.input.x, 1f * Gdx.input.y, 0f) 31 | camera.unproject(touchPoint) 32 | if (level < TileMapData.levelData.size && nextButton.rect.contains(touchPoint)) { 33 | ignoreInput = true 34 | context.gsm.push(TransitionState(context, PlayState(context, level + 1), 2)) 35 | } else if (backButton.rect.contains(touchPoint)) { 36 | ignoreInput = true 37 | context.gsm.push(TransitionState(context, LevelSelectState(context, (level - 1) / LevelSelectState.LEVELS_PER_PAGE), 2)) 38 | } else if (restartButton.rect.contains(touchPoint)) { 39 | ignoreInput = true 40 | context.gsm.push(TransitionState(context, PlayState(context, level), 2)) 41 | } 42 | } 43 | } 44 | if (dimColor.a < 0.7f) { 45 | dimColor.a += 2f * dt 46 | if (dimColor.a > 0.7f) { 47 | dimColor.a = 0.7f 48 | } 49 | } 50 | } 51 | 52 | override fun render(sb: SpriteBatch) { 53 | sb.use { 54 | val c = sb.color 55 | sb.color = dimColor 56 | sb.draw(dot, 0f, 0f, Constants.WIDTH, Constants.HEIGHT) 57 | sb.color = c 58 | 59 | sb.drawButton(completeImage) 60 | bestLabel.render(sb) 61 | movesLabel.render(sb) 62 | if (best == 0 || moves < best) { 63 | sb.drawButton(newRecordImage) 64 | } 65 | 66 | sb.drawButton(restartButton) 67 | sb.drawButton(backButton) 68 | if (level < TileMapData.levelData.size) sb.drawButton(nextButton) 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/states/LevelSelectState.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.states 2 | 3 | import com.badlogic.gdx.Gdx 4 | import com.badlogic.gdx.graphics.Color 5 | import com.badlogic.gdx.graphics.OrthographicCamera 6 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 7 | import com.badlogic.gdx.graphics.g2d.TextureRegion 8 | import com.badlogic.gdx.math.MathUtils 9 | import com.badlogic.gdx.math.Rectangle 10 | import com.distraction.sandbox.* 11 | import com.distraction.sandbox.tilemap.TileMapData 12 | 13 | class LevelSelectState(context: Context, private var page: Int = 0) : GameState(context) { 14 | companion object { 15 | const val LEVELS_PER_PAGE = 18 16 | } 17 | 18 | private val levelIcon = context.assets.getAtlas().findRegion("levelicon") 19 | private val levelCheck = context.assets.getAtlas().findRegion("levelcheck") 20 | private val colSize = 6 21 | private val maxPages = MathUtils.ceil(TileMapData.levelData.size / 18f) 22 | 23 | private val levels = Array(TileMapData.levelData.size) { 24 | val page = it / 18 25 | val row = (it % 18) / colSize 26 | val col = it % colSize 27 | val x = col * (levelIcon.regionWidth + 5f) + 38 + Constants.WIDTH * page 28 | val y = Constants.HEIGHT - row * (levelIcon.regionHeight + 5f) - 50 29 | Button(context.assets.getAtlas().findRegion("levelicon"), x, y) 30 | } 31 | 32 | private val numberFont = NumberFont(context, true) 33 | private val levelSelectImage = context.assets.getAtlas().findRegion("levelselect") 34 | private val backButton = Button(context.assets.getAtlas().findRegion("back"), y = 7f, centered = true) 35 | private val disableColor = Color(0.3f, 0.3f, 0.3f, 1f) 36 | private val staticCam = OrthographicCamera().apply { 37 | setToOrtho(false, Constants.WIDTH, Constants.HEIGHT) 38 | } 39 | 40 | private val leftButton = Button(context.assets.getAtlas().findRegion("levelselectarrow"), 41 | Rectangle(10f, Constants.HEIGHT / 2 - 5f, 10f, 11f)) 42 | private val rightButton = Button(context.assets.getAtlas().findRegion("levelselectarrow"), 43 | Rectangle(Constants.WIDTH - 20f, Constants.HEIGHT / 2 - 5f, 10f, 11f)) 44 | 45 | init { 46 | camera.position.set(Constants.WIDTH * page + Constants.WIDTH / 2, Constants.HEIGHT / 2, 0f) 47 | camera.update() 48 | } 49 | 50 | override fun update(dt: Float) { 51 | if (!ignoreInput) { 52 | if (Gdx.input.justTouched()) { 53 | touchPoint.set(1f * Gdx.input.x, 1f * Gdx.input.y, 0f) 54 | camera.unproject(touchPoint) 55 | levels.forEachIndexed { i, it -> 56 | if (it.rect.contains(touchPoint) && i < TileMapData.levelData.size) { 57 | ignoreInput = true 58 | context.gsm.push(TransitionState(context, PlayState(context, i + 1))) 59 | return@forEachIndexed 60 | } 61 | } 62 | 63 | touchPoint.set(1f * Gdx.input.x, 1f * Gdx.input.y, 0f) 64 | staticCam.unproject(touchPoint) 65 | if (backButton.rect.contains(touchPoint)) { 66 | ignoreInput = true 67 | context.gsm.push(TransitionState(context, TitleState(context))) 68 | } 69 | if (leftButton.rect.contains(touchPoint)) { 70 | if (page > 0) { 71 | page-- 72 | } 73 | } else if (rightButton.rect.contains(touchPoint)) { 74 | if (page < maxPages - 1) { 75 | page++ 76 | } 77 | } 78 | } 79 | } 80 | camera.position.set(camera.position.lerp(Constants.WIDTH * page + Constants.WIDTH / 2, Constants.HEIGHT / 2, 0f, 0.3f)) 81 | camera.update() 82 | } 83 | 84 | override fun render(sb: SpriteBatch) { 85 | clearScreen(76, 176, 219) 86 | sb.use { 87 | sb.projectionMatrix = staticCam.combined 88 | sb.draw(levelSelectImage, (Constants.WIDTH - levelSelectImage.regionWidth) / 2, Constants.HEIGHT - levelSelectImage.regionHeight - 8) 89 | sb.draw(backButton.image, backButton.rect.x, backButton.rect.y) 90 | 91 | if (page > 0) sb.drawButton(leftButton, true) 92 | if (page < maxPages - 1) sb.drawButton(rightButton) 93 | 94 | sb.projectionMatrix = camera.combined 95 | levels.forEachIndexed { i, it -> 96 | val c = sb.color 97 | val best = context.scoreHandler.scores[i] 98 | if (best == 0) { 99 | sb.color = disableColor 100 | } 101 | sb.draw(it.image, it.rect.x, it.rect.y) 102 | numberFont.num = i + 1 103 | numberFont.render(sb, it.rect.x + levelIcon.regionWidth / 2, it.rect.y + (levelIcon.regionHeight - 6) / 2) 104 | sb.color = c 105 | if (best > 0 && best <= TileMapData.levelData[i].goal) { 106 | sb.draw(levelCheck, it.rect.x + (it.rect.width - levelCheck.regionWidth) / 2, it.rect.y - 2) 107 | } 108 | } 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/states/PlayState.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.states 2 | 3 | import com.badlogic.gdx.Gdx 4 | import com.badlogic.gdx.Input 5 | import com.badlogic.gdx.graphics.OrthographicCamera 6 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 7 | import com.badlogic.gdx.math.Vector2 8 | import com.badlogic.gdx.math.Vector3 9 | import com.distraction.sandbox.* 10 | import com.distraction.sandbox.tilemap.TileMap 11 | import com.distraction.sandbox.tilemap.TileMapData 12 | import com.distraction.sandbox.tilemap.tileobjects.Player 13 | 14 | interface MoveListener { 15 | fun onMoved() 16 | fun onToggled() 17 | fun onIllegal() 18 | } 19 | 20 | class PlayState(context: Context, private val level: Int) : GameState(context), MoveListener, ButtonListener { 21 | 22 | private val tileMap = TileMap(context, TileMapData.levelData[level - 1]) 23 | private val player = Player(context, tileMap, this) 24 | private val bg = Background(context) 25 | private val bgCam = OrthographicCamera().apply { 26 | setToOrtho(false, Constants.WIDTH, Constants.HEIGHT) 27 | } 28 | private val tp = Vector3() 29 | 30 | private val hud = HUD(context, this) 31 | private val cameraOffset = Vector2(0f, 0f) 32 | 33 | init { 34 | camera.position.set(-100f, player.pp.y + cameraOffset.y, 0f) 35 | camera.update() 36 | 37 | hud.setGoal(TileMapData.levelData[level - 1].goal) 38 | hud.setBest(context.scoreHandler.scores[level - 1]) 39 | } 40 | 41 | override fun onMoved() { 42 | if (!tileMap.isFinished()) { 43 | hud.incrementMoves() 44 | } 45 | } 46 | 47 | override fun onToggled() { 48 | if (tileMap.isFinished()) { 49 | ignoreInput = true 50 | 51 | if (hud.getBest() == 0 || hud.getMoves() < hud.getBest()) { 52 | context.scoreHandler.saveScore(level - 1, hud.getMoves()) 53 | } 54 | 55 | // if (level == TileMapData.levelData.size) { 56 | // context.gsm.push(TransitionState(context, TitleState(context))) 57 | // } else { 58 | // context.gsm.push(TransitionState(context, PlayState(context, level + 1))) 59 | // } 60 | context.gsm.push(LevelFinishState(context, level, hud.getMoves(), hud.getBest())) 61 | } 62 | } 63 | 64 | override fun onIllegal() { 65 | if (!tileMap.isFinished() && !ignoreInput) { 66 | ignoreInput = true 67 | context.gsm.push(TransitionState(context, PlayState(context, level))) 68 | } 69 | } 70 | 71 | fun back() { 72 | if (!ignoreInput) { 73 | ignoreInput = true 74 | context.gsm.push(TransitionState(context, LevelSelectState(context, (level - 1) / LevelSelectState.LEVELS_PER_PAGE))) 75 | } 76 | } 77 | 78 | override fun onButtonPressed(type: ButtonListener.ButtonType) { 79 | when (type) { 80 | ButtonListener.ButtonType.UP -> player.moveTile(-1, 0) 81 | ButtonListener.ButtonType.LEFT -> player.moveTile(0, -1) 82 | ButtonListener.ButtonType.DOWN -> player.moveTile(1, 0) 83 | ButtonListener.ButtonType.RIGHT -> player.moveTile(0, 1) 84 | ButtonListener.ButtonType.RESTART -> onIllegal() 85 | ButtonListener.ButtonType.BACK -> back() 86 | } 87 | } 88 | 89 | override fun update(dt: Float) { 90 | if (!ignoreInput) { 91 | hud.update(dt) 92 | when { 93 | Gdx.input.isKeyPressed(Input.Keys.RIGHT) -> player.moveTile(0, 1) 94 | Gdx.input.isKeyPressed(Input.Keys.LEFT) -> player.moveTile(0, -1) 95 | Gdx.input.isKeyPressed(Input.Keys.UP) -> player.moveTile(-1, 0) 96 | Gdx.input.isKeyPressed(Input.Keys.DOWN) -> player.moveTile(1, 0) 97 | Gdx.input.isKeyJustPressed(Input.Keys.R) -> onIllegal() 98 | } 99 | } 100 | 101 | player.update(dt) 102 | 103 | if (player.teleporting) { 104 | tileMap.toIsometric(player.pdest.x, player.pdest.y, tp) 105 | camera.position.set(camera.position.lerp(tp.x + cameraOffset.x, tp.y + cameraOffset.y, 0f, 0.1f)) 106 | } else { 107 | camera.position.set(camera.position.lerp(player.pp.x + cameraOffset.x, player.pp.y + cameraOffset.y, 0f, 0.1f)) 108 | } 109 | camera.update() 110 | 111 | bg.update(dt) 112 | tileMap.update(dt) 113 | } 114 | 115 | override fun render(sb: SpriteBatch) { 116 | sb.use { 117 | sb.projectionMatrix = bgCam.combined 118 | bg.render(sb) 119 | 120 | sb.projectionMatrix = camera.combined 121 | tileMap.render(sb) 122 | player.render(sb) 123 | tileMap.renderOther(sb) 124 | 125 | hud.render(sb) 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/states/TitleState.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.states 2 | 3 | import com.badlogic.gdx.Gdx 4 | import com.badlogic.gdx.Input 5 | import com.badlogic.gdx.graphics.OrthographicCamera 6 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 7 | import com.distraction.sandbox.* 8 | import com.distraction.sandbox.tilemap.TileMap 9 | import com.distraction.sandbox.tilemap.TileMapDataModel 10 | import com.distraction.sandbox.tilemap.tileobjects.Player 11 | 12 | class TitleState(context: Context) : GameState(context) { 13 | private val tileMap = TileMap(context, TileMapDataModel(3, 3, IntArray(9) { 1 }, goal = 0)) 14 | private val player = Player(context, tileMap, null) 15 | private val title = context.assets.getAtlas().findRegion("title") 16 | private val hudCam = OrthographicCamera().apply { 17 | setToOrtho(false, Constants.WIDTH, Constants.HEIGHT) 18 | } 19 | 20 | init { 21 | hudCam.position.set(Constants.WIDTH / 2f, -100f, 0f) 22 | hudCam.update() 23 | camera.position.set(0f, 100f, 0f) 24 | camera.update() 25 | } 26 | 27 | override fun update(dt: Float) { 28 | if (!ignoreInput) { 29 | if (Gdx.input.justTouched()) { 30 | ignoreInput = true 31 | context.gsm.push(TransitionState(context, LevelSelectState(context))) 32 | } 33 | if (Gdx.input.isKeyJustPressed(Input.Keys.ENTER)) { 34 | ignoreInput = true 35 | context.gsm.push(TransitionState(context, LevelSelectState(context))) 36 | } 37 | } 38 | 39 | player.update(dt) 40 | 41 | hudCam.position.set(hudCam.position.lerp(Constants.WIDTH / 2f, Constants.HEIGHT / 2f, 0f, 0.1f)) 42 | hudCam.update() 43 | camera.position.set(camera.position.lerp(player.pp.x, player.pp.y + Constants.HEIGHT / 4, player.pp.z, 0.03f)) 44 | camera.update() 45 | } 46 | 47 | override fun render(sb: SpriteBatch) { 48 | clearScreen(76, 176, 219) 49 | sb.use { 50 | sb.projectionMatrix = hudCam.combined 51 | sb.draw(title, (Constants.WIDTH - title.regionWidth) / 2f, 60f) 52 | 53 | sb.projectionMatrix = camera.combined 54 | tileMap.render(sb) 55 | player.render(sb) 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/states/TransitionState.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.states 2 | 3 | import com.badlogic.gdx.graphics.Color 4 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 5 | import com.distraction.sandbox.Constants 6 | import com.distraction.sandbox.Context 7 | import com.distraction.sandbox.getAtlas 8 | import com.distraction.sandbox.use 9 | 10 | class TransitionState(context: Context, val nextState: GameState, val numPop: Int = 1) : GameState(context) { 11 | 12 | private val dot = context.assets.getAtlas().findRegion("dot") 13 | private val duration = 0.5f 14 | private var time = 0f 15 | private var next = false 16 | 17 | init { 18 | context.gsm.depth++ 19 | } 20 | 21 | override fun update(dt: Float) { 22 | time += dt 23 | if (!next && time > duration / 2) { 24 | next = true 25 | nextState.ignoreInput = true 26 | for (i in 0 until numPop) { 27 | context.gsm.pop() 28 | } 29 | context.gsm.depth -= numPop - 1 30 | context.gsm.replace(nextState) 31 | context.gsm.push(this) 32 | } 33 | if (time > duration) { 34 | context.gsm.depth-- 35 | context.gsm.pop() 36 | nextState.ignoreInput = false 37 | } 38 | } 39 | 40 | override fun render(sb: SpriteBatch) { 41 | val interp = time / duration 42 | val perc = if (interp < 0.5f) interp * 2f else 1f - (time - duration / 2) / duration * 2 43 | val c = sb.color 44 | sb.color = Color.BLACK 45 | sb.projectionMatrix = camera.combined 46 | sb.use { 47 | sb.draw(dot, 0f, Constants.HEIGHT, 1f * Constants.WIDTH, -perc * Constants.HEIGHT / 2) 48 | sb.draw(dot, 0f, 0f, 1f * Constants.WIDTH, perc * Constants.HEIGHT / 2) 49 | } 50 | sb.color = c 51 | } 52 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/tilemap/TileMap.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.tilemap 2 | 3 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 4 | import com.badlogic.gdx.math.Vector3 5 | import com.distraction.sandbox.Context 6 | import com.distraction.sandbox.getAtlas 7 | import com.distraction.sandbox.tilemap.TileObjectType.* 8 | import com.distraction.sandbox.tilemap.tileobjects.Arrow 9 | import com.distraction.sandbox.tilemap.tileobjects.Player 10 | import com.distraction.sandbox.tilemap.tileobjects.SuperJump 11 | import com.distraction.sandbox.tilemap.tileobjects.Teleport 12 | 13 | class Tile(val context: Context, val value: Int, var active: Boolean = false) { 14 | val objects = arrayListOf() 15 | fun toggleActive() { 16 | active = !active 17 | } 18 | 19 | fun getImage() = if (active) context.assets.getAtlas().findRegion("tilea") else context.assets.getAtlas().findRegion("tile") 20 | } 21 | 22 | class TileMap(private val context: Context, val levelData: TileMapDataModel) { 23 | 24 | companion object { 25 | const val TILE_WIDTH = 32f 26 | const val TILE_IWIDTH = 16f 27 | const val TILE_IHEIGHT = 8f 28 | } 29 | 30 | private val p = Vector3() 31 | private val grid = Array(levelData.grid.size) { 32 | Tile(context, levelData.grid[it], if (levelData.grid[it] == 2) true else false) 33 | } 34 | val otherObjects = arrayListOf() 35 | 36 | init { 37 | levelData.objs.forEach { 38 | val tile = getTile(it.row, it.col) 39 | when (it.type) { 40 | ARROW_RIGHT -> tile.objects.add(Arrow(context, this, it.row, it.col, Player.Direction.RIGHT)) 41 | ARROW_LEFT -> tile.objects.add(Arrow(context, this, it.row, it.col, Player.Direction.LEFT)) 42 | ARROW_DOWN -> tile.objects.add(Arrow(context, this, it.row, it.col, Player.Direction.DOWN)) 43 | ARROW_UP -> tile.objects.add(Arrow(context, this, it.row, it.col, Player.Direction.UP)) 44 | SUPER_JUMP -> tile.objects.add(SuperJump(context, this, it.row, it.col)) 45 | TELEPORT -> { 46 | if (it is TeleportDataModel) { 47 | val teleport = Teleport(context, this, it.row, it.col, it.row2, it.col2) 48 | tile.objects.add(teleport) 49 | val tile2 = getTile(teleport.row2, teleport.col2) 50 | tile2.objects.add(teleport) 51 | } 52 | } 53 | } 54 | 55 | } 56 | } 57 | 58 | fun update(dt: Float) { 59 | for (row in 0 until levelData.numRows) { 60 | for (col in 0 until levelData.numCols) { 61 | val tile = getTile(row, col) 62 | tile.objects.forEach { 63 | it.update(dt) 64 | } 65 | } 66 | } 67 | otherObjects.forEach { 68 | it.update(dt) 69 | } 70 | otherObjects.removeAll { 71 | it.remove 72 | } 73 | } 74 | 75 | fun render(sb: SpriteBatch) { 76 | for (row in 0 until levelData.numRows) { 77 | for (col in 0 until levelData.numCols) { 78 | val tile = getTile(row, col) 79 | if (tile.value != 0) { 80 | toIsometric(col * TileMap.TILE_WIDTH, row * TileMap.TILE_WIDTH, p) 81 | sb.draw(tile.getImage(), p.x - TILE_WIDTH / 2, p.y - TILE_IHEIGHT * 2) 82 | } 83 | tile.objects.forEach { 84 | it.render(sb) 85 | } 86 | } 87 | } 88 | } 89 | 90 | fun renderOther(sb: SpriteBatch) { 91 | otherObjects.forEach { 92 | it.render(sb) 93 | } 94 | } 95 | 96 | fun toPosition(row: Int, col: Int, p: Vector3) { 97 | p.x = col * TILE_WIDTH 98 | p.y = row * TILE_WIDTH 99 | } 100 | 101 | fun toPosition(tile: Int) = tile * TILE_WIDTH 102 | 103 | fun toIsometric(x: Float, y: Float, p: Vector3) { 104 | val xo = x / TileMap.TILE_WIDTH 105 | val yo = y / TileMap.TILE_WIDTH 106 | p.x = (xo - yo) * TileMap.TILE_IWIDTH 107 | p.y = (-xo - yo) * TileMap.TILE_IHEIGHT 108 | } 109 | 110 | fun isValidTile(row: Int, col: Int): Boolean { 111 | if (row < 0 || row >= levelData.numRows || col < 0 || col >= levelData.numCols) return false 112 | return getTile(row, col).value != 0 113 | } 114 | 115 | fun contains(row: Int, col: Int) = row >= 0 && row < levelData.numRows && col >= 0 && col <= levelData.numCols && getTile(row, col).value != 0 116 | 117 | fun getTile(row: Int, col: Int) = grid[row * levelData.numCols + col] 118 | 119 | fun isFinished(): Boolean { 120 | for (row in 0 until levelData.numRows) { 121 | for (col in 0 until levelData.numCols) { 122 | val tile = getTile(row, col) 123 | if (tile.value != 0 && !tile.active) { 124 | return false 125 | } 126 | } 127 | } 128 | return true 129 | } 130 | 131 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/tilemap/TileMapData.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.tilemap 2 | 3 | class TileMapDataModel(val numRows: Int, val numCols: Int, val grid: IntArray, val objs: Array = arrayOf(), val startRow: Int = 0, val startCol: Int = 0, val goal: Int) 4 | open class TileObjectDataModel(val type: TileObjectType, val row: Int, val col: Int) 5 | class TeleportDataModel(type: TileObjectType, row: Int, col: Int, val row2: Int, val col2: Int) : TileObjectDataModel(type, row, col) 6 | 7 | enum class TileObjectType { 8 | ARROW_RIGHT, 9 | ARROW_LEFT, 10 | ARROW_DOWN, 11 | ARROW_UP, 12 | SUPER_JUMP, 13 | TELEPORT 14 | } 15 | 16 | class TileMapData { 17 | companion object { 18 | val levelData = arrayOf( 19 | 20 | ////////////// BASIC LEVELS 21 | 22 | TileMapDataModel(4, 4, intArrayOf( 23 | 1, 1, 1, 1, 24 | 1, 0, 0, 1, 25 | 1, 0, 0, 1, 26 | 1, 1, 1, 1 27 | ), goal = 11), 28 | TileMapDataModel(3, 3, intArrayOf( 29 | 1, 1, 1, 30 | 1, 1, 1, 31 | 1, 1, 1 32 | ), startRow = 1, startCol = 1, goal = 8), 33 | TileMapDataModel(3, 3, intArrayOf( 34 | 1, 1, 1, 35 | 1, 1, 1, 36 | 0, 1, 0 37 | ), goal = 8), 38 | TileMapDataModel(5, 3, intArrayOf( 39 | 1, 1, 1, 40 | 1, 0, 1, 41 | 1, 1, 1, 42 | 1, 0, 1, 43 | 1, 1, 1 44 | ), startRow = 0, startCol = 1, goal = 16), 45 | TileMapDataModel(4, 4, intArrayOf( 46 | 1, 1, 1, 1, 47 | 1, 0, 0, 1, 48 | 1, 1, 1, 1, 49 | 1, 1, 1, 1 50 | ), startRow = 2, startCol = 1, goal = 13), 51 | TileMapDataModel(6, 6, intArrayOf( 52 | 1, 1, 1, 1, 1, 1, 53 | 1, 0, 1, 1, 0, 1, 54 | 1, 1, 1, 1, 1, 1, 55 | 1, 1, 1, 1, 1, 1, 56 | 1, 0, 1, 1, 0, 1, 57 | 1, 1, 1, 1, 1, 1 58 | ), goal = 31), 59 | TileMapDataModel(4, 4, intArrayOf( 60 | 0, 0, 1, 1, 61 | 0, 1, 1, 1, 62 | 1, 1, 1, 0, 63 | 1, 1, 0, 0 64 | ), startRow = 1, startCol = 2, goal = 11), 65 | 66 | ////////////////// ARROW LEVELS 67 | 68 | TileMapDataModel(3, 5, intArrayOf( 69 | 1, 1, 1, 1, 1, 70 | 1, 0, 0, 0, 1, 71 | 1, 1, 1, 1, 1 72 | ), arrayOf( 73 | arrowRight(0, 1), 74 | arrowRight(0, 2), 75 | arrowRight(0, 3), 76 | arrowLeft(2, 1), 77 | arrowLeft(2, 2), 78 | arrowLeft(2, 3)), 79 | goal = 11), 80 | TileMapDataModel(3, 4, intArrayOf( 81 | 1, 1, 1, 1, 82 | 1, 1, 1, 1, 83 | 1, 1, 1, 1 84 | ), arrayOf( 85 | arrowLeft(1, 1), 86 | arrowRight(1, 2)), 87 | goal = 11), 88 | TileMapDataModel(4, 3, intArrayOf( 89 | 1, 1, 1, 90 | 1, 1, 1, 91 | 1, 1, 1, 92 | 1, 1, 1 93 | ), arrayOf( 94 | arrowUp(1, 0), arrowUp(2, 0), arrowUp(3, 0), 95 | arrowDown(0, 2), arrowDown(1, 2), arrowDown(2, 2)), 96 | 1, 1, 97 | goal = 11), 98 | TileMapDataModel(3, 4, intArrayOf( 99 | 1, 1, 1, 1, 100 | 1, 1, 1, 1, 101 | 1, 1, 1, 1 102 | ), arrayOf( 103 | arrowRight(0, 1), 104 | arrowRight(0, 2), 105 | arrowLeft(2, 1), 106 | arrowLeft(2, 2)), 107 | 1, 0, 15), 108 | TileMapDataModel(4, 4, intArrayOf( 109 | 1, 1, 1, 1, 110 | 1, 1, 1, 1, 111 | 1, 1, 1, 1, 112 | 1, 1, 1, 1 113 | ), arrayOf( 114 | arrowLeft(1, 1), 115 | arrowUp(1, 2), 116 | arrowRight(2, 2), 117 | arrowDown(2, 1)), 118 | goal = 23), 119 | 120 | //////////////// SUPER JUMP LEVELS 121 | 122 | TileMapDataModel(5, 5, intArrayOf( 123 | 1, 1, 1, 0, 0, 124 | 0, 0, 1, 0, 0, 125 | 0, 0, 0, 0, 0, 126 | 0, 0, 1, 0, 0, 127 | 0, 0, 1, 1, 1 128 | ), arrayOf( 129 | superJump(1, 2)), 130 | goal = 7), 131 | TileMapDataModel(2, 4, intArrayOf( 132 | 1, 1, 0, 1, 133 | 1, 0, 1, 1 134 | ), arrayOf( 135 | superJump(0, 1), 136 | superJump(1, 2)), 137 | goal = 5), 138 | TileMapDataModel(4, 3, intArrayOf( 139 | 1, 1, 1, 140 | 1, 1, 1, 141 | 1, 1, 1, 142 | 1, 1, 1 143 | ), arrayOf( 144 | superJump(1, 1), 145 | superJump(2, 1)), 146 | goal = 17), 147 | TileMapDataModel(5, 5, intArrayOf( 148 | 1, 1, 0, 1, 1, 149 | 1, 1, 1, 1, 1, 150 | 0, 0, 1, 0, 0, 151 | 1, 1, 1, 1, 1, 152 | 1, 1, 0, 1, 1 153 | ), arrayOf( 154 | superJump(1, 4), 155 | superJump(3, 0)), 156 | goal = 22), 157 | TileMapDataModel(4, 4, intArrayOf( 158 | 1, 1, 1, 1, 159 | 1, 1, 1, 1, 160 | 1, 1, 1, 1, 161 | 1, 1, 1, 1 162 | ), arrayOf( 163 | superJump(1, 1), 164 | superJump(1, 2), 165 | superJump(2, 1), 166 | superJump(2, 2)), 167 | goal = 15), 168 | 169 | ///////////// SUPER JUMP + ARROW LEVELS 170 | 171 | TileMapDataModel(5, 5, intArrayOf( 172 | 0, 0, 1, 1, 1, 173 | 0, 0, 1, 0, 1, 174 | 1, 1, 1, 1, 1, 175 | 1, 0, 1, 0, 0, 176 | 1, 1, 1, 0, 0 177 | ), arrayOf( 178 | arrowRight(2, 1), arrowRight(2, 2), arrowRight(2, 3), arrowUp(2, 4), 179 | arrowUp(1, 4), arrowLeft(0, 4), arrowLeft(0, 3), arrowDown(0, 2), arrowDown(1, 2), 180 | arrowDown(3, 2), arrowLeft(4, 2), arrowLeft(4, 1), arrowUp(4, 0), arrowUp(3, 0), 181 | superJump(1, 2)), 182 | 2, 0, 14), 183 | TileMapDataModel(5, 5, intArrayOf( 184 | 1, 1, 1, 0, 0, 185 | 1, 0, 1, 0, 0, 186 | 1, 1, 1, 1, 1, 187 | 0, 0, 1, 0, 1, 188 | 0, 0, 1, 1, 1 189 | ), arrayOf( 190 | arrowUp(3, 2), 191 | arrowDown(1, 2)), 192 | goal = 20), 193 | TileMapDataModel(4, 4, intArrayOf( 194 | 1, 1, 1, 0, 195 | 1, 1, 1, 1, 196 | 1, 1, 1, 1, 197 | 0, 1, 1, 1 198 | ), arrayOf( 199 | arrowDown(0, 1), arrowUp(3, 2), 200 | superJump(1, 1), superJump(2, 2)), 201 | goal = 15), 202 | TileMapDataModel(3, 5, intArrayOf( 203 | 1, 1, 1, 1, 1, 204 | 1, 0, 1, 1, 1, 205 | 1, 1, 1, 1, 1 206 | ), arrayOf( 207 | arrowLeft(2, 2), 208 | arrowDown(0, 0)), 209 | 1, 4, 17), 210 | TileMapDataModel(5, 5, intArrayOf( 211 | 1, 1, 0, 1, 1, 212 | 1, 1, 1, 1, 1, 213 | 0, 1, 1, 1, 0, 214 | 1, 1, 1, 1, 1, 215 | 1, 1, 0, 1, 1 216 | ), arrayOf( 217 | arrowLeft(0, 1), arrowDown(0, 0), arrowRight(1, 0), 218 | arrowDown(3, 0), arrowRight(4, 0), arrowUp(4, 1), 219 | arrowRight(4, 3), arrowUp(4, 4), arrowLeft(3, 4), 220 | arrowUp(1, 4), arrowLeft(0, 4), arrowDown(0, 3)), 221 | 2, 2, 32), 222 | TileMapDataModel(4, 4, intArrayOf( 223 | 1, 1, 1, 1, 224 | 1, 1, 0, 1, 225 | 1, 0, 1, 1, 226 | 1, 1, 1, 1 227 | ), arrayOf( 228 | superJump(1, 1), 229 | superJump(2, 2)), 230 | goal = 17), 231 | 232 | //////////////// TELEPORT LEVELS 233 | 234 | TileMapDataModel(5, 5, intArrayOf( 235 | 0, 0, 1, 1, 1, 236 | 0, 0, 0, 0, 1, 237 | 1, 0, 0, 0, 1, 238 | 1, 0, 0, 0, 0, 239 | 1, 1, 1, 0, 0 240 | ), arrayOf( 241 | teleport(4, 2, 0, 2)), 242 | 2, 0, 9), 243 | TileMapDataModel(5, 3, intArrayOf( 244 | 0, 1, 0, 245 | 1, 1, 1, 246 | 1, 1, 1, 247 | 1, 1, 1, 248 | 0, 1, 0 249 | ), arrayOf( 250 | teleport(0, 1, 4, 1)), 251 | 1, 0, 12), 252 | 253 | TileMapDataModel(3, 8, intArrayOf( 254 | 1, 1, 0, 1, 1, 0, 1, 1, 255 | 1, 1, 0, 1, 1, 0, 1, 1, 256 | 1, 1, 0, 1, 1, 0, 1, 1 257 | ), arrayOf( 258 | teleport(1, 1, 1, 3), 259 | teleport(1, 4, 1, 6)), 260 | goal = 25), 261 | TileMapDataModel(7, 2, intArrayOf( 262 | 1, 1, 263 | 1, 1, 264 | 1, 1, 265 | 0, 0, 266 | 1, 1, 267 | 1, 1, 268 | 1, 1 269 | ), arrayOf( 270 | teleport(1, 0, 5, 1)), 271 | goal = 11), 272 | TileMapDataModel(2, 7, intArrayOf( 273 | 1, 1, 1, 0, 1, 1, 1, 274 | 1, 1, 1, 0, 1, 1, 1 275 | ), arrayOf( 276 | teleport(0, 1, 0, 5)), 277 | startRow = 1, startCol = 1, goal = 23), 278 | 279 | ///////////// OTHER ??? 280 | TileMapDataModel(4, 4, intArrayOf( 281 | 1, 1, 2, 1, 282 | 1, 1, 1, 2, 283 | 2, 1, 1, 1, 284 | 1, 2, 1, 1 285 | ), goal = 15), 286 | 287 | ///////////// HARD LEVELS 288 | 289 | TileMapDataModel(7, 6, intArrayOf( 290 | 0, 1, 1, 1, 1, 0, 291 | 0, 1, 0, 0, 1, 0, 292 | 1, 1, 1, 1, 1, 1, 293 | 1, 0, 1, 1, 0, 1, 294 | 1, 1, 1, 1, 1, 1, 295 | 0, 1, 0, 0, 1, 0, 296 | 0, 1, 1, 1, 1, 0 297 | ), startRow = 3, startCol = 2, goal = 31), 298 | TileMapDataModel(5, 7, intArrayOf( 299 | 0, 1, 0, 0, 0, 1, 0, 300 | 0, 1, 0, 1, 0, 1, 0, 301 | 1, 1, 1, 1, 1, 1, 1, 302 | 0, 1, 0, 1, 0, 1, 0, 303 | 0, 1, 0, 0, 0, 1, 0 304 | ), arrayOf( 305 | teleport(0, 1, 4, 5), 306 | teleport(0, 5, 4, 1)), 307 | 2, 3, 22), 308 | 309 | TileMapDataModel(5, 5, intArrayOf( 310 | 0, 1, 0, 1, 0, 311 | 1, 1, 1, 1, 1, 312 | 0, 1, 1, 1, 0, 313 | 1, 1, 1, 1, 1, 314 | 0, 1, 0, 1, 0 315 | ), arrayOf( 316 | teleport(0, 1, 3, 4), 317 | teleport(0, 3, 3, 0), 318 | teleport(1, 0, 4, 3), 319 | teleport(1, 4, 4, 1)), 320 | 2, 2, 24), 321 | TileMapDataModel(7, 3, intArrayOf( 322 | 0, 1, 0, 323 | 1, 1, 1, 324 | 1, 1, 1, 325 | 0, 0, 0, 326 | 1, 1, 1, 327 | 1, 1, 1, 328 | 0, 1, 0 329 | ), arrayOf( 330 | superJump(2, 1), 331 | superJump(4, 1)), 332 | startRow = 0, startCol = 1, goal = 25), 333 | TileMapDataModel(3, 5, intArrayOf( 334 | 1, 0, 1, 1, 1, 335 | 1, 1, 1, 1, 1, 336 | 1, 0, 1, 1, 1 337 | ), arrayOf( 338 | arrowUp(2, 2), 339 | arrowRight(2, 0), 340 | arrowRight(0, 2), 341 | arrowRight(0, 0), 342 | superJump(0, 0), 343 | superJump(0, 2), 344 | superJump(2, 0), 345 | superJump(2, 2)), 346 | startRow = 1, startCol = 1, goal = 24), 347 | TileMapDataModel(5, 3, intArrayOf( 348 | 0, 1, 0, 349 | 1, 1, 1, 350 | 1, 1, 1, 351 | 1, 1, 1, 352 | 1, 1, 1 353 | ), arrayOf( 354 | teleport(1, 1, 4, 0), 355 | teleport(1, 2, 4, 2), 356 | teleport(2, 0, 4, 1), 357 | teleport(2, 1, 3, 1), 358 | teleport(2, 2, 3, 0), 359 | teleport(3, 2, 1, 0)), 360 | startRow = 0, startCol = 1, goal = 12), 361 | TileMapDataModel(5, 5, intArrayOf( 362 | 1, 1, 1, 0, 0, 363 | 1, 1, 1, 1, 0, 364 | 1, 1, 1, 1, 1, 365 | 0, 1, 1, 1, 1, 366 | 0, 0, 1, 1, 1 367 | ), arrayOf( 368 | arrowRight(3, 1), 369 | arrowDown(1, 3), 370 | superJump(2, 2), 371 | teleport(4, 4, 0, 0)), 372 | 1, 1, 28) 373 | ) 374 | 375 | private fun arrowUp(row: Int, col: Int) = TileObjectDataModel(TileObjectType.ARROW_UP, row, col) 376 | private fun arrowLeft(row: Int, col: Int) = TileObjectDataModel(TileObjectType.ARROW_LEFT, row, col) 377 | private fun arrowDown(row: Int, col: Int) = TileObjectDataModel(TileObjectType.ARROW_DOWN, row, col) 378 | private fun arrowRight(row: Int, col: Int) = TileObjectDataModel(TileObjectType.ARROW_RIGHT, row, col) 379 | private fun superJump(row: Int, col: Int) = TileObjectDataModel(TileObjectType.SUPER_JUMP, row, col) 380 | private fun teleport(row: Int, col: Int, row2: Int, col2: Int) = TeleportDataModel(TileObjectType.TELEPORT, row, col, row2, col2) 381 | } 382 | 383 | } 384 | -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/tilemap/TileObject.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.tilemap 2 | 3 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 4 | import com.badlogic.gdx.math.Vector3 5 | import com.distraction.sandbox.Context 6 | 7 | abstract class TileObject(protected val context: Context, val tileMap: TileMap) { 8 | val p = Vector3() 9 | val pp = Vector3() 10 | val pdest = Vector3() 11 | 12 | var row = 0 13 | var col = 0 14 | var width = 0f 15 | var height = 0f 16 | var remove = false 17 | 18 | open fun setTile(row: Int, col: Int) { 19 | this.row = row 20 | this.col = col 21 | tileMap.toPosition(row, col, p) 22 | } 23 | 24 | fun moveToDest(dist: Float) { 25 | if (p.x < pdest.x) { 26 | p.x += dist 27 | if (p.x > pdest.x) { 28 | p.x = pdest.x 29 | } 30 | } 31 | if (p.x > pdest.x) { 32 | p.x -= dist 33 | if (p.x < pdest.x) { 34 | p.x = pdest.x 35 | } 36 | } 37 | if (p.y < pdest.y) { 38 | p.y += dist 39 | if (p.y > pdest.y) { 40 | p.y = pdest.y 41 | } 42 | } 43 | if (p.y > pdest.y) { 44 | p.y -= dist 45 | if (p.y < pdest.y) { 46 | p.y = pdest.y 47 | } 48 | } 49 | } 50 | 51 | abstract fun update(dt: Float) 52 | abstract fun render(sb: SpriteBatch) 53 | } 54 | 55 | -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/tilemap/tileobjects/Arrow.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.tilemap.tileobjects 2 | 3 | 4 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 5 | import com.distraction.sandbox.Context 6 | import com.distraction.sandbox.getAtlas 7 | import com.distraction.sandbox.tilemap.TileMap 8 | import com.distraction.sandbox.tilemap.TileObject 9 | import com.distraction.sandbox.tilemap.tileobjects.Player.Direction.* 10 | 11 | class Arrow(context: Context, tileMap: TileMap, row: Int, col: Int, val direction: Player.Direction) : TileObject(context, tileMap) { 12 | private val image = context.assets.getAtlas().findRegion("arrow") 13 | 14 | init { 15 | setTile(row, col) 16 | } 17 | 18 | override fun update(dt: Float) { 19 | 20 | } 21 | 22 | override fun render(sb: SpriteBatch) { 23 | tileMap.toIsometric(p.x, p.y, pp) 24 | when (direction) { 25 | RIGHT -> sb.draw(image, pp.x - image.regionWidth / 2 - 2, pp.y - image.regionHeight / 2 - 2) 26 | LEFT -> sb.draw(image, pp.x + image.regionWidth / 2 + 3, pp.y + image.regionHeight / 2 - 3, -image.regionWidth * 1f, -image.regionHeight * 1f) 27 | UP -> sb.draw(image, pp.x - image.regionWidth / 2 - 2, pp.y + image.regionHeight / 2 - 3, image.regionWidth * 1f, -image.regionHeight * 1f) 28 | DOWN -> sb.draw(image, pp.x + image.regionWidth / 2 + 3, pp.y - image.regionHeight / 2 - 2, -image.regionWidth * 1f, image.regionHeight * 1f) 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/tilemap/tileobjects/Player.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.tilemap.tileobjects 2 | 3 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 4 | import com.badlogic.gdx.math.MathUtils 5 | import com.distraction.sandbox.* 6 | import com.distraction.sandbox.states.MoveListener 7 | import com.distraction.sandbox.tilemap.Tile 8 | import com.distraction.sandbox.tilemap.TileMap 9 | import com.distraction.sandbox.tilemap.TileObject 10 | import com.distraction.sandbox.tilemap.tileobjects.Player.Direction.* 11 | 12 | class Player(context: Context, tileMap: TileMap, private val moveListener: MoveListener?) : TileObject(context, tileMap) { 13 | 14 | enum class Direction { 15 | UP, 16 | RIGHT, 17 | LEFT, 18 | DOWN 19 | } 20 | 21 | private val animationSet = AnimationSet() 22 | 23 | private val speed = 32f * 2 24 | private val jumpHeight = 20f 25 | private var totalDist = 0f 26 | private var moving = false 27 | private var sliding = false 28 | private var superjump = false 29 | var teleporting = false 30 | private var justTeleported = false 31 | private var teleportSpeed = 0f 32 | private var direction = RIGHT 33 | 34 | init { 35 | setTile(tileMap.levelData.startRow, tileMap.levelData.startCol) 36 | p.z = 4f 37 | pdest.set(p) 38 | 39 | animationSet.addAnimation("idle", Animation(context.assets.getAtlas().findRegion("playeridle").split(16, 18)[0], 1f / 2f)) 40 | animationSet.addAnimation("idler", Animation(context.assets.getAtlas().findRegion("playeridler").split(16, 18)[0], 1f / 2f)) 41 | animationSet.addAnimation("jump", Animation(context.assets.getAtlas().findRegion("playerjump").split(13, 18)[0], -1f)) 42 | animationSet.addAnimation("jumpr", Animation(context.assets.getAtlas().findRegion("playerjumpr").split(13, 18)[0], -1f)) 43 | animationSet.addAnimation("crouch", Animation(context.assets.getAtlas().findRegion("playercrouch").split(16, 18)[0], 1f / 10f)) 44 | animationSet.addAnimation("crouchr", Animation(context.assets.getAtlas().findRegion("playercrouchr").split(16, 18)[0], 1f / 10f)) 45 | 46 | animationSet.setAnimation("idle") 47 | } 48 | 49 | override fun setTile(row: Int, col: Int) { 50 | super.setTile(row, col) 51 | tileMap.getTile(row, col).toggleActive() 52 | } 53 | 54 | fun moveTile(rowdx: Int, coldx: Int) { 55 | if (moving) return 56 | if (!superjump && !tileMap.isValidTile(row + rowdx, col + coldx)) return 57 | if (!teleporting) { 58 | when { 59 | coldx > 0 -> direction = RIGHT 60 | coldx < 0 -> direction = LEFT 61 | rowdx > 0 -> direction = DOWN 62 | rowdx < 0 -> direction = UP 63 | } 64 | } 65 | row += rowdx 66 | col += coldx 67 | tileMap.toPosition(row, col, pdest) 68 | totalDist = getRemainingDistance() 69 | moving = true 70 | justTeleported = false 71 | } 72 | 73 | fun getRemainingDistance() = Utils.dist(pdest.x, pdest.y, p.x, p.y) 74 | 75 | fun atDestination() = p.x == pdest.x && p.y == pdest.y 76 | 77 | private fun addTileLight() { 78 | if (tileMap.getTile(row, col).active) { 79 | tileMap.otherObjects.add(TileLight(context, tileMap, row, col)) 80 | } 81 | } 82 | 83 | private fun handleJustMoved(tile: Tile) { 84 | if (moving) { 85 | moveListener?.onMoved() 86 | if (!tileMap.isFinished()) { 87 | tile.toggleActive() 88 | moveListener?.onToggled() 89 | } 90 | sliding = false 91 | superjump = false 92 | moving = false 93 | if (atDestination()) { 94 | teleporting = false 95 | } 96 | addTileLight() 97 | } 98 | } 99 | 100 | private fun handleTileObjects(tile: Tile) { 101 | tile.objects.forEach { 102 | when { 103 | it is Arrow -> { 104 | sliding = true 105 | direction = it.direction 106 | } 107 | it is SuperJump -> { 108 | superjump = true 109 | } 110 | it is Teleport && !justTeleported -> { 111 | teleporting = true 112 | if (it.row == row && it.col == col) { 113 | teleportSpeed = Utils.max(Utils.abs(p.y - tileMap.toPosition(it.row2)), Utils.abs(p.x - tileMap.toPosition(it.col2))) * 1.5f 114 | moveTile(it.row2 - it.row, it.col2 - it.col) 115 | } else { 116 | teleportSpeed = Utils.max(Utils.abs(p.y - tileMap.toPosition(it.row)), Utils.abs(p.x - tileMap.toPosition(it.col))) * 1.5f 117 | moveTile(it.row - it.row2, it.col - it.col2) 118 | } 119 | justTeleported = true 120 | } 121 | } 122 | } 123 | 124 | if (sliding || superjump) { 125 | val dist2 = if (superjump) 2 else 1 126 | var r = 0 127 | var c = 0 128 | when (direction) { 129 | UP -> r = -dist2 130 | LEFT -> c = -dist2 131 | RIGHT -> c = dist2 132 | DOWN -> r = dist2 133 | } 134 | moving = false 135 | if (superjump) { 136 | sliding = false 137 | } 138 | moveTile(r, c) 139 | } 140 | } 141 | 142 | private fun updateBounceHeight() { 143 | if (sliding) { 144 | p.z = 4f 145 | } else { 146 | p.z = 4f + (jumpHeight * (if (superjump) 2 else 1) * MathUtils.sin(3.14f * getRemainingDistance() / totalDist)) 147 | } 148 | } 149 | 150 | private fun updateAnimations(dt: Float) { 151 | if (sliding) { 152 | animationSet.setAnimation(if (direction == RIGHT || direction == DOWN) "crouch" else "crouchr") 153 | } else if (p.x == pdest.x && p.y == pdest.y) { 154 | if ((animationSet.currentAnimationKey.equals("jump") || animationSet.currentAnimationKey.equals("jumpr"))) { 155 | animationSet.setAnimation(if (direction == RIGHT || direction == DOWN) "crouch" else "crouchr") 156 | } else if (animationSet.currentAnimation!!.hasPlayedOnce()) { 157 | animationSet.setAnimation(if (direction == RIGHT || direction == DOWN) "idle" else "idler") 158 | } 159 | } else { 160 | if ((animationSet.currentAnimationKey.equals("idle") || animationSet.currentAnimationKey.equals("idler"))) { 161 | animationSet.setAnimation(if (direction == RIGHT || direction == DOWN) "crouch" else "crouchr") 162 | } else { 163 | animationSet.setAnimation(if (direction == RIGHT || direction == DOWN) "jump" else "jumpr") 164 | } 165 | } 166 | animationSet.update(dt) 167 | } 168 | 169 | override fun update(dt: Float) { 170 | moveToDest((if (teleporting && justTeleported) teleportSpeed else speed) * dt * (if (sliding) 4f else if (superjump) 2f else 1f)) 171 | 172 | if (atDestination()) { 173 | if (!tileMap.contains(row, col)) { 174 | moveListener?.onIllegal() 175 | return 176 | } 177 | val tile = tileMap.getTile(row, col) 178 | 179 | handleJustMoved(tile) 180 | handleTileObjects(tile) 181 | } 182 | 183 | updateBounceHeight() 184 | updateAnimations(dt) 185 | } 186 | 187 | override fun render(sb: SpriteBatch) { 188 | tileMap.toIsometric(p.x, p.y, pp) 189 | if (!teleporting) { 190 | if (direction == RIGHT || direction == UP) { 191 | sb.draw(animationSet.getImage(), pp.x - animationSet.getImage()!!.regionWidth / 2, pp.y - animationSet.getImage()!!.regionHeight / 2 + p.z) 192 | } else { 193 | sb.draw( 194 | animationSet.getImage(), 195 | pp.x + animationSet.getImage()!!.regionWidth / 2, 196 | pp.y - animationSet.getImage()!!.regionHeight / 2 + p.z, 197 | -animationSet.getImage()!!.regionWidth * 1f, 198 | animationSet.getImage()!!.regionHeight * 1f) 199 | } 200 | } 201 | } 202 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/tilemap/tileobjects/SuperJump.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.tilemap.tileobjects 2 | 3 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 4 | import com.distraction.sandbox.Context 5 | import com.distraction.sandbox.getAtlas 6 | import com.distraction.sandbox.tilemap.TileMap 7 | import com.distraction.sandbox.tilemap.TileObject 8 | 9 | class SuperJumpLight(context: Context, tileMap: TileMap, row: Int, col: Int) : TileObject(context, tileMap) { 10 | private val image = context.assets.getAtlas().findRegion("superjump") 11 | private val speed = 10f 12 | private val duration = 1f 13 | private var time = 0f 14 | 15 | init { 16 | setTile(row, col) 17 | p.z = -2f 18 | } 19 | 20 | override fun update(dt: Float) { 21 | time += dt 22 | p.z += speed * dt 23 | if (time > duration) { 24 | remove = true 25 | } 26 | } 27 | 28 | override fun render(sb: SpriteBatch) { 29 | tileMap.toIsometric(p.x, p.y, pp) 30 | sb.draw(image, pp.x - image.regionWidth / 2, pp.y - image.regionHeight / 2 + p.z) 31 | } 32 | } 33 | 34 | class SuperJump(context: Context, tileMap: TileMap, row: Int, col: Int) : TileObject(context, tileMap) { 35 | private val interval = 0.4f 36 | private var time = interval 37 | 38 | init { 39 | setTile(row, col) 40 | } 41 | 42 | override fun update(dt: Float) { 43 | time += dt 44 | while (time > interval) { 45 | time -= interval 46 | tileMap.otherObjects.add(SuperJumpLight(context, tileMap, row, col)) 47 | } 48 | } 49 | 50 | override fun render(sb: SpriteBatch) { 51 | 52 | } 53 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/tilemap/tileobjects/Teleport.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.tilemap.tileobjects 2 | 3 | import com.badlogic.gdx.graphics.Color 4 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 5 | import com.badlogic.gdx.math.MathUtils 6 | import com.badlogic.gdx.math.Vector3 7 | import com.distraction.sandbox.Context 8 | import com.distraction.sandbox.getAtlas 9 | import com.distraction.sandbox.tilemap.TileMap 10 | import com.distraction.sandbox.tilemap.TileObject 11 | 12 | class TeleportLight(context: Context, tileMap: TileMap, row: Int, col: Int) : TileObject(context, tileMap) { 13 | private val image = context.assets.getAtlas().findRegion("teleport") 14 | private val dot = context.assets.getAtlas().findRegion("dot") 15 | private val color = Color.valueOf("AAE2FF30") 16 | private val particles = arrayListOf() 17 | private val speed = 32f 18 | 19 | private val interval = 0.1f 20 | private var time = interval 21 | 22 | init { 23 | setTile(row, col) 24 | p.z = -2f 25 | height = 16f 26 | } 27 | 28 | override fun update(dt: Float) { 29 | time += dt 30 | while (time >= interval) { 31 | time -= interval 32 | val v = Vector3(p.x, p.y, 0f) 33 | tileMap.toIsometric(v.x, v.y, v) 34 | v.x += MathUtils.round(MathUtils.random() * (image.regionWidth - 1) - image.regionWidth / 2) 35 | v.y += MathUtils.random() * 5 36 | v.z = v.y + height 37 | particles.add(v) 38 | } 39 | particles.forEach { 40 | it.y += speed * dt 41 | } 42 | particles.removeAll { 43 | it.y > it.z 44 | } 45 | } 46 | 47 | override fun render(sb: SpriteBatch) { 48 | tileMap.toIsometric(p.x, p.y, pp) 49 | sb.draw(image, pp.x - image.regionWidth / 2, pp.y - image.regionHeight / 2 + 5 + p.z) 50 | val c = sb.color 51 | sb.color = color 52 | particles.forEach { 53 | color.a = (it.z - it.y) / height 54 | sb.color = color 55 | sb.draw(dot, it.x, it.y, 1f, 2f) 56 | } 57 | sb.color = c 58 | } 59 | } 60 | 61 | class Teleport(context: Context, tileMap: TileMap, row: Int, col: Int, val row2: Int, val col2: Int) : TileObject(context, tileMap) { 62 | private val p2 = Vector3() 63 | 64 | init { 65 | setTile(row, col) 66 | p.z = -2f 67 | tileMap.toPosition(row2, col2, p2) 68 | tileMap.otherObjects.add(TeleportLight(context, tileMap, row, col)) 69 | tileMap.otherObjects.add(TeleportLight(context, tileMap, row2, col2)) 70 | } 71 | 72 | override fun update(dt: Float) { 73 | 74 | } 75 | 76 | override fun render(sb: SpriteBatch) { 77 | 78 | } 79 | } -------------------------------------------------------------------------------- /core/src/com/distraction/sandbox/tilemap/tileobjects/TileLight.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.tilemap.tileobjects 2 | 3 | import com.badlogic.gdx.graphics.Color 4 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 5 | import com.distraction.sandbox.Context 6 | import com.distraction.sandbox.getAtlas 7 | import com.distraction.sandbox.tilemap.TileMap 8 | import com.distraction.sandbox.tilemap.TileObject 9 | 10 | class TileLight(context: Context, tileMap: TileMap, row: Int, col: Int) : TileObject(context, tileMap) { 11 | private val image = context.assets.getAtlas().findRegion("tilelight") 12 | private val color = Color(1f, 1f, 1f, 1f) 13 | private val maxHeight = 32f 14 | private val speed = 32f * 12f 15 | private val duration = 0.5f 16 | private var time = 0f 17 | 18 | init { 19 | setTile(row, col) 20 | } 21 | 22 | override fun update(dt: Float) { 23 | height += speed * dt 24 | if (height > maxHeight) { 25 | height = maxHeight 26 | } 27 | time += dt 28 | color.a = 1f - time / duration 29 | if (time > duration) { 30 | remove = true 31 | } 32 | } 33 | 34 | override fun render(sb: SpriteBatch) { 35 | tileMap.toIsometric(p.x, p.y, pp) 36 | val c = sb.color 37 | sb.color = color 38 | sb.draw(image, pp.x - image.regionWidth / 2, pp.y - image.regionHeight / 2 + 5, 1f * image.regionWidth, height) 39 | sb.color = c 40 | } 41 | } -------------------------------------------------------------------------------- /desktop/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "kotlin" 2 | 3 | sourceCompatibility = 1.6 4 | sourceSets.main.java.srcDirs = [ "src/" ] 5 | 6 | project.ext.mainClassName = "com.distraction.sandbox.desktop.DesktopLauncher" 7 | project.ext.assetsDir = new File("../android/assets"); 8 | 9 | task run(dependsOn: classes, type: JavaExec) { 10 | main = project.mainClassName 11 | classpath = sourceSets.main.runtimeClasspath 12 | standardInput = System.in 13 | workingDir = project.assetsDir 14 | ignoreExitValue = true 15 | } 16 | 17 | task debug(dependsOn: classes, type: JavaExec) { 18 | main = project.mainClassName 19 | classpath = sourceSets.main.runtimeClasspath 20 | standardInput = System.in 21 | workingDir = project.assetsDir 22 | ignoreExitValue = true 23 | debug = true 24 | } 25 | 26 | task dist(type: Jar) { 27 | from files(sourceSets.main.output.classesDir) 28 | from files(sourceSets.main.output.resourcesDir) 29 | from {configurations.compile.collect {zipTree(it)}} 30 | from files(project.assetsDir); 31 | 32 | manifest { 33 | attributes 'Main-Class': project.mainClassName 34 | } 35 | } 36 | 37 | dist.dependsOn classes 38 | 39 | eclipse { 40 | project { 41 | name = appName + "-desktop" 42 | linkedResource name: 'assets', type: '2', location: 'PARENT-1-PROJECT_LOC/android/assets' 43 | } 44 | } 45 | 46 | task afterEclipseImport(description: "Post processing after project generation", group: "IDE") { 47 | doLast { 48 | def classpath = new XmlParser().parse(file(".classpath")) 49 | new Node(classpath, "classpathentry", [ kind: 'src', path: 'assets' ]); 50 | def writer = new FileWriter(file(".classpath")) 51 | def printer = new XmlNodePrinter(new PrintWriter(writer)) 52 | printer.setPreserveWhitespace(true) 53 | printer.print(classpath) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /desktop/src/com/distraction/sandbox/desktop/DesktopLauncher.kt: -------------------------------------------------------------------------------- 1 | package com.distraction.sandbox.desktop 2 | 3 | import com.badlogic.gdx.backends.lwjgl.LwjglApplication 4 | import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration 5 | import com.distraction.sandbox.Constants 6 | import com.distraction.sandbox.MainGame 7 | 8 | object DesktopLauncher { 9 | @JvmStatic 10 | fun main(arg: Array) { 11 | val config = LwjglApplicationConfiguration() 12 | config.width = Constants.DESKTOP_WIDTH 13 | config.height = Constants.DESKTOP_HEIGHT 14 | LwjglApplication(MainGame(), config) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.daemon=true 2 | org.gradle.jvmargs=-Xms128m -Xmx1500m 3 | org.gradle.configureondemand=false 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/foreignguymike/Sandbox/526a5c4e0096a0bd7cbd959eb394921ba48912a8/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 09 23:06:52 EDT 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':LevelMaker' 2 | include 'desktop', 'android', 'core' --------------------------------------------------------------------------------