diff --git a/android/assets/badlogic.jpg b/android/assets/badlogic.jpg deleted file mode 100644 index 4390da6..0000000 Binary files a/android/assets/badlogic.jpg and /dev/null differ diff --git a/android/assets/images/bucket.png b/android/assets/images/bucket.png new file mode 100644 index 0000000..0538dc3 Binary files /dev/null and b/android/assets/images/bucket.png differ diff --git a/android/assets/images/drop.png b/android/assets/images/drop.png new file mode 100644 index 0000000..8ce41f4 Binary files /dev/null and b/android/assets/images/drop.png differ diff --git a/android/assets/music/rain.mp3 b/android/assets/music/rain.mp3 new file mode 100644 index 0000000..74624d1 Binary files /dev/null and b/android/assets/music/rain.mp3 differ diff --git a/android/assets/sounds/drop.wav b/android/assets/sounds/drop.wav new file mode 100644 index 0000000..f63f553 Binary files /dev/null and b/android/assets/sounds/drop.wav differ diff --git a/build.gradle b/build.gradle index 9bf6785..bb9fbeb 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlinVersion = '1.3.41' + ext.kotlinVersion = '1.3.50' repositories { mavenLocal() @@ -27,6 +27,7 @@ allprojects { box2DLightsVersion = '1.4' ashleyVersion = '1.7.0' aiVersion = '1.8.0' + ktxVersion = '1.9.10-b2' } repositories { @@ -102,5 +103,6 @@ project(":core") { api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" api "com.badlogicgames.ashley:ashley:$ashleyVersion" api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + api "io.github.libktx:ktx-app:$ktxVersion" } } diff --git a/core/src/me/msoucy/ptures/PTures.kt b/core/src/me/msoucy/ptures/PTures.kt index 41f8833..905e235 100644 --- a/core/src/me/msoucy/ptures/PTures.kt +++ b/core/src/me/msoucy/ptures/PTures.kt @@ -1,30 +1,34 @@ package me.msoucy.ptures -import com.badlogic.gdx.ApplicationAdapter +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 : ApplicationAdapter() { - internal lateinit var batch: SpriteBatch - internal lateinit var img: Texture +class PTures : Game() { + public lateinit var batch: SpriteBatch + public lateinit var font: BitmapFont override fun create() { batch = SpriteBatch() - img = Texture("badlogic.jpg") + // use LibGDX's default Arial font + font = BitmapFont() + this.setScreen(MainMenuScreen(this)) } override fun render() { - Gdx.gl.glClearColor(1f, 0f, 0f, 1f) - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) - batch.begin() - batch.draw(img, 0f, 0f) - batch.end() + super.render() // important! } override fun dispose() { + this.getScreen().dispose() + batch.dispose() - img.dispose() + font.dispose() } } diff --git a/core/src/me/msoucy/ptures/screens/GameScreen.kt b/core/src/me/msoucy/ptures/screens/GameScreen.kt new file mode 100644 index 0000000..5be5d6f --- /dev/null +++ b/core/src/me/msoucy/ptures/screens/GameScreen.kt @@ -0,0 +1,161 @@ +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 +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 me.msoucy.ptures.PTures + +class GameScreen(val game: PTures) : Screen { + + private var dropImage: Texture + private var bucketImage: Texture + private var dropSound: Sound + private var rainMusic: Music + // 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 fun spawnRaindrop() { + var raindrop = Rectangle() + raindrop.x = MathUtils.random(0f, 800f - 64f) + raindrop.y = 480f + raindrop.width = 64f + raindrop.height = 64f + raindrops.add(raindrop) + 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) + + // 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.end() + + // process user input + if (Gdx.input.isTouched()) { + touchPos.set(Gdx.input.getX().toFloat(), + Gdx.input.getY().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() + } + if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) { + bucket.x += 200 * Gdx.graphics.getDeltaTime() + } + + // 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 + + // check if we need to create a new raindrop + 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() + if (raindrop.y + 64 < 0) + iter.remove() + + if (raindrop.overlaps(bucket)) { + dropsGathered++ + dropSound.play() + iter.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() + } + + override fun dispose() { + dropImage.dispose() + bucketImage.dispose() + dropSound.dispose() + rainMusic.dispose() + } +} \ No newline at end of file diff --git a/core/src/me/msoucy/ptures/screens/MainMenuScreen.kt b/core/src/me/msoucy/ptures/screens/MainMenuScreen.kt new file mode 100644 index 0000000..a26901a --- /dev/null +++ b/core/src/me/msoucy/ptures/screens/MainMenuScreen.kt @@ -0,0 +1,52 @@ +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 me.msoucy.ptures.PTures + +class MainMenuScreen(val game: PTures) : Screen { + private var camera: OrthographicCamera + + init { + camera = OrthographicCamera(); + camera.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.setProjectionMatrix(camera.combined); + + 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(); + } + } + + 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