Skip to content

Commit

Permalink
Released KTX 1.9.6-b7.
Browse files Browse the repository at this point in the history
  • Loading branch information
czyzby committed Aug 6, 2017
2 parents e806250 + 53da719 commit 58d95f8
Show file tree
Hide file tree
Showing 17 changed files with 224 additions and 307 deletions.
16 changes: 16 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@ previous task sequence (if it fails on the `closeAndPromoteRepository` task).
Name of the release should match `KTX $libVersion`. Copy latest [changelog](../CHANGELOG.md) entries to release
description. Note that a release is not necessary for snapshot versions.

### Updating dependencies

Dependencies versions are stored in the [gradle.properties](../gradle.properties) file. Snapshot releases should keep
all of the dependencies (outside of testing scope) up-to-date. Major dependencies updating:

- **LibGDX**: update `gdxVersion` in the properties file and LibGDX version in the tag on the top of the
[README.md](../README.md) file.
- **Kotlin**: update the `kotlinVersion` property and the Kotlin tag in the [README.md](../README.md).
- **Kotlin Coroutines**: update `kotlinCoroutinesVersion` property and the tag in the
`ktx-async` [README.md](../async/README.md).
- **Gradle**: run `gradle wrapper` in the root project folder. Make sure that the
[Gradle wrapper properties file](../gradle/wrapper/gradle-wrapper.properties) points the `all` Gradle release under
`distributionUrl` rather than just the binaries (`bin`).

All of the major dependencies updates should be added to the [changelog](../CHANGELOG.md).

### Adding a new KTX module

Adding a new library to KTX:
Expand Down
11 changes: 6 additions & 5 deletions .github/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
Project contributors listed chronologically.

* [@czyzby](https://github.com/czyzby)
* Author of most libraries, main maintainer.
* Author of most of the libraries, main maintainer.
* [@kotcrab](https://github.com/kotcrab)
* Author of [`VisUI` extension](../vis).
* Author of the [`VisUI` extension](../vis).
* [@MrPlow442](https://github.com/MrPlow442)
* Contributed LibGDX [collections](../collections) utilities.
* [@sreich](https://github.com/sreich)
* Contributed various utilities from [Ore Infinium](https://github.com/sreich/ore-infinium) project.
* [@raincole](https://github.com/raincole)
* Contributed LibGDX [collections](../collections) utilities.
* Provided insightful review of the [`Async`](../async) module.
Contributed LibGDX [collections](../collections) utilities.
* [@Jkly](https://github.com/Jkly)
* Author of [`Ashley` module](../ashley), as well as the [gdx-box2d-kotlin](https://github.com/Jkly/gdx-box2d-kotlin)
library, which inspired the `Box2D` **KTX** module. Provided insightful review of the [`Box2D`](../box2d) module.
* Author of the [`Ashley` module](../ashley).
* Author of the [gdx-box2d-kotlin](https://github.com/Jkly/gdx-box2d-kotlin) library, which inspired the `Box2D` **KTX** module.
* Provided insightful review of the [`Box2D`](../box2d) module. Contributed ray casting utilities.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
#### 1.9.6-b7

- **[UPDATE]** Updated to Kotlin 1.1.3-2.
- **[UPDATE]** Updated to Kotlin Coroutines 0.17.
- **[UPDATE]** Updated to Gradle 4.0.2.
- **[CHANGE]** (`ktx-app`) `KotlinApplication` was removed. Use `KtxApplicationAdapter` or `KtxGame` instead.
- **[CHANGE]** (`ktx-app`) `KtxGame` no longer supports fixed rendering time steps.
- **[FEATURE]** (`ktx-app`) Clearing screen on rendering is now optional when using `KtxGame`. Change `clearScreen` parameter to `false` to turn off screen clearing.
- **[FEATURE]** (`ktx-box2d`) `World.rayCast` extension methods that allow creating ray-cast callbacks with the Kotlin
lambda syntax. `KtxRayCastCallback` alias added to ease implementation of this utility.
- **[FEATURE]** (`ktx-box2d`) Added `RayCast` object with constants that can be returned by the custom `RayCastCallback` implementations.

#### 1.9.6-b6

- **[UPDATE]** Updated to Gradle 4.0.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![Travis CI](https://travis-ci.org/libktx/ktx.svg?branch=master)](https://travis-ci.org/libktx/ktx)
[![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)
[![Kotlin](https://img.shields.io/badge/kotlin-1.1.2--5-orange.svg)](http://kotlinlang.org/)
[![Kotlin](https://img.shields.io/badge/kotlin-1.1.3--2-orange.svg)](http://kotlinlang.org/)
[![LibGDX](https://img.shields.io/badge/libgdx-1.9.6-red.svg)](https://libgdx.badlogicgames.com/)

[![KTX](.github/ktx-logo.png "KTX")](http://libktx.github.io)
Expand Down
59 changes: 11 additions & 48 deletions app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,12 @@ by `ktx-app`.

#### `ApplicationListener` implementations

- `KotlinApplication` is an `ApplicationAdapter` equivalent. Additionally to providing empty implementations for all
optional `ApplicationListener` methods, it also automatically clears the screen and implements
[fixed rendering time steps](http://www.badlogicgames.com/forum/viewtopic.php?p=96803#p96803), allowing you to customize
time step duration and max time step with its constructor parameters. This is a solid base for your `ApplicationListener`
implementation if you like working from scratch.
- `KtxApplicationAdapter` is an `ApplicationListener` extension. Provides no-op implementations of all methods, without
being an abstract class like `com.badlogic.gdx.ApplicationAdapter`.
- `KtxGame` is a bit more opinionated `Game` equivalent that not only delegates all game events to the current `Screen`
instance, but also ensures non-nullability of screens, manages screen clearing and fixed rendering step, and maintains
screens collection, which allows to switch screens knowing only their concrete class. `KtxScreen` is an interface
extending `Screen` that provides no-op method implementations, making all methods optional to override.
instance, but also ensures non-nullability of screens, manages screen clearing, and maintains screens collection, which
allows switching screens while knowing only their concrete class. `KtxScreen` is an interface extending `Screen` that
provides no-op method implementations, making all methods optional to override.

#### `InputProcessor` implementations

Expand All @@ -48,41 +43,6 @@ calls before using batches and shader programs.

### Usage examples

Creating a simple `ApplicationListener` based on `KotlinApplication`:

```Kotlin
import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import ktx.app.KotlinApplication

class MyApplication : KotlinApplication() {
lateinit var batch: Batch
lateinit var font: BitmapFont

override fun create() {
batch = SpriteBatch()
font = BitmapFont()
}

override fun render(delta: Float) {
batch.begin()
font.draw(batch, "Hello world!", 100f, 100f)
batch.end()
}
}
```

Customizing fixed time steps of `KotlinApplication`:

```Kotlin
import ktx.app.KotlinApplication

class MyApplication : KotlinApplication(fixedTimeStep = 1f / 60f, maxDeltaTime = 1f / 15f) {
// ...
}
```

Implementing `KtxApplicationAdapter`:

```Kotlin
Expand Down Expand Up @@ -154,7 +114,7 @@ import ktx.app.KtxInputAdapter
class MyInputListener : KtxInputAdapter {
// Implementation of all ApplicationListener methods is optional. Handle the events you plan on supporting.

override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int) {
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
// Handle mouse click...
return true
}
Expand Down Expand Up @@ -184,10 +144,13 @@ val font = BitmapFont()
batch.use {
font.draw(it, "KTX!", 100f, 100f)
}
// The snippet above is an equivalent to:
// batch.begin()
// font.draw(batch, "KTX!", 100f, 100f)
// batch.end()

/* The snippet above is an equivalent to:
batch.begin()
font.draw(batch, "KTX!", 100f, 100f)
batch.end()
*/
```

Creating `Color` instances:
Expand Down
46 changes: 0 additions & 46 deletions app/src/main/kotlin/ktx/app/application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,6 @@ import com.badlogic.gdx.ApplicationListener
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.InputProcessor

/**
* Abstract implementation of [ApplicationListener] similar in scope to [com.badlogic.gdx.ApplicationAdapter]. Provides
* empty implementations of most optional methods. Handles screen clearing (with black color) and rendering on a fixed
* step value.
* @param fixedTimeStep minimum time (in seconds) between two consequent render calls. Might not match the delta time
* reported by [Gdx.graphics]. Defaults to 1/60.
* @param maxDeltaTime maximum time (in seconds) stored by the application listener for fixed time step calculations.
* Defaults to 1 second.
*/
abstract class KotlinApplication(protected val fixedTimeStep: Float = 1f / 60f,
protected val maxDeltaTime: Float = 1f) : ApplicationListener {
/** Internal control variable used to sure fixed time step durations. In seconds. Might not match the actual time
* since the last [render] call in case of subsequent [render] calls on devices unable to run the application at the
* chosen time step rate.*/
protected var timeSinceLastRender = 0f
private set

override fun resize(width: Int, height: Int) {
}

override final fun render() {
timeSinceLastRender = Math.min(timeSinceLastRender + Gdx.graphics.rawDeltaTime, maxDeltaTime)
while (timeSinceLastRender >= fixedTimeStep) {
timeSinceLastRender -= fixedTimeStep
clearScreen(0f, 0f, 0f, 1f)
render(fixedTimeStep)
}
}

/**
* Called by [render] function when the raw delta time reported by current [Gdx.graphics] reaches the chosen
* [fixedTimeStep] value. Ensures smooth rendering on fixed time step value.
* @param delta estimate of time since last method call.
*/
abstract fun render(delta: Float)

override fun pause() {
}

override fun resume() {
}

override fun dispose() {
}
}

/**
* Wrapping interface around [com.badlogic.gdx.ApplicationListener]. Provides no-op implementations of all methods,
* making them optional to implement.
Expand Down
16 changes: 7 additions & 9 deletions app/src/main/kotlin/ktx/app/game.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,18 @@ import com.badlogic.gdx.utils.ObjectMap
* manually. [ScreenType] generic type allows to users to use an extended specific base class (or interface) for all
* screens, without locking into [Screen].
*
* Since this is a [KotlinApplication] extension, it also handles screen clearing and fixed rendering time step. See
* [KotlinApplication] for more info.
*
* @param firstScreen will be immediately used by the application. Note that it cannot use any resources initiated by
* the LibGDX (like the OpenGL context) in the constructor, as the screen will be created before the application is
* launched. Defaults to an empty, mock-up screen implementation that should be replaced with the first [setScreen]
* method call in [create]. Note: `firstScreen` still has to be explicitly registered with [addScreen] if you want it to
* be accessible with [getScreen].
* @param fixedTimeStep see [KotlinApplication.fixedTimeStep].
* @param maxDeltaTime see [KotlinApplication.maxDeltaTime].
* @param clearScreen if true (the default), [clearScreen] will be called before screen rendering.
* @param ScreenType common base interface or class of all screens. Allows to use custom extended [Screen] API.
* @see KtxScreen
*/
open class KtxGame<ScreenType : Screen>(
firstScreen: ScreenType? = null,
fixedTimeStep: Float = 1f / 60f,
maxDeltaTime: Float = 1f) : KotlinApplication(fixedTimeStep, maxDeltaTime) {
private val clearScreen: Boolean = true) : KtxApplicationAdapter {
/** Holds references to all screens registered with [addScreen]. Allows to get a reference of the screen instance
* knowing only its type. */
protected val screens: ObjectMap<Class<out ScreenType>, ScreenType> = ObjectMap()
Expand All @@ -51,8 +46,11 @@ open class KtxGame<ScreenType : Screen>(
currentScreen.show()
}

override fun render(delta: Float) {
currentScreen.render(delta)
override fun render() {
if (clearScreen) {
clearScreen(0f, 0f, 0f, 1f)
}
currentScreen.render(Gdx.graphics.deltaTime)
}

override fun resize(width: Int, height: Int) {
Expand Down
117 changes: 0 additions & 117 deletions app/src/test/kotlin/ktx/app/applicationTest.kt
Original file line number Diff line number Diff line change
@@ -1,122 +1,5 @@
package ktx.app

import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.verify
import org.junit.After
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test

/**
* Tests [KotlinApplication] - KTX equivalent of [com.badlogic.gdx.ApplicationAdapter].
*/
class KotlinApplicationTest {
@Before
fun `set up OpenGL`() {
Gdx.gl20 = mock<GL20>()
Gdx.gl = Gdx.gl20
}

@Test
fun `should not render if delta time is lower than fixed time step`() {
Gdx.graphics = mockGraphicsWithDeltaTime(1 / 120f)
val application = MockKotlinApplication(fixedTimeStep = 1 / 30f)

application.render()

assertFalse(application.rendered)
}

@Test
fun `should render if delta time is equal to fixed time step`() {
Gdx.graphics = mockGraphicsWithDeltaTime(1 / 30f)
val application = MockKotlinApplication(fixedTimeStep = 1 / 30f)

application.render()

assertTrue(application.rendered)
assertEquals(1, application.renderedTimes)
}

@Test
fun `should render if delta time is higher than fixed time step`() {
Gdx.graphics = mockGraphicsWithDeltaTime(1 / 30f)
val application = MockKotlinApplication(fixedTimeStep = 1 / 60f)

application.render()

assertTrue(application.rendered)
assertEquals(2, application.renderedTimes)
}

@Test
fun `should render if delta times are collectively equal to or higher than fixed time step`() {
Gdx.graphics = mockGraphicsWithDeltaTime(1 / 50f)
val application = MockKotlinApplication(fixedTimeStep = 1 / 30f)

application.render() // 0.02 - 0.0
assertEquals(0, application.renderedTimes)

application.render() // 0.04 - 0.0(3)
assertEquals(1, application.renderedTimes)

application.render() // 0.06 - 0.0(3)
assertEquals(1, application.renderedTimes)

application.render() // 0.08 - 0.0(6)
assertEquals(2, application.renderedTimes)
}

@Test
fun `should clear screen on render`() {
Gdx.graphics = mockGraphicsWithDeltaTime(1 / 30f)
val application = MockKotlinApplication(fixedTimeStep = 1 / 30f)

application.render()

verify(Gdx.gl).glClearColor(0f, 0f, 0f, 1f)
verify(Gdx.gl).glClear(GL20.GL_COLOR_BUFFER_BIT)
}

@Test
fun `should not render more times than max delta time limit allows`() {
Gdx.graphics = mockGraphicsWithDeltaTime(1f)
val application = MockKotlinApplication(fixedTimeStep = 1 / 60f, maxDeltaTime = 5f / 60f)

application.render()

assertEquals(5, application.renderedTimes)
}

@After
fun `clear static LibGDX variables`() {
Gdx.graphics = null
Gdx.gl = null
Gdx.gl20 = null
}

/**
* Test implementation of [KotlinApplication]. Reports rendering data for tests.
*/
class MockKotlinApplication(fixedTimeStep: Float = 1f / 60f, maxDeltaTime: Float = 1f) :
KotlinApplication(fixedTimeStep, maxDeltaTime) {
var lastDelta = -1f
var rendered = false
var renderedTimes = 0

override fun create() {
}

override fun render(delta: Float) {
rendered = true
lastDelta = delta
renderedTimes++
}
}
}

@Suppress("unused")
class `should implement KtxApplicationAdapter with no methods overridden` : KtxApplicationAdapter {
// Guarantees all KtxApplicationAdapter methods are optional to implement.
Expand Down
Loading

0 comments on commit 58d95f8

Please sign in to comment.