Skip to content

Commit

Permalink
Shape2D destructuring and MapRenderer use extension. #479
Browse files Browse the repository at this point in the history
* #479: add math Shape2D destructure extensions and MapRenderer use extension

* move Shape2D info to separate section

* make BatchTiledMapRenderer extensions call original protected methods

* remove warning info (not necessary anymore)

---------

Co-authored-by: Simon Klausner <[email protected]>
  • Loading branch information
Quillraven and Simon Klausner authored Mar 26, 2024
1 parent 671f7e5 commit ddab0e7
Show file tree
Hide file tree
Showing 15 changed files with 395 additions and 1 deletion.
9 changes: 9 additions & 0 deletions math/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,15 @@ val spawners = listOf(
)
```

#### `Shape2D` extensions

- `Rectangle` and `Ellipse` instances can be destructed to four float variables in one step with
`val (x, y, w, h) = rectangle/ellipse` syntax thanks to `component1()`, `component2()`, `component3()` and `component4()` operator methods.
- `Circle` instances can be destructed to three float variables in one step with
`val (x, y, radius) = circle` syntax thanks to `component1()`, `component2()` and `component3()` operator methods.
- `Polygon` and `Polyline` instances can be destructed to two float variables in one step with
`val (x, y) = polygon/polyline` syntax thanks to `component1()` and `component2()` operator methods.

### Alternatives

You can use libGDX APIs directly or rely on third-party math libraries:
Expand Down
21 changes: 21 additions & 0 deletions math/src/main/kotlin/ktx/math/circle.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ktx.math

import com.badlogic.gdx.math.Circle

/**
* Operator function that allows to deconstruct this circle.
* @return X component.
*/
operator fun Circle.component1() = this.x

/**
* Operator function that allows to deconstruct this circle.
* @return Y component.
*/
operator fun Circle.component2() = this.y

/**
* Operator function that allows to deconstruct this circle.
* @return Radius component.
*/
operator fun Circle.component3() = this.radius
27 changes: 27 additions & 0 deletions math/src/main/kotlin/ktx/math/ellipse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ktx.math

import com.badlogic.gdx.math.Ellipse

/**
* Operator function that allows to deconstruct this ellipse.
* @return X component.
*/
operator fun Ellipse.component1() = this.x

/**
* Operator function that allows to deconstruct this ellipse.
* @return Y component.
*/
operator fun Ellipse.component2() = this.y

/**
* Operator function that allows to deconstruct this ellipse.
* @return Width component.
*/
operator fun Ellipse.component3() = this.width

/**
* Operator function that allows to deconstruct this ellipse.
* @return Height component.
*/
operator fun Ellipse.component4() = this.height
15 changes: 15 additions & 0 deletions math/src/main/kotlin/ktx/math/polygon.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ktx.math

import com.badlogic.gdx.math.Polygon

/**
* Operator function that allows to deconstruct this polygon.
* @return X component.
*/
operator fun Polygon.component1() = this.x

/**
* Operator function that allows to deconstruct this polygon.
* @return Y component.
*/
operator fun Polygon.component2() = this.y
15 changes: 15 additions & 0 deletions math/src/main/kotlin/ktx/math/polyline.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ktx.math

import com.badlogic.gdx.math.Polyline

/**
* Operator function that allows to deconstruct this polyline.
* @return X component.
*/
operator fun Polyline.component1() = this.x

/**
* Operator function that allows to deconstruct this polyline.
* @return Y component.
*/
operator fun Polyline.component2() = this.y
27 changes: 27 additions & 0 deletions math/src/main/kotlin/ktx/math/rectangle.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ktx.math

import com.badlogic.gdx.math.Rectangle

/**
* Operator function that allows to deconstruct this rectangle.
* @return X component.
*/
operator fun Rectangle.component1() = this.x

/**
* Operator function that allows to deconstruct this rectangle.
* @return Y component.
*/
operator fun Rectangle.component2() = this.y

/**
* Operator function that allows to deconstruct this rectangle.
* @return Width component.
*/
operator fun Rectangle.component3() = this.width

/**
* Operator function that allows to deconstruct this rectangle.
* @return Height component.
*/
operator fun Rectangle.component4() = this.height
20 changes: 20 additions & 0 deletions math/src/test/kotlin/ktx/math/CircleTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ktx.math

import com.badlogic.gdx.math.Circle
import org.junit.Assert.assertEquals
import org.junit.Test

class CircleTest {

@Test
fun `should destructure Circle`() {
val circle = Circle(1f, 2f, 3f)

val (x, y, radius) = circle

assertEquals(1f, x)
assertEquals(2f, y)
assertEquals(3f, radius)
}

}
21 changes: 21 additions & 0 deletions math/src/test/kotlin/ktx/math/EllipseTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ktx.math

import com.badlogic.gdx.math.Ellipse
import org.junit.Assert.assertEquals
import org.junit.Test

class EllipseTest {

@Test
fun `should destructure Ellipse`() {
val ellipse = Ellipse(1f, 2f, 3f, 4f)

val (x, y, w, h) = ellipse

assertEquals(1f, x)
assertEquals(2f, y)
assertEquals(3f, w)
assertEquals(4f, h)
}

}
19 changes: 19 additions & 0 deletions math/src/test/kotlin/ktx/math/PolygonTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ktx.math

import com.badlogic.gdx.math.Polygon
import org.junit.Assert.assertEquals
import org.junit.Test

class PolygonTest {

@Test
fun `should destructure Polygon`() {
val polygon = Polygon().apply { setPosition(1f, 2f) }

val (x, y) = polygon

assertEquals(1f, x)
assertEquals(2f, y)
}

}
19 changes: 19 additions & 0 deletions math/src/test/kotlin/ktx/math/PolylineTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ktx.math

import com.badlogic.gdx.math.Polyline
import org.junit.Assert.assertEquals
import org.junit.Test

class PolylineTest {

@Test
fun `should destructure Polyline`() {
val polyline = Polyline().apply { setPosition(1f, 2f) }

val (x, y) = polyline

assertEquals(1f, x)
assertEquals(2f, y)
}

}
21 changes: 21 additions & 0 deletions math/src/test/kotlin/ktx/math/RectangleTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ktx.math

import com.badlogic.gdx.math.Rectangle
import org.junit.Assert.assertEquals
import org.junit.Test

class RectangleTest {

@Test
fun `should destructure Rectangle`() {
val rect = Rectangle(1f, 2f, 3f, 4f)

val (x, y, w, h) = rect

assertEquals(1f, x)
assertEquals(2f, y)
assertEquals(3f, w)
assertEquals(4f, h)
}

}
27 changes: 26 additions & 1 deletion tiled/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

### Why?

libGDX brings its own set of Tiled map utilities, including loading and handling of maps exported from the editor.
LibGDX brings its own set of Tiled map utilities, including loading and handling of maps exported from the editor.
However, the API contains many wrapped non-standard collections, which makes accessing the loaded maps cumbersome.
With Kotlin's reified types and extension methods, the Tiled API can be significantly improved.

Expand Down Expand Up @@ -83,6 +83,11 @@ a certain function on them.

`isEmpty` and `isNotEmpty` extension method to check if the specific collection is empty or not.

### `BatchTiledMapRenderer`

`use` extension method to call `beginRender()` and `endRender()` automatically before
your render logic.

### Usage examples

#### General
Expand Down Expand Up @@ -259,6 +264,26 @@ if (map.layers.isNotEmpty()) {
}
```

Using the `use` extension function to render background layers:

```kotlin
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.maps.tiled.TiledMap
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer

val tiledMap = TiledMap()
val renderer = OrthogonalTiledMapRenderer(tiledMap)
val camera = OrthographicCamera()
val bgdLayers: List<TiledMapTileLayer> = tiledMap.layers
.filter { it.name.startsWith("bgd") }
.filterIsInstance<TiledMapTileLayer>()

renderer.use(camera) { mapRenderer ->
bgdLayers.forEach { mapRenderer.renderTileLayer(it) }
}
```

#### Additional documentation

- [Official Tiled website.](https://www.mapeditor.org/)
Expand Down
16 changes: 16 additions & 0 deletions tiled/src/main/kotlin/ktx/tiled/batchTiledMapRenderer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@file:Suppress("PackageDirectoryMismatch")

package com.badlogic.gdx.maps.tiled.renderers

/**
* This file is used as a workaround for the tiledMapRenderer extensions. They need
* to call [BatchTiledMapRenderer.beginRender] and [BatchTiledMapRenderer.endRender] methods
* which are protected methods. Since this file matches the package of the [BatchTiledMapRenderer],
* we can call protected methods of it and use our wrapper functions for public API extensions.
*/

@PublishedApi
internal fun BatchTiledMapRenderer.beginInternal() = this.beginRender()

@PublishedApi
internal fun BatchTiledMapRenderer.endInternal() = this.endRender()
64 changes: 64 additions & 0 deletions tiled/src/main/kotlin/ktx/tiled/tiledMapRenderer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package ktx.tiled

import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.maps.tiled.renderers.BatchTiledMapRenderer
import com.badlogic.gdx.maps.tiled.renderers.beginInternal
import com.badlogic.gdx.maps.tiled.renderers.endInternal
import com.badlogic.gdx.math.Matrix4
import com.badlogic.gdx.math.Rectangle

/**
* Automatically calls [BatchTiledMapRenderer.beginRender] and [BatchTiledMapRenderer.endRender].
* @param camera A camera to set on the renderer before [BatchTiledMapRenderer.beginRender].
* @param block inlined. Executed after [BatchTiledMapRenderer.beginRender] and before [BatchTiledMapRenderer.endRender].
*/
inline fun <T : BatchTiledMapRenderer> T.use(
camera: OrthographicCamera,
block: (T) -> Unit
) {
this.setView(camera)
this.use(block)
}

/**
* Automatically calls [BatchTiledMapRenderer.beginRender] and [BatchTiledMapRenderer.endRender].
* @param projection A projection matrix to set on the renderer before [BatchTiledMapRenderer.beginRender].
* @param x map render boundary x value.
* @param y map render boundary y value.
* @param width map render boundary width value.
* @param height map render boundary height value.
* @param block inlined. Executed after [BatchTiledMapRenderer.beginRender] and before [BatchTiledMapRenderer.endRender].
*/
inline fun <T : BatchTiledMapRenderer> T.use(
projection: Matrix4,
x: Float, y: Float,
width: Float, height: Float,
block: (T) -> Unit
) {
this.setView(projection, x, y, width, height)
this.use(block)
}

/**
* Automatically calls [BatchTiledMapRenderer.beginRender] and [BatchTiledMapRenderer.endRender].
* @param projection A projection matrix to set on the renderer before [BatchTiledMapRenderer.beginRender].
* @param mapBoundary map render boundary.
* @param block inlined. Executed after [BatchTiledMapRenderer.beginRender] and before [BatchTiledMapRenderer.endRender].
*/
inline fun <T : BatchTiledMapRenderer> T.use(
projection: Matrix4,
mapBoundary: Rectangle,
block: (T) -> Unit
) = this.use(projection, mapBoundary.x, mapBoundary.y, mapBoundary.width, mapBoundary.height, block)

/**
* Automatically calls [BatchTiledMapRenderer.beginRender] and [BatchTiledMapRenderer.endRender].
* @param block inlined. Executed after [BatchTiledMapRenderer.beginRender] and before [BatchTiledMapRenderer.endRender].
*/
inline fun <T : BatchTiledMapRenderer> T.use(block: (T) -> Unit) {
this.beginInternal()

block(this)

this.endInternal()
}
Loading

0 comments on commit ddab0e7

Please sign in to comment.