diff --git a/build.gradle b/build.gradle index bb9fbeb..f2c7aef 100644 --- a/build.gradle +++ b/build.gradle @@ -104,5 +104,7 @@ project(":core") { api "com.badlogicgames.ashley:ashley:$ashleyVersion" api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" api "io.github.libktx:ktx-app:$ktxVersion" + api "io.github.libktx:ktx-collections:$ktxVersion" + api "io.github.libktx:ktx-graphics:$ktxVersion" } } diff --git a/core/src/me/msoucy/ptures/PTures.kt b/core/src/me/msoucy/ptures/PTures.kt index 905e235..79d6978 100644 --- a/core/src/me/msoucy/ptures/PTures.kt +++ b/core/src/me/msoucy/ptures/PTures.kt @@ -1,34 +1,25 @@ package me.msoucy.ptures -import com.badlogic.gdx.Game -import com.badlogic.gdx.Gdx -import com.badlogic.gdx.graphics.GL20 -import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.g2d.BitmapFont import com.badlogic.gdx.graphics.g2d.SpriteBatch import ktx.app.KtxGame import ktx.app.KtxScreen import me.msoucy.ptures.screens.MainMenuScreen -class PTures : Game() { - public lateinit var batch: SpriteBatch - public lateinit var font: BitmapFont +class PTures : KtxGame() { + val batch by lazy { SpriteBatch() } + // use LibGDX's default Arial font + val font by lazy { BitmapFont() } override fun create() { - batch = SpriteBatch() - // use LibGDX's default Arial font - font = BitmapFont() - this.setScreen(MainMenuScreen(this)) - } - - override fun render() { - super.render() // important! + addScreen(MainMenuScreen(this)) + setScreen() + super.create() } override fun dispose() { - this.getScreen().dispose() - batch.dispose() font.dispose() + super.dispose() } } diff --git a/core/src/me/msoucy/ptures/screens/GameScreen.kt b/core/src/me/msoucy/ptures/screens/GameScreen.kt index 5be5d6f..e508657 100644 --- a/core/src/me/msoucy/ptures/screens/GameScreen.kt +++ b/core/src/me/msoucy/ptures/screens/GameScreen.kt @@ -1,12 +1,7 @@ package me.msoucy.ptures.screens -import com.badlogic.gdx.Game import com.badlogic.gdx.Gdx import com.badlogic.gdx.Input -import com.badlogic.gdx.Screen -import com.badlogic.gdx.audio.Music -import com.badlogic.gdx.audio.Sound -import com.badlogic.gdx.graphics.GL20 import com.badlogic.gdx.graphics.OrthographicCamera import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.math.MathUtils @@ -14,142 +9,87 @@ import com.badlogic.gdx.math.Rectangle import com.badlogic.gdx.math.Vector3 import com.badlogic.gdx.utils.Array import com.badlogic.gdx.utils.TimeUtils +import ktx.app.KtxScreen +import ktx.collections.iterate +import ktx.graphics.use import me.msoucy.ptures.PTures -class GameScreen(val game: PTures) : Screen { +class GameScreen(val game: PTures) : KtxScreen { - private var dropImage: Texture - private var bucketImage: Texture - private var dropSound: Sound - private var rainMusic: Music + private val dropImage = Texture(Gdx.files.internal("images/drop.png")) + private val bucketImage = Texture(Gdx.files.internal("images/bucket.png")) + private val dropSound = Gdx.audio.newSound(Gdx.files.internal("sounds/drop.wav")) + private val rainMusic = Gdx.audio.newMusic(Gdx.files.internal("music/rain.mp3")).apply { isLooping = true } // The camera ensures we can render using our target resolution of 800x480 // pixels no matter what the screen resolution is. - private var camera: OrthographicCamera - private var bucket: Rectangle - private var touchPos: Vector3 - private var raindrops: Array // gdx, not Kotlin Array - private var lastDropTime: Long = 0L - private var dropsGathered: Int = 0 + private val camera = OrthographicCamera().apply { setToOrtho(false, 800f, 480f) } + private val bucket = Rectangle(800f / 2f - 64f / 2f, 20f, 64f, 64f) + private val touchPos = Vector3() + private val raindrops = Array() // gdx, not Kotlin Array + private var lastDropTime = 0L + private var dropsGathered = 0 private fun spawnRaindrop() { - var raindrop = Rectangle() - raindrop.x = MathUtils.random(0f, 800f - 64f) - raindrop.y = 480f - raindrop.width = 64f - raindrop.height = 64f - raindrops.add(raindrop) + raindrops.add(Rectangle(MathUtils.random(0f, 800f - 64f), 480f, 64f, 64f)) lastDropTime = TimeUtils.nanoTime() } - // initializer block - init { - // load the images for the droplet & bucket, 64x64 pixels each - dropImage = Texture(Gdx.files.internal("images/drop.png")) - bucketImage = Texture(Gdx.files.internal("images/bucket.png")) - - // load the drop sound effect and the rain background music - dropSound = Gdx.audio.newSound(Gdx.files.internal("sounds/drop.wav")) - rainMusic = Gdx.audio.newMusic(Gdx.files.internal("music/rain.mp3")) - rainMusic.setLooping(true) - - // create the camera - camera = OrthographicCamera() - camera.setToOrtho(false, 800f, 480f) - - // create a Rectangle to logically represent the bucket - bucket = Rectangle() - bucket.x = 800f / 2f - 64f / 2f // center the bucket horizontally - bucket.y = 20f // bottom left bucket corner is 20px above - // bottom screen edge - bucket.width = 64f - bucket.height = 64f - - // create the touchPos to store mouse click position - touchPos = Vector3() - - // create the raindrops array and spawn the first raindrop - raindrops = Array() - spawnRaindrop() - } - override fun render(delta: Float) { - // clear the screen with a dark blue color. The arguments to glClearColor - // are the RGB and alpha component in the range [0,1] of the color to - // be used to clear the screen. - Gdx.gl.glClearColor(0f, 0f, 0.2f, 1f) - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) - // generally good practice to update the camera's matrices once per frame camera.update() // tell the SpriteBatch to render in the coordinate system specified by the camera. - game.batch.setProjectionMatrix(camera.combined) + game.batch.projectionMatrix = camera.combined // begin a new batch and draw the bucket and all drops - game.batch.begin() - game.font.draw(game.batch, "Drops Collected: " + dropsGathered, 0f, 480f) - game.batch.draw(bucketImage, bucket.x, bucket.y, - bucket.width, bucket.height) - for (raindrop in raindrops) { - game.batch.draw(dropImage, raindrop.x, raindrop.y) + game.batch.use { batch -> + game.font.draw(batch, "Drops Collected: " + dropsGathered, 0f, 480f) + batch.draw(bucketImage, bucket.x, bucket.y, bucket.width, bucket.height) + raindrops.forEach { r -> batch.draw(dropImage, r.x, r.y) } } - game.batch.end() // process user input - if (Gdx.input.isTouched()) { - touchPos.set(Gdx.input.getX().toFloat(), - Gdx.input.getY().toFloat(), - 0f) + if (Gdx.input.isTouched) { + touchPos.set(Gdx.input.x.toFloat(), Gdx.input.y.toFloat(),0f) camera.unproject(touchPos) bucket.x = touchPos.x - 64f / 2f } if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) { // getDeltaTime returns the time passed between the last and the current frame in seconds - bucket.x -= 200 * Gdx.graphics.getDeltaTime() + bucket.x -= 200 * delta } if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) { - bucket.x += 200 * Gdx.graphics.getDeltaTime() + bucket.x += 200 * delta } // make sure the bucket stays within the screen bounds - if (bucket.x < 0f) - bucket.x = 0f - if (bucket.x > 800f - 64f) - bucket.x = 800f - 64f + bucket.x = MathUtils.clamp(bucket.x, 0f, 800f - 64f) // check if we need to create a new raindrop - if (TimeUtils.nanoTime() - lastDropTime > 1_000_000_000L) + if (TimeUtils.nanoTime() - lastDropTime > 1_000_000_000L) { spawnRaindrop() + } // move the raindrops, remove any that are beneath the bottom edge of the // screen or that hit the bucket. In the latter case, play back a sound // effect also - var iter = raindrops.iterator() - while (iter.hasNext()) { - var raindrop = iter.next() - raindrop.y -= 200 * Gdx.graphics.getDeltaTime() + raindrops.iterate { raindrop, iterator -> + raindrop.y -= 200 * delta if (raindrop.y + 64 < 0) - iter.remove() + iterator.remove() if (raindrop.overlaps(bucket)) { dropsGathered++ dropSound.play() - iter.remove() + iterator.remove() } } } - // the following overrides are no-ops, unused in tutorial, but needed in - // order to compile a class that implements Screen - override fun resize(width: Int, height: Int) {} - - override fun hide() {} - override fun pause() {} - override fun resume() {} - override fun show() { // start the playback of the background music when the screen is shown rainMusic.play() + spawnRaindrop() } override fun dispose() { diff --git a/core/src/me/msoucy/ptures/screens/MainMenuScreen.kt b/core/src/me/msoucy/ptures/screens/MainMenuScreen.kt index a26901a..2b21f57 100644 --- a/core/src/me/msoucy/ptures/screens/MainMenuScreen.kt +++ b/core/src/me/msoucy/ptures/screens/MainMenuScreen.kt @@ -1,52 +1,30 @@ package me.msoucy.ptures.screens import com.badlogic.gdx.Gdx -import com.badlogic.gdx.Screen -import com.badlogic.gdx.graphics.GL20 import com.badlogic.gdx.graphics.OrthographicCamera +import ktx.app.KtxScreen +import ktx.graphics.use import me.msoucy.ptures.PTures -class MainMenuScreen(val game: PTures) : Screen { - private var camera: OrthographicCamera - - init { - camera = OrthographicCamera(); - camera.setToOrtho(false, 800f, 480f); +class MainMenuScreen(val game: PTures) : KtxScreen { + private val camera = OrthographicCamera().apply { + setToOrtho(false, 800f, 480f) } override fun render(delta: Float) { - Gdx.gl.glClearColor(0f, 0f, 0.2f, 1f); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + camera.update() + game.batch.projectionMatrix = camera.combined - camera.update(); - game.batch.setProjectionMatrix(camera.combined); + game.batch.use { + game.font.draw(it, "Welcome to Drop!!! ", 100f, 150f) + game.font.draw(it, "Tap anywhere to begin!", 100f, 100f) + } - game.batch.begin(); - game.font.draw(game.batch, "Welcome to Drop!!! ", 100f, 150f); - game.font.draw(game.batch, "Tap anywhere to begin!", 100f, 100f); - game.batch.end(); - - if (Gdx.input.isTouched()) { - game.setScreen(GameScreen(game)); - dispose(); + if (Gdx.input.isTouched) { + game.addScreen(GameScreen(game)) + game.setScreen() + game.removeScreen() + dispose() } } - - override fun hide() { - } - - override fun show() { - } - - override fun pause() { - } - - override fun resume() { - } - - override fun resize(width: Int, height: Int) { - } - - override fun dispose() { - } } \ No newline at end of file