Skip to content

Instantly share code, notes, and snippets.

@dksmiffs
Created May 15, 2018 20:32
Show Gist options
  • Save dksmiffs/d921cc20ca6d96284266d13077929705 to your computer and use it in GitHub Desktop.
Save dksmiffs/d921cc20ca6d96284266d13077929705 to your computer and use it in GitHub Desktop.
This is a Kotlin gist for the "Extended Simple App" LibGDX tutorial found at: https://github.com/libgdx/libgdx/wiki/Extending-the-simple-game. The Java version is here: https://gist.github.com/sinistersnare/6367829
package drop
import com.badlogic.gdx.Game;
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.SpriteBatch
class Drop : Game() {
public lateinit var batch: SpriteBatch
public lateinit var font: BitmapFont
override fun create() {
batch = SpriteBatch()
// use LibGDX's default Arial font
font = BitmapFont()
this.setScreen(MainMenuScreen(this))
}
override fun render() {
super.render() // important!
}
override fun dispose() {
// per @rohansuri's suggestion here:
// https://gist.github.com/sinistersnare/6367829#gistcomment-1661438
this.getScreen().dispose()
batch.dispose()
font.dispose()
}
}
package drop
import com.badlogic.gdx.audio.Music
import com.badlogic.gdx.audio.Sound
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.Input.Keys
import com.badlogic.gdx.math.MathUtils
import com.badlogic.gdx.math.Rectangle
import com.badlogic.gdx.math.Vector3
import com.badlogic.gdx.Screen
import com.badlogic.gdx.utils.Array
import com.badlogic.gdx.utils.TimeUtils
class GameScreen(val game: Drop) : 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<Rectangle> // 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("droplet.png"))
bucketImage = Texture(Gdx.files.internal("bucket.png"))
// load the drop sound effect and the rain background music
dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"))
rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"))
rainMusic.setLooping(true)
// create the camera and the SpriteBatch
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<Rectangle>()
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(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(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()
}
}
package drop
import com.badlogic.gdx.audio.Music
import com.badlogic.gdx.audio.Sound
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.Input.Keys
import com.badlogic.gdx.math.MathUtils
import com.badlogic.gdx.math.Rectangle
import com.badlogic.gdx.math.Vector3
import com.badlogic.gdx.Screen
import com.badlogic.gdx.utils.Array
import com.badlogic.gdx.utils.TimeUtils
class GameScreen(val game: Drop) : 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<Rectangle> // 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("droplet.png"))
bucketImage = Texture(Gdx.files.internal("bucket.png"))
// load the drop sound effect and the rain background music
dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"))
rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"))
rainMusic.setLooping(true)
// create the camera and the SpriteBatch
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<Rectangle>()
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(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(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()
}
}
@Airsaid
Copy link

Airsaid commented Jul 2, 2018

Hi, The MainMenuScreen.kt code is incorrect, please update!

@Quillraven
Copy link

It would look like this:

class MainMenuScreen(val game: MainGame) : 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() {
    }
}

@crykn
Copy link

crykn commented Oct 22, 2020

Hey @dksmiffs, the link in your description of the gist is no longer correct. The extended game tutorial can now be found at https://libgdx.com/dev/simple_game_extended/.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment