← Tiled-based Raycasting
Authors:
Tags:
dependencies:
- https://github.com/korlibs/korge-ext/tree/v0.1.3/korma-tile-raycasting/korma-tile-raycasting##2a331af4bab999c105c5f945b152e5f95dbf49f1
Some code to get started
fun chunk(pos: PointInt, data: String): StackedIntArray2 = StackedIntArray2(IntArray2(data, gen = { c, x, y -> if (c == '.') 0 else 1 }), startX = pos.x, startY = pos.y)
val fullMap = SparseChunkedStackedIntArray2()
fullMap.putChunk(chunk(PointInt(0, 0), """
.......
.......
.####..
.......
""".trimIndent()))
val result = fullMap.raycast(RayFromTwoPoints(Point(12, 12), Point(120, 80)), Size(8, 8)) { this.getLast(it.x, it.y) != 0 }
assertEquals(PointInt(18, 16), result?.toInt())
Visual testing scene
import korlibs.datastructure.*
import korlibs.image.atlas.*
import korlibs.image.bitmap.*
import korlibs.image.color.*
import korlibs.image.tiles.*
import korlibs.korge.*
import korlibs.korge.input.*
import korlibs.korge.scene.*
import korlibs.korge.view.*
import korlibs.korge.view.tiles.*
import korlibs.math.geom.*
import korlibs.math.geom.Circle
import korlibs.math.raycasting.*
suspend fun main() = Korge {
sceneContainer().changeTo({ RaycastingExampleScene()})
}
class RaycastingExampleScene : Scene() {
@KeepOnReload
var startPoint: Point = Point(300, 300)
@KeepOnReload
var endPoint: Point = Point(100, 100)
@KeepOnReload
var tileMap: IntArray2 = IntArray2(100, 100, 0).also {
for (n in 0 until 10) {
it[10 + n, 10] = 1
it[10, 10 + n] = 1
}
}
override suspend fun SContainer.sceneMain() {
val atlas = MutableAtlasUnit()
val bmp0 = atlas.add(Bitmap32(16, 16, Colors.TRANSPARENT.premultiplied)).slice
val bmp1 = atlas.add(Bitmap32(16, 16, Colors.BLUE.premultiplied)).slice
val tileSet = TileSet(TileSetTileInfo(0, bmp0), TileSetTileInfo(0, bmp1))
val tileMap = tileMap(tileMap, tileSet)
val cellSize = Size(bmp0.width, bmp0.height)
val overlay = graphics(renderer = GraphicsRenderer.SYSTEM) { }
text("""
mouse down: put blocks
shift+mouse down: remove blocks
ctrl+mouse down: to change the starting point
""".trimIndent())
fun updateOverlay(
startPoint: Point,
endPoint: Point,
result: Point?
) {
overlay.updateShape {
clear()
stroke(Colors.YELLOW) { line(startPoint, endPoint) }
stroke(Colors.GREEN) { circle(Circle(startPoint, 3f)) }
//stroke(Colors.WHITE) { circle(Circle(endPoint, 3f)) }
if (result != null) {
stroke(Colors.RED) {
circle(Circle(result, 3f))
}
}
}
}
fun downOnTileMapPos(mousePos: Point, add: Boolean, setStartPos: Boolean) {
if (setStartPos) {
startPoint = mousePos
return
}
val cell = (mousePos / cellSize).toInt()
tileMap.lock {
tileMap.stackedIntMap.setFirst(cell.x, cell.y, if (add) 1 else 0)
}
}
fun checkTileMap(mousePos: Point) {
val result = tileMap.stackedIntMap.raycast(RayFromTwoPoints(startPoint, mousePos), cellSize) {
//println("this.getLast(it.x, it.y): $it")
if (!this.inside(it.x, it.y)) return@raycast false
this.getLast(it.x, it.y) != 0
}
updateOverlay(startPoint, mousePos, result)
}
tileMap.mouse {
onDown {
downOnTileMapPos(it.currentPosLocal, !it.isShiftDown, it.isCtrlDown)
checkTileMap(it.currentPosLocal)
}
onMove {
if (it.pressing) downOnTileMapPos(it.currentPosLocal, !it.isShiftDown, it.isCtrlDown)
checkTileMap(it.currentPosLocal)
}
}
}
}