From 3c3322ef1a7aca3517ff94f723004fb809dec6cd Mon Sep 17 00:00:00 2001 From: James Barnett Date: Wed, 30 Dec 2020 23:13:40 +0000 Subject: Add adjustable render options. Update UI --- src/main/kotlin/Camera.kt | 4 +-- src/main/kotlin/CameraController.kt | 15 +++++++--- src/main/kotlin/Minimap.kt | 11 ++----- src/main/kotlin/RaycastContext.kt | 1 + src/main/kotlin/Raycaster.kt | 17 +++++++---- src/main/kotlin/Renderer.kt | 10 ++----- src/main/kotlin/Ui.kt | 58 +++++++++++++++++++++++++++++++++---- src/main/kotlin/main.kt | 8 +++-- 8 files changed, 90 insertions(+), 34 deletions(-) (limited to 'src/main/kotlin') diff --git a/src/main/kotlin/Camera.kt b/src/main/kotlin/Camera.kt index 4eb8d43..3c2e582 100644 --- a/src/main/kotlin/Camera.kt +++ b/src/main/kotlin/Camera.kt @@ -1,6 +1,6 @@ data class Camera( - val fov: Int, + var fov: Int, var xPos: Double, var yPos: Double, - var rotation: Double + var rotation: Double, ) \ No newline at end of file diff --git a/src/main/kotlin/CameraController.kt b/src/main/kotlin/CameraController.kt index 436b34b..510f1a0 100644 --- a/src/main/kotlin/CameraController.kt +++ b/src/main/kotlin/CameraController.kt @@ -1,4 +1,5 @@ import kotlinx.browser.document +import org.w3c.dom.HTMLButtonElement class CameraController( private val camera: Camera, @@ -8,18 +9,20 @@ class CameraController( ) { init { - document.onkeydown = { inputHandler(it.code) } + document.onkeydown = { keyHandler(it.code) } + (document.getElementById("up") as HTMLButtonElement).onclick = { moveForward() } + (document.getElementById("down") as HTMLButtonElement).onclick = { moveBack() } + (document.getElementById("left") as HTMLButtonElement).onclick = { rotateAntiClockwise() } + (document.getElementById("right") as HTMLButtonElement).onclick = { rotateClockwise() } } - private fun inputHandler(code: String) { + private fun keyHandler(code: String) { when (code) { "KeyW" -> moveForward() "KeyS" -> moveBack() "KeyA" -> rotateAntiClockwise() "KeyD" -> rotateClockwise() } - afterInput() - console.log("x: ${camera.xPos} y: ${camera.yPos} r: ${camera.rotation}") } private fun moveForward() { @@ -27,6 +30,7 @@ class CameraController( val cameraSin = camera.rotation.sine() * moveSpeed camera.xPos += cameraCos camera.yPos += cameraSin + afterInput() } private fun moveBack() { @@ -34,14 +38,17 @@ class CameraController( val cameraSin = camera.rotation.sine() * moveSpeed camera.xPos -= cameraCos camera.yPos -= cameraSin + afterInput() } private fun rotateClockwise() { camera.rotation += rotateSpeed + afterInput() } private fun rotateAntiClockwise() { camera.rotation -= rotateSpeed + afterInput() } } \ No newline at end of file diff --git a/src/main/kotlin/Minimap.kt b/src/main/kotlin/Minimap.kt index 34862e0..7cbc892 100644 --- a/src/main/kotlin/Minimap.kt +++ b/src/main/kotlin/Minimap.kt @@ -3,26 +3,21 @@ import org.w3c.dom.CanvasRenderingContext2D import org.w3c.dom.HTMLCanvasElement class Minimap(private val map: Map) { - private val scale = 20 + private val scale = 15 - private val canvas = (document.createElement("canvas") as HTMLCanvasElement) + private val canvas = (document.getElementById("minimap") as HTMLCanvasElement) .apply { width = map.width * scale height = map.height * scale - id = "minimap" } private val context = canvas.getContext("2d") as CanvasRenderingContext2D - init { - document.body!!.appendChild(canvas) - } - private fun drawMap() { for (y in 0 until map.height) { for (x in 0 until map.width) { val wall = map.data[y][x] if (wall > 0) { - context.fillStyle = "#000000" + context.fillStyle = "#202020" context.fillRect((x * scale).toDouble(), (y * scale).toDouble(), scale.toDouble(), scale.toDouble()) } } diff --git a/src/main/kotlin/RaycastContext.kt b/src/main/kotlin/RaycastContext.kt index 808f3c4..2f8ec9c 100644 --- a/src/main/kotlin/RaycastContext.kt +++ b/src/main/kotlin/RaycastContext.kt @@ -1,4 +1,5 @@ data class RaycastContext( + val raycastOptions: RaycastOptions, val renderer: Renderer, val textureManager: TextureManager, val camera: Camera, diff --git a/src/main/kotlin/Raycaster.kt b/src/main/kotlin/Raycaster.kt index ff2cc24..04b4d6f 100644 --- a/src/main/kotlin/Raycaster.kt +++ b/src/main/kotlin/Raycaster.kt @@ -1,11 +1,16 @@ import kotlin.js.Date import kotlin.math.pow -class Raycaster(private val stepPrecision: Int) { +data class RaycastOptions( + var fixFisheye: Boolean, + var stepPrecision: Int +) + +class Raycaster { fun raycast(raycastContext: RaycastContext) { val raycastStartMs = Date().getTime() - val (renderer, textureManager, camera, map, _) = raycastContext + val (options, renderer, textureManager, camera, map, _) = raycastContext val viewportWidth = renderer.viewportWidth val viewportHeight = renderer.viewportHeight @@ -20,8 +25,8 @@ class Raycaster(private val stepPrecision: Int) { var objectTypeHit: Int do { - rayX += raySweepAngle.cosine() / stepPrecision - rayY += raySweepAngle.sine() / stepPrecision + rayX += raySweepAngle.cosine() / options.stepPrecision + rayY += raySweepAngle.sine() / options.stepPrecision // TODO bounds checking objectTypeHit = map.data[rayY.toFlooredInt()][rayX.toFlooredInt()] @@ -31,7 +36,9 @@ class Raycaster(private val stepPrecision: Int) { val textureXIndex = ((texture.width * (rayX + rayY)) % texture.width).toFlooredInt() var distanceToWall = kotlin.math.sqrt((camera.xPos - rayX).pow(2) + (camera.yPos - rayY).pow(2)) -// distanceToWall *= (raySweepAngle-camera.rotation).cosine() + if (options.fixFisheye) { + distanceToWall *= (raySweepAngle-camera.rotation).cosine() + } val wallHeight = viewportHeightHalf / distanceToWall // Ceiling diff --git a/src/main/kotlin/Renderer.kt b/src/main/kotlin/Renderer.kt index 3a7111e..49d6b2c 100644 --- a/src/main/kotlin/Renderer.kt +++ b/src/main/kotlin/Renderer.kt @@ -4,18 +4,14 @@ import org.w3c.dom.HTMLCanvasElement class Renderer(val viewportWidth: Int, val viewportHeight: Int, private val outputScale: Int) { - private val canvas = (document.createElement("canvas") as HTMLCanvasElement) + private val canvas = (document.getElementById("render-output") as HTMLCanvasElement) .apply { width = viewportWidth * outputScale height = viewportHeight * outputScale } - private val context = canvas.getContext("2d") as CanvasRenderingContext2D - - init { - context.scale(outputScale.toDouble(), outputScale.toDouble()) - document.body!!.appendChild(canvas) - } + private val context = (canvas.getContext("2d") as CanvasRenderingContext2D) + .apply { scale(outputScale.toDouble(), outputScale.toDouble()) } fun drawLine(startX: Double, startY: Double, endX: Double, endY: Double, cssColour: String = "#FF0000") { context.strokeStyle = cssColour diff --git a/src/main/kotlin/Ui.kt b/src/main/kotlin/Ui.kt index e477bec..dd8b0fc 100644 --- a/src/main/kotlin/Ui.kt +++ b/src/main/kotlin/Ui.kt @@ -1,23 +1,71 @@ import kotlinx.browser.document +import kotlinx.dom.removeClass +import org.w3c.dom.HTMLElement +import org.w3c.dom.HTMLInputElement import org.w3c.dom.HTMLSelectElement -class Ui(private val textureManager: TextureManager, private val afterChange: () -> Unit) { - private val textureSelect: HTMLSelectElement +class Ui(private val context: RaycastContext, private val afterChange: () -> Unit) { + + private val textureSelect = registerTextureSetHandler() + init { - textureSelect = registerTextureSetHandler() + registerFovInputHandler() + registerRaycastPrecisionInputHandler() + registerMinimapToggleHandler() + registerFisheyeToggleHandler() } private fun registerTextureSetHandler(): HTMLSelectElement { val select = document.getElementById("texture-set") as HTMLSelectElement select.onchange = { - textureManager.loadTextures(select.value) + context.textureManager.loadTextures(select.value) afterChange() } - return select } + private fun registerFovInputHandler() { + val fov = document.getElementById("fov") as HTMLInputElement + val fovValue = document.getElementById("fov-value") as HTMLElement + fov.oninput = { + context.camera.fov = fov.value.toInt() + fovValue.textContent = fov.value + afterChange() + } + } + + private fun registerRaycastPrecisionInputHandler() { + val precision = document.getElementById("raycast-precision") as HTMLInputElement + val precisionValue = document.getElementById("raycast-precision-value") as HTMLElement + precision.oninput = { + context.raycastOptions.stepPrecision = precision.value.toInt() + precisionValue.textContent = precision.value + afterChange() + } + } + + private fun registerMinimapToggleHandler() { + val toggle = document.getElementById("minimap-toggle") as HTMLInputElement + val minimap = document.getElementById("minimap") as HTMLElement + toggle.onchange = { + minimap.hidden = !toggle.checked + afterChange() + } + } + + private fun registerFisheyeToggleHandler() { + val fixFisheye = document.getElementById("fisheye-fix") as HTMLInputElement + fixFisheye.oninput = { + context.raycastOptions.fixFisheye = fixFisheye.checked + afterChange() + } + } + fun getSelectedTextureSet(): String { return textureSelect.value } + + fun removeLoadingIndicator() { + document.getElementById("output-wrapper")?.removeClass("loading") + } } \ No newline at end of file diff --git a/src/main/kotlin/main.kt b/src/main/kotlin/main.kt index bc39316..aa69ad2 100644 --- a/src/main/kotlin/main.kt +++ b/src/main/kotlin/main.kt @@ -1,4 +1,5 @@ fun main() { + val raycastOptions = RaycastOptions(fixFisheye = false, stepPrecision = 32) val renderer = Renderer(viewportWidth = 320, viewportHeight = 240, outputScale = 3) val textureManager = TextureManager() val camera = Camera( @@ -10,15 +11,15 @@ fun main() { val map = Map() val minimap = Minimap(map) - val context = RaycastContext(renderer, textureManager, camera, map, minimap) + val context = RaycastContext(raycastOptions, renderer, textureManager, camera, map, minimap) - val raycaster = Raycaster(stepPrecision = 32) + val raycaster = Raycaster() CameraController(camera, moveSpeed = 1.0, rotateSpeed = 15) { paint(raycaster, context) } - val ui = Ui(textureManager) { + val ui = Ui(context) { paint(raycaster, context) } @@ -26,6 +27,7 @@ fun main() { // Do an initial paint and wait for input paint(raycaster, context) + ui.removeLoadingIndicator() } fun paint(raycaster: Raycaster, raycastContext: RaycastContext) { -- cgit v1.2.3