Skip to content

Commit

Permalink
KTX 1.10.0-rc2 release. #413
Browse files Browse the repository at this point in the history
  • Loading branch information
czyzby committed Apr 24, 2022
2 parents 2a97861 + 9ace5ab commit 9716f90
Show file tree
Hide file tree
Showing 19 changed files with 661 additions and 25 deletions.
1 change: 1 addition & 0 deletions .github/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Project contributors listed chronologically.
* Tested KTX on iOS and documented RoboVM issue with Kotlin coroutines.
* [@RedGrapefruit09](https://github.com/RedGrapefruit09)
* Updated the project from Gradle 6 to Gradle 7.
* Contributed utilities to the [Ashley module](../ashley).
* [@vrudas](https://github.com/vrudas)
* Updated Kotlin dependencies.
* Contributed utilities to the [collections module](../collections).
Expand Down
16 changes: 14 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
_See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob/master/CHANGES)._

#### 1.10.0-rc2

- **[UPDATE]** Updated to Kotlin 1.6.21.
- **[UPDATE]** Updated to Kotlin Coroutines 1.6.1.
- **[FEATURE]** (`ktx-ashley`) Added utilities for working with Ashley's `EntityListener` interface:
- `EntityAdditionListener`: an interface extending `EntityListener` that only requires implementation of the `entityAdded` method.
- `EntityRemovalListener`: an interface extending `EntityListener` that only requires implementation of the `entityRemoved` method.
- `Engine.onEntityAdded` and `Engine.onEntityRemoved` extension methods that create entity listeners from lambdas.
- Wrappers for `Engine.onEntityAdded` and `Engine.onEntityRemoved` for `IteratingSystem`, `IntervalIteratingSystem`
and `SortedIteratingSystem` that use system's `Family` and `Engine` automatically.
- **[FEATURE]** (`ktx-script`) Added `KotlinScriptEngine.evaluateOn` methods that can execute scripts with a custom receiver.
- **[CHANGE]** (`ktx-script`) Generic libGDX and Java exceptions replaced with a custom `ScriptEngineException`.

#### 1.10.0-rc1

- **[UPDATE]** Updated to Kotlin 1.6.10.
- **[UPDATE]** Updated to Kotlin Coroutines 1.6.0.
- **[MISC]** Links to the libGDX wiki were updated.
- **[MISC]** Stable **KTX** releases are now marked with the `-rc` suffix.
- **[FEATURE]** (`ktx-actors`) Added `Tree.onSelectionChange` extension method that attaches a `ChangeListener` to a `Tree`.
- **[CHANGE]** (`ktx-scene2d`) The generic `Node` type of `KTreeWidget` was changed to `KNode<*>`.
- **[FEATURE]** Added `Tree.onSelectionChange` extension method that attaches a `ChangeListener` to a `Tree`.
- **[FEATURE]** (`ktx-script`) Added a new module with `KotlinScriptEngine` evaluating Kotlin scripts in runtime.
- `evaluate(String)`: compiles and executes a script passed as a string.
- `evaluate(FileHandle)`: compiles and executes a script from the selected file.
Expand All @@ -19,7 +32,6 @@ _See also: [the official libGDX changelog](https://github.com/libgdx/libgdx/blob
- `import(String, String?)`: adds an import to the script context. Accepts optional alias.
- `importAll(vararg String)`, `importAll(Iterable<String>)`: adds the selected imports to the script context.
- `setPackage(String)`: sets the package for the scripts.
- `onItemClick(Node)`: adds a listener that gets invoked when `Node` in a `Tree` gets clicked.
- **[CHANGE]** (`ktx-vis`) The generic `Node` type of `KVisTree` was changed to `KNode<*>`.

#### 1.10.0-b4
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[![GitHub Build](https://github.com/libktx/ktx/workflows/build/badge.svg)](https://github.com/libktx/ktx/actions?query=workflow%3Abuild)
[![Kotlin](https://img.shields.io/badge/kotlin-1.6.10-orange.svg)](http://kotlinlang.org/)
[![Kotlin](https://img.shields.io/badge/kotlin-1.6.21-orange.svg)](http://kotlinlang.org/)
[![libGDX](https://img.shields.io/badge/libgdx-1.10.0-red.svg)](https://libgdx.com/)
[![Maven Central](https://img.shields.io/maven-central/v/io.github.libktx/ktx-async.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.github.libktx%22)

Expand Down
98 changes: 97 additions & 1 deletion ashley/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Utilities and type-safe builders for the [Ashley](https://github.com/libgdx/ashl
### Why?

Since [Ashley](https://github.com/libgdx/ashley) contains many generic methods consuming `Class` instances, Kotlin can
provide a pleasant DSL via inlined methods reified generic types. Additionally, creating `Entities` and their respective
provide a pleasant DSL via inlined methods with reified generic types. Additionally, creating `Entities` and their respective
`Components` can result in a lot of declarative-style code which is greatly improved by an easily readable type-safe
builder DSL.

Expand All @@ -29,6 +29,14 @@ builder DSL.
- `Entity.plusAssign` (`+=`) operator allows to add a `Component` to an existing `Entity`.
- Top-level and `Builder` extension DSL methods for constructing `Family` builders with `KClass` instances: `oneOf`,
`allOf`, `exclude`.
- `EntityAdditionListener` is an interface extending `EntityListener` which provides improved typing, as well as empty
implementations of event listening methods except for `entityAdded`.
- `EntityRemovalListener` is an interface extending `EntityListener` which provides improved typing, as well as empty
implementations of event listening methods except for `entityRemoved` event.
- `Engine.onEntityAdded` and `Engine.onEntityRemoved` extension methods make it possible to attach an entity listener
created from a passed with a lambda and add them to the `Engine` immediately.
- Wrappers for `Engine.onEntityAdded` and `Engine.onEntityRemoved` for `IteratingSystem`, `IntervalIteratingSystem` and
`SortedIteratingSystem` that use system's `Family` and `Engine` automatically.
- `mapperFor` factory method allows creating `ComponentMapper` instances.
- `Mapper` abstract class can be extended by `companion object`s of `Component` to obtain `ComponentMapper` instances.

Expand Down Expand Up @@ -289,6 +297,94 @@ class C: Component
object CMapper: Mapper<C>()
```

Creating an `EntitySystem` that doubles as a listener of entity addition events:

```kotlin
import com.badlogic.ashley.core.Entity
import com.badlogic.ashley.core.EntitySystem
import ktx.ashley.EntityAdditionListener

class MySystem : EntitySystem(), EntityAdditionListener {
override fun entityAdded(entity: Entity) {
println("Entity added: $entity")
}
}

```

Creating, storing and removing `EntityAdditionListener`s and `EntityRemovalListener`s with lambdas:

```kotlin
import com.badlogic.ashley.core.Engine
import ktx.ashley.onEntityAdded
import ktx.ashley.onEntityRemoved

val engine = Engine()

fun registerListeners() {
val additionListener = engine.onEntityAdded { entity ->
println("Entity added: $entity")
}

val removalListener = engine.onEntityRemoved { entity ->
println("Entity removed: $entity")
}

// If you need to remove such listeners later,
// retain a reference to them and call
// Engine.removeEntityListener when necessary:
engine.removeEntityListener(additionListener)
engine.removeEntityListener(removalListener)
}
```

Managing `EntityAdditionListener`s and `EntityRemovalListener`s with an `IteratingSystem`'s `Family`:

```kotlin
import com.badlogic.ashley.core.Component
import com.badlogic.ashley.core.Engine
import com.badlogic.ashley.core.Entity
import com.badlogic.ashley.systems.IteratingSystem
import ktx.ashley.EntityAdditionListener
import ktx.ashley.EntityRemovalListener
import ktx.ashley.allOf
import ktx.ashley.onEntityAdded
import ktx.ashley.onEntityRemoved

class ExampleComponent : Component

// Listeners can be added to all Ashley iterating systems such as
// IteratingSystem, IntervalIteratingSystem or SortedIteratingSystem.
class MyIteratingSystem : IteratingSystem(allOf(ExampleComponent::class).get()) {
// You can retain references to your listeners to remove them from the engine.
private lateinit var additionListener: EntityAdditionListener
private lateinit var removalListener: EntityRemovalListener

override fun addedToEngine(engine: Engine) {
super.addedToEngine(engine)

additionListener = onEntityAdded { entity ->
// Handle entities with an ExampleComponent being added.
}

removalListener = onEntityRemoved { entity ->
// Handle entities with an ExampleComponent being removed.
}
}

override fun processEntity(entity: Entity, deltaTime: Float) {
// System logic goes here.
}

override fun removedFromEngine(engine: Engine) {
super.removedFromEngine(engine)

engine.removeEntityListener(additionListener)
engine.removeEntityListener(removalListener)
}
}
```

#### Additional documentation

- [Ashley repository.](https://github.com/libgdx/ashley)
Expand Down
158 changes: 158 additions & 0 deletions ashley/src/main/kotlin/ktx/ashley/listeners.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package ktx.ashley

import com.badlogic.ashley.core.Engine
import com.badlogic.ashley.core.Entity
import com.badlogic.ashley.core.EntityListener
import com.badlogic.ashley.core.Family
import com.badlogic.ashley.systems.IntervalIteratingSystem
import com.badlogic.ashley.systems.IteratingSystem
import com.badlogic.ashley.systems.SortedIteratingSystem

/**
* An [EntityListener] only requiring an implementation of the [entityAdded] method.
*
* An empty implementation is provided for the [entityRemoved] method. By default, the entity removal event is ignored.
*
* To handle more types of events, consider implementing [EntityListener] directly.
*/
interface EntityAdditionListener : EntityListener {
/**
* Invoked when a matching [Entity] is added to the [Engine].
*
* See [EntityListener.entityAdded].
*/
override fun entityAdded(entity: Entity)

override fun entityRemoved(entity: Entity) = Unit
}

/**
* An [EntityListener] only requiring an implementation of the [entityRemoved] method.
*
* An empty implementation is provided for the [entityAdded] method. By default, the entity addition event is ignored.
*
* To handle more types of events, consider implementing [EntityListener] directly.
*/
interface EntityRemovalListener : EntityListener {
/**
* Invoked when a matching [Entity] is removed from the [Engine].
*
* See [EntityListener.entityRemoved].
*/
override fun entityRemoved(entity: Entity)

override fun entityAdded(entity: Entity) = Unit
}

// A family that matches any entity in the engine. Used to make Family an optional parameter in the API.
@PublishedApi internal val anyFamily = Family.all().get()

/**
* Adds an [EntityAdditionListener] to this [Engine] and returns a reference to the new listener instance.
* The listener calls [onAdded] lambda every time an entity addition event is triggered.
*
* The [family] parameter allows targeting a specific subset of entities. By default, [anyFamily] is used,
* matching every entity within the engine.
*
* The [priority] argument affects the order in which the listeners are triggered. Lower value means higher
* priority.
*
* To remove this [EntityListener] from the [Engine] afterwards, retain the reference returned by
* this method and pass it to [Engine.removeEntityListener].
*/
inline fun Engine.onEntityAdded(
family: Family = anyFamily,
priority: Int = 0,
crossinline onAdded: (entity: Entity) -> Unit
): EntityAdditionListener {
val listener = object : EntityAdditionListener {
override fun entityAdded(entity: Entity) {
onAdded.invoke(entity)
}
}

addEntityListener(family, priority, listener)
return listener
}

/**
* Adds an [EntityRemovalListener] to this [Engine] and returns a reference to the new listener instance.
* The listener calls [onRemoved] lambda every time an entity addition event is triggered.
*
* The [family] parameter allows targeting a specific subset of entities. By default, [anyFamily] is used,
* matching every entity within the engine.
*
* The [priority] argument affects the order in which the listeners are triggered. Lower value means higher
* priority.
*
* To remove this [EntityListener] from the [Engine] afterwards, retain the reference returned by this method
* and pass it to [Engine.removeEntityListener].
*/
inline fun Engine.onEntityRemoved(
family: Family = anyFamily,
priority: Int = 0,
crossinline onRemoved: (entity: Entity) -> Unit
): EntityRemovalListener {
val listener = object : EntityRemovalListener {
override fun entityRemoved(entity: Entity) {
onRemoved.invoke(entity)
}
}

addEntityListener(family, priority, listener)
return listener
}

/**
* A wrapper for [Engine.onEntityAdded] that uses this [IteratingSystem]'s [Family]
* as a filter for the [EntityAdditionListener].
*/
inline fun IteratingSystem.onEntityAdded(
priority: Int = 0,
crossinline onAdded: (entity: Entity) -> Unit
): EntityAdditionListener = engine.onEntityAdded(family, priority, onAdded)

/**
* A wrapper for [Engine.onEntityRemoved] that uses this [IteratingSystem]'s [Family]
* as a filter for the [EntityRemovalListener].
*/
inline fun IteratingSystem.onEntityRemoved(
priority: Int = 0,
crossinline onRemoved: (entity: Entity) -> Unit
): EntityRemovalListener = engine.onEntityRemoved(family, priority, onRemoved)

/**
* A wrapper for [Engine.onEntityAdded] that uses this [IntervalIteratingSystem]'s [Family]
* as a filter for the [EntityAdditionListener].
*/
inline fun IntervalIteratingSystem.onEntityAdded(
priority: Int = 0,
crossinline onAdded: (entity: Entity) -> Unit
): EntityAdditionListener = engine.onEntityAdded(family, priority, onAdded)

/**
* A wrapper for [Engine.onEntityRemoved] that uses this [IntervalIteratingSystem]'s [Family]
* as a filter for the [EntityRemovalListener].
*/
inline fun IntervalIteratingSystem.onEntityRemoved(
priority: Int = 0,
crossinline onRemoved: (entity: Entity) -> Unit
): EntityRemovalListener = engine.onEntityRemoved(family, priority, onRemoved)

/**
* A wrapper for [Engine.onEntityAdded] that uses this [SortedIteratingSystem]'s [Family]
* as a filter for the [EntityAdditionListener].
*/
inline fun SortedIteratingSystem.onEntityAdded(
priority: Int = 0,
crossinline onAdded: (entity: Entity) -> Unit
): EntityAdditionListener = engine.onEntityAdded(family, priority, onAdded)

/**
* A wrapper for [Engine.onEntityRemoved] that uses this [SortedIteratingSystem]'s [Family]
* as a filter for the [EntityRemovalListener].
*/
inline fun SortedIteratingSystem.onEntityRemoved(
priority: Int = 0,
crossinline onRemoved: (entity: Entity) -> Unit
): EntityRemovalListener = engine.onEntityRemoved(family, priority, onRemoved)
Loading

0 comments on commit 9716f90

Please sign in to comment.