Reputation: 13
I'm currently working through the examples in the book "Java Game Development with LibGDX" by Lee Stemkoski. I wanted to try Kotlin and converted the code in chapter 2 into Kotlin.
I'm asking if the following code is best practice, since it seems the Kotlin code is much more cumbersome (and not as 'good') as the Java counterpart.
package chapter2
import com.badlogic.gdx.Game
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.math.Rectangle
class StarfishCollectorAlpha : Game() {
private lateinit var batch: SpriteBatch
private var turtleTexture: Texture? = null
private var turtleX: Float? = null
private var turtleY: Float? = null
private lateinit var turtleRectangle: Rectangle
private var starfishTexture: Texture? = null
private var starfishX: Float? = null
private var starfishY: Float? = null
private lateinit var starfishRectangle: Rectangle
private var oceanTexture: Texture? = null
private var winMessageTexture: Texture? = null
private var win: Boolean? = null
override fun create() {
batch = SpriteBatch()
turtleTexture = Texture(Gdx.files.internal("assets/turtle-1.png"))
turtleX = 20f
turtleY = 20f
turtleRectangle = Rectangle(
turtleX!!,
turtleY!!,
turtleTexture!!.width.toFloat(),
turtleTexture!!.height.toFloat()
)
starfishTexture = Texture(Gdx.files.internal("assets/starfish.png"))
starfishX = 380f
starfishY = 380f
starfishRectangle = Rectangle(
starfishX!!,
starfishY!!,
starfishTexture!!.width.toFloat(),
starfishTexture!!.height.toFloat()
)
oceanTexture = Texture(Gdx.files.internal("assets/water.jpg"))
winMessageTexture = Texture(Gdx.files.internal("assets/you-win.png"))
win = false
}
override fun render() {
// check user input
if (Gdx.input.isKeyPressed(Input.Keys.LEFT))
turtleX = turtleX!! - 1
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT))
turtleX = turtleX!! + 1
if(Gdx.input.isKeyPressed(Input.Keys.UP))
turtleY = turtleY!! + 1
if(Gdx.input.isKeyPressed(Input.Keys.DOWN))
turtleY = turtleY!! - 1
// update turtle rectangle location
turtleRectangle.setPosition(turtleX!!, turtleY!!)
// checks win condition: Turtle must be overlapping starfish
if (turtleRectangle.overlaps(starfishRectangle))
win = true
// clear screen
Gdx.gl.glClearColor(0f, 0f, 0f, 1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
// draw graphics
batch.begin()
batch.draw(oceanTexture, 0f, 0f)
if (!win!!)
batch.draw(starfishTexture, starfishX!!, starfishY!!)
batch.draw(turtleTexture, turtleX!!, turtleY!!)
if (win!!)
batch.draw(winMessageTexture, 180f, 180f)
batch.end()
}
}
Firstly: The Java version defines nullable variables in only three words:
private Texture turtleTexture;
Secondly: You have to explicitly convert ints to floats with Kotlin, wheras Java manages this for you.
Thirdly: In order to use the nullable defined variables you have to use a double exclamation signs !! at the end, and also whenever you want to change them.
I want to use Kotlin with game development (LibGDX), but it seems to me (with my limited knowledge perhaps) that Java is the better language.
Please tell me my Kotlin code is rubbish and that there is a better way to refactor my mess.
Upvotes: 1
Views: 916
Reputation: 2764
For libgdx the usual case is that either all your variables should be null, or all your variables should be initialized, and nothing in between. Because of that you can use a single nullable variable in your Game class to delegate to a context class that has no nullable properties.
That gets rid of most of the annoying null-checking.
As for needing to explicitly convert between number types - for me that's a feature :D. I can see how it might irritate though. I'd give it a try though and see if it grows on you.
Here's the one I've just whipped up for my own purposes:
class GolGui : ApplicationAdapter() {
companion object {
private val SCREEN_HEIGHT = 480
private val SCREEN_WIDTH = 800
private val SCREEN_CENTER_X = SCREEN_WIDTH / 2
private val SCREEN_CENTER_Y = SCREEN_HEIGHT / 2
}
private class Context : Disposable {
val batch = SpriteBatch();
val img = Texture("badlogic.jpg")
val gameSession = GameSession(GameBoard(12, 12))
val camera = OrthographicCamera(SCREEN_WIDTH.toFloat(), SCREEN_HEIGHT.toFloat())
val shapeRenderer = ShapeRenderer()
init {
shapeRenderer.projectionMatrix = camera.combined
}
fun render() {
Gdx.gl.glClearColor(0.2f, 0f, 0f, 1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
shapeRenderer.apply {
begin(ShapeRenderer.ShapeType.Filled)
rect(200f, 200f, 200f, 200f)
end()
}
}
override fun dispose() {
batch.dispose()
img.dispose()
shapeRenderer.dispose()
}
}
private var context: Context? = null
override fun create() {
context = Context()
}
override fun render() {
context!!.render()
}
override fun dispose() {
context!!.dispose()
}
}
Upvotes: 1