From cfebae281d772fa226b3f0ce255c23b23661ca2b97a8fe19950a1f2288586d5a Mon Sep 17 00:00:00 2001 From: snap Date: Fri, 6 Feb 2026 13:12:12 +0000 Subject: [PATCH 1/2] Work through the Simple Game Extended section --- .../src/main/kotlin/com/badlogic/drop/Drop.kt | 29 ++++++++++ .../kotlin/com/badlogic/drop/GameScreen.kt | 34 ++++++++++++ .../com/badlogic/drop/MainMenuScreen.kt | 54 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Drop.kt create mode 100644 Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/GameScreen.kt create mode 100644 Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/MainMenuScreen.kt diff --git a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Drop.kt b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Drop.kt new file mode 100644 index 0000000..155599c --- /dev/null +++ b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Drop.kt @@ -0,0 +1,29 @@ +package com.badlogic.drop + +import com.badlogic.gdx.Game +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.graphics.g2d.BitmapFont +import com.badlogic.gdx.graphics.g2d.SpriteBatch +import com.badlogic.gdx.utils.viewport.FitViewport + +class Drop : Game() { + val batch: SpriteBatch = SpriteBatch() + val viewport: FitViewport = FitViewport(8f, 5f) // We put viewport above font for the .appy scope function + val font: BitmapFont = BitmapFont().apply { + setUseIntegerPositions(false) + data.scale(viewport.worldHeight / Gdx.graphics.height) + } + + override fun create(): Unit { + this.screen = MainMenuScreen(this) + } + + override fun render() { + super.render() + } + + override fun dispose() { + batch.dispose() + font.dispose() + } +} diff --git a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/GameScreen.kt b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/GameScreen.kt new file mode 100644 index 0000000..2b1fc71 --- /dev/null +++ b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/GameScreen.kt @@ -0,0 +1,34 @@ +package com.badlogic.drop + +import com.badlogic.gdx.Screen + +class GameScreen(val newGame: Drop) : Screen { + override fun show() { + TODO("Not yet implemented") + } + + override fun render(delta: Float) { + TODO("Not yet implemented") + } + + override fun resize(width: Int, height: Int) { + TODO("Not yet implemented") + } + + override fun pause() { + TODO("Not yet implemented") + } + + override fun resume() { + TODO("Not yet implemented") + } + + override fun hide() { + TODO("Not yet implemented") + } + + override fun dispose() { + TODO("Not yet implemented") + } + +} diff --git a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/MainMenuScreen.kt b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/MainMenuScreen.kt new file mode 100644 index 0000000..5e0043d --- /dev/null +++ b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/MainMenuScreen.kt @@ -0,0 +1,54 @@ +package com.badlogic.drop + +import com.badlogic.gdx.Screen +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.utils.ScreenUtils + +class MainMenuScreen(val newGame: Drop) : Screen { + + val game: Drop = newGame + + override fun show() { + TODO("Not yet implemented") + } + + override fun render(delta: Float) { + ScreenUtils.clear(Color.BLACK) + + game.viewport.apply() + game.batch.projectionMatrix = game.viewport.camera.combined + + game.batch.begin() + + game.font.draw(game.batch, "Wekcine to Drop!!!", 1f, 1.5f) + game.font.draw(game.batch, "Tap anywhere to begin!", 1f, 1f) + + game.batch.end() + + if (Gdx.input.isTouched) { + game.screen = GameScreen(game) + } + + } + + override fun resize(width: Int, height: Int) { + TODO("Not yet implemented") + } + + override fun pause() { + TODO("Not yet implemented") + } + + override fun resume() { + TODO("Not yet implemented") + } + + override fun hide() { + TODO("Not yet implemented") + } + + override fun dispose() { + TODO("Not yet implemented") + } +} From 5c89bd0d94aeaf2f6005d604d10ae2792235eb3af73dcbbfa004346f74450401 Mon Sep 17 00:00:00 2001 From: snap Date: Sat, 7 Feb 2026 00:11:05 +0000 Subject: [PATCH 2/2] Finish the Simple Game Extended section --- .../badlogic/drop/android/AndroidLauncher.kt | 4 +- .../src/main/kotlin/com/badlogic/drop/Drop.kt | 17 ++- .../kotlin/com/badlogic/drop/GameScreen.kt | 138 ++++++++++++++++-- .../src/main/kotlin/com/badlogic/drop/Main.kt | 138 ------------------ .../com/badlogic/drop/MainMenuScreen.kt | 42 +++--- 5 files changed, 156 insertions(+), 183 deletions(-) delete mode 100644 Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Main.kt diff --git a/Exercises/Drop/android/src/main/kotlin/com/badlogic/drop/android/AndroidLauncher.kt b/Exercises/Drop/android/src/main/kotlin/com/badlogic/drop/android/AndroidLauncher.kt index 5f6f1d9..b9b115a 100644 --- a/Exercises/Drop/android/src/main/kotlin/com/badlogic/drop/android/AndroidLauncher.kt +++ b/Exercises/Drop/android/src/main/kotlin/com/badlogic/drop/android/AndroidLauncher.kt @@ -1,16 +1,16 @@ package com.badlogic.drop.android import android.os.Bundle +import com.badlogic.drop.Drop import com.badlogic.gdx.backends.android.AndroidApplication import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration -import com.badlogic.drop.Main /** Launches the Android application. */ class AndroidLauncher : AndroidApplication() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - initialize(Main(), AndroidApplicationConfiguration().apply { + initialize(Drop(), AndroidApplicationConfiguration().apply { // Configure your application here. useImmersiveMode = true // Recommended, but not required. }) diff --git a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Drop.kt b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Drop.kt index 155599c..3e08317 100644 --- a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Drop.kt +++ b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Drop.kt @@ -7,14 +7,19 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.utils.viewport.FitViewport class Drop : Game() { - val batch: SpriteBatch = SpriteBatch() - val viewport: FitViewport = FitViewport(8f, 5f) // We put viewport above font for the .appy scope function - val font: BitmapFont = BitmapFont().apply { - setUseIntegerPositions(false) - data.scale(viewport.worldHeight / Gdx.graphics.height) - } + lateinit var batch: SpriteBatch + lateinit var font: BitmapFont + //lateinit var viewport: FitViewport // Use camera instead of viewport override fun create(): Unit { + batch = SpriteBatch() + //viewport = FitViewport(8f, 5f) + /*font = BitmapFont().apply { + setUseIntegerPositions(false) + data.scale(viewport.worldHeight / Gdx.graphics.height) + }*/ + font = BitmapFont() + this.screen = MainMenuScreen(this) } diff --git a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/GameScreen.kt b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/GameScreen.kt index 2b1fc71..cc78c47 100644 --- a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/GameScreen.kt +++ b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/GameScreen.kt @@ -1,34 +1,146 @@ package com.badlogic.drop +import com.badlogic.gdx.Gdx import com.badlogic.gdx.Screen +import com.badlogic.gdx.graphics.Texture +import com.badlogic.gdx.graphics.OrthographicCamera +import com.badlogic.gdx.Gdx.audio +import com.badlogic.gdx.Input +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.g2d.Sprite +import com.badlogic.gdx.math.MathUtils +import com.badlogic.gdx.math.Rectangle +import com.badlogic.gdx.math.Vector2 +import com.badlogic.gdx.math.Vector3 +import com.badlogic.gdx.utils.ScreenUtils +import ktx.assets.toInternalFile + +class GameScreen(val game: Drop) : Screen { + val camera = OrthographicCamera().apply { setToOrtho(false, 800f, 480f) } + + val backgroundTexture = Texture("background.png") + val bucketTexture = Texture("bucket.png") + val dropTexture = Texture("drop.png") + val dropSound = audio.newSound("drop.mp3".toInternalFile()) + val music = audio.newMusic("music.mp3".toInternalFile()).apply { + isLooping = true + volume = 0.5f + } + val bucketSprite = Sprite(bucketTexture).apply { setSize(64f, 64f) } + val touchPos = Vector3() + val dropSprites = mutableListOf() + val dropSpeed = -128f + var dropTimer = 0f + val bucketRectangle = Rectangle() + val dropRectangle = Rectangle() + var dropsGathered = 0 -class GameScreen(val newGame: Drop) : Screen { override fun show() { - TODO("Not yet implemented") + music.play() } override fun render(delta: Float) { - TODO("Not yet implemented") + input() + logic() + draw() } - override fun resize(width: Int, height: Int) { - TODO("Not yet implemented") + private fun input() { + val speed = 4f + val delta: Float = Gdx.graphics.deltaTime + + if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) { + bucketSprite.translateX(speed * delta) + } + if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) { + bucketSprite.translateX(-speed * delta) + } + + if (Gdx.input.isTouched) { + touchPos.set(Gdx.input.x.toFloat(), Gdx.input.y.toFloat(), 0f) + camera.unproject(touchPos) + bucketSprite.setCenterX(touchPos.x) + } } - override fun pause() { - TODO("Not yet implemented") + private fun logic() { + val worldWidth: Float = camera.viewportWidth + val worldHeight: Float = camera.viewportHeight + val bucketWidth: Float = bucketSprite.width + val bucketHeight: Float = bucketSprite.height + val delta: Float = Gdx.graphics.deltaTime + + bucketSprite.x = MathUtils.clamp(bucketSprite.x, 0f, worldWidth - bucketWidth) + bucketRectangle.set(bucketSprite.x, bucketSprite.y, bucketWidth, bucketHeight) + + for (dropSprite in dropSprites.reversed()) { + val dropWidth: Float = dropSprite.width + val dropHeight: Float = dropSprite.height + + dropSprite.translateY(dropSpeed * delta * (MathUtils.clamp((dropsGathered.toFloat() + 1f) / 5f, 1f, Float.MAX_VALUE))) + dropRectangle.set(dropSprite.x, dropSprite.y, dropWidth, dropHeight) + + if (dropSprite.y < -dropHeight) dropSprites.remove(dropSprite) + else if (bucketRectangle.overlaps(dropRectangle)) { + dropsGathered++ + dropSprites.remove(dropSprite) + dropSound.play() + } + } + + dropTimer += delta + if (dropTimer > 1f) { + dropTimer = 0f + createDroplet() + } } - override fun resume() { - TODO("Not yet implemented") + private fun draw() { + ScreenUtils.clear(Color.BLACK) + + camera.update() + game.batch.projectionMatrix = camera.combined + + game.batch.begin() + val worldWidth: Float = camera.viewportWidth + val worldHeight: Float = camera.viewportHeight + game.batch.draw(backgroundTexture, 0f, 0f, worldWidth, worldHeight) + bucketSprite.draw(game.batch) + + game.font.draw(game.batch, "Drops collected: $dropsGathered", 0f, worldHeight) + + for (dropSprite in dropSprites) dropSprite.draw(game.batch) + + game.batch.end() } - override fun hide() { - TODO("Not yet implemented") + private fun createDroplet() { + val dropWidth = 64f + val dropHeight = 64f + val worldWidth: Float = camera.viewportWidth + val worldHeight: Float = camera.viewportHeight + + val dropSprite = Sprite(dropTexture).apply { + setSize(dropWidth, dropHeight) + x = MathUtils.random(0f, worldWidth - dropWidth) + y = worldHeight + } + dropSprites.add(dropSprite) } + override fun resize(width: Int, height: Int) = Unit + + override fun pause() = Unit + + override fun resume() = Unit + + override fun hide() = Unit + override fun dispose() { - TODO("Not yet implemented") + backgroundTexture.dispose() + dropSound.dispose() + music.dispose() + dropTexture.dispose() + bucketTexture.dispose() } - } diff --git a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Main.kt b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Main.kt deleted file mode 100644 index 88d0b95..0000000 --- a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/Main.kt +++ /dev/null @@ -1,138 +0,0 @@ -package com.badlogic.drop - -import com.badlogic.gdx.Gdx -import com.badlogic.gdx.Gdx.audio -import com.badlogic.gdx.audio.Music -import com.badlogic.gdx.audio.Sound -import com.badlogic.gdx.graphics.Color -import com.badlogic.gdx.graphics.Texture -import com.badlogic.gdx.graphics.Texture.TextureFilter.Linear -import com.badlogic.gdx.graphics.g2d.Sprite -import com.badlogic.gdx.graphics.g2d.SpriteBatch -import com.badlogic.gdx.math.MathUtils -import com.badlogic.gdx.math.Rectangle -import com.badlogic.gdx.math.Vector2 -import com.badlogic.gdx.utils.ScreenUtils -import com.badlogic.gdx.utils.viewport.FitViewport -import ktx.app.KtxGame -import ktx.app.KtxScreen -import ktx.assets.disposeSafely -import ktx.assets.toInternalFile -import ktx.async.KtxAsync -import ktx.graphics.use - -class Main : KtxGame() { - override fun create() { - KtxAsync.initiate() - - addScreen(FirstScreen()) - setScreen() - } - class FirstScreen : KtxScreen { - private val backgroundTexture: Texture = Texture("background.png".toInternalFile(), true).apply { setFilter(Linear, Linear) } - private val bucketTexture: Texture = Texture("bucket.png".toInternalFile(), true).apply { setFilter(Linear, Linear) } - private val dropTexture: Texture = Texture("drop.png".toInternalFile(), true).apply { setFilter(Linear, Linear) } - - private val dropSound: Sound = audio.newSound("drop.mp3".toInternalFile()) - private val music: Music = audio.newMusic("music.mp3".toInternalFile()).apply { - isLooping = true - volume = 0.5f - play() - } - - private val bucketSprite: Sprite = Sprite(bucketTexture).apply { setSize(1f, 1f) } - - private val image = Texture("logo.png".toInternalFile(), true).apply { setFilter(Linear, Linear) } - private val batch = SpriteBatch() - private val viewport = FitViewport(8f, 5f) - - private var touchPos: Vector2 = Vector2() - - private var dropletSpriteList: MutableList = mutableListOf() - - private var dropTimer: Float = 0f - - private val bucketRectangle: Rectangle = Rectangle() - private val dropletRectangle: Rectangle = Rectangle() - - override fun resize(width: Int, height: Int) { - viewport.update(width, height, true) - } - - override fun render(delta: Float) { - input() - logic() - draw() - } - - override fun dispose() { - image.disposeSafely() - batch.disposeSafely() - } - - private fun input() { - if (Gdx.input.isTouched) { - touchPos.set(Gdx.input.x.toFloat(), Gdx.input.y.toFloat()) - viewport.unproject(touchPos) - bucketSprite.setCenterX(touchPos.x) - } - } - - private fun logic() { - val worldWidth: Float = viewport.worldWidth - - bucketSprite.x = MathUtils.clamp(bucketSprite.x, 0f, worldWidth - bucketSprite.width) - - val delta: Float = Gdx.graphics.deltaTime - bucketRectangle.set(bucketSprite.x, bucketSprite.y, bucketSprite.width, bucketSprite.height) - - for (sprite in dropletSpriteList.reversed()) { - sprite.translateY(-2f * delta) - - dropletRectangle.set(sprite.x, sprite.y, sprite.width, sprite.height) - - if (sprite.y < -sprite.height) dropletSpriteList.remove(sprite) - else if (bucketRectangle.overlaps(dropletRectangle)) { - dropletSpriteList.remove(sprite) - dropSound.play() - } - } - - dropTimer += delta - if (dropTimer >= 1f) - { - dropTimer = 0f - dropletSpriteList.add(createDroplet()) - } - //Gdx.app.log("Droplets", dropletSpriteList.size.toString() + " in List") - } - - private fun draw() { - ScreenUtils.clear(Color.BLACK) - viewport.apply() - batch.setProjectionMatrix(viewport.camera.combined) - batch.use { - it.draw(backgroundTexture, 0f, 0f, viewport.worldWidth, viewport.worldHeight) - for (s in dropletSpriteList) { - s.draw(it) - } - bucketSprite.draw(it) - } - } - - private fun createDroplet(): Sprite { - val dropWidth: Float = 1f - val dropHeight: Float = 1f - val worldWidth: Float = viewport.worldWidth - val worldHeight: Float = viewport.worldHeight - - val dropSprite: Sprite = Sprite(dropTexture).apply { - setSize(dropWidth, dropHeight) - x = MathUtils.random(0f, worldWidth - dropWidth) - y = worldHeight //- dropHeight // Spawn droplet above world for cleaner transition in? - } // We don't add the object to the set here because apply is really meant for doing stuff with members - - return dropSprite - } - } -} diff --git a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/MainMenuScreen.kt b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/MainMenuScreen.kt index 5e0043d..2a47d11 100644 --- a/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/MainMenuScreen.kt +++ b/Exercises/Drop/core/src/main/kotlin/com/badlogic/drop/MainMenuScreen.kt @@ -3,26 +3,30 @@ package com.badlogic.drop import com.badlogic.gdx.Screen import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.OrthographicCamera import com.badlogic.gdx.utils.ScreenUtils -class MainMenuScreen(val newGame: Drop) : Screen { +class MainMenuScreen(val game: Drop) : Screen { + private val camera = OrthographicCamera() - val game: Drop = newGame - - override fun show() { - TODO("Not yet implemented") + init { + camera.setToOrtho(false, 800f, 480f) } + override fun show() = Unit + override fun render(delta: Float) { ScreenUtils.clear(Color.BLACK) - game.viewport.apply() - game.batch.projectionMatrix = game.viewport.camera.combined + //game.viewport.apply() + //game.batch.projectionMatrix = game.viewport.camera.combined + camera.update() + game.batch.projectionMatrix = camera.combined game.batch.begin() - game.font.draw(game.batch, "Wekcine to Drop!!!", 1f, 1.5f) - game.font.draw(game.batch, "Tap anywhere to begin!", 1f, 1f) + game.font.draw(game.batch, "Welcome to Drop!!!", 100f, 150f) + game.font.draw(game.batch, "Tap anywhere to begin!", 100f, 100f) game.batch.end() @@ -32,23 +36,13 @@ class MainMenuScreen(val newGame: Drop) : Screen { } - override fun resize(width: Int, height: Int) { - TODO("Not yet implemented") - } + override fun resize(width: Int, height: Int) = Unit - override fun pause() { - TODO("Not yet implemented") - } + override fun pause() = Unit - override fun resume() { - TODO("Not yet implemented") - } + override fun resume() = Unit - override fun hide() { - TODO("Not yet implemented") - } + override fun hide() = Unit - override fun dispose() { - TODO("Not yet implemented") - } + override fun dispose() = Unit }