Exit Full View

Coding with Ignorance

Here is the complete code for a demo "Game" using the KorGE framework. It displays an image, and rotates it backwards and forwards.

Straight out of the box, this will run in a window, as well as in a browser (the Kotlin code is "compiled" to Javascript). Nice.

I think this is an excellent introduction to KorGE. Not too long, and introduces many features of KorGE.

  1. suspend fun main() = Korge( width = 512, height = 512, bgcolor = Colors["#2b2b2b"] ) {
  2. val sceneContainer = sceneContainer()
  3. sceneContainer.changeTo({ MyScene() })
  4. }
  5. class MyScene : Scene() {
  6. override suspend fun SContainer.sceneMain() {
  7. val minDegrees = (-16).degrees
  8. val maxDegrees = (+16).degrees
  9. val image = image(resourcesVfs["korge.png"].readBitmap()) {
  10. rotation = maxDegrees
  11. anchor(.5, .5)
  12. scale(0.8)
  13. position(256, 256)
  14. }
  15. while (true) {
  16. image.tween(image::rotation[minDegrees], time = 1.seconds, easing = Easing.EASE_IN_OUT)
  17. Image.tween(image::rotation[maxDegrees], time = 1.seconds, easing = Easing.EASE_IN_OUT)
  18. }
  19. }
  20. }

I was hooked. I want to use KorGE in my next project!

Then I looked more closely at the code. What does this do :

  1. Korge(width = 512, height = 512, bgcolor = Colors["#2b2b2b"])

It looks like we are calling the constructor of class Korge.

Nope!

Maybe Korge is a function (but functions shouldn't start with a capital letter).

Nope!

Korge is a Kotlin object. And therefore we have no constructor.

We are calling the method suspend operator fun invoke(), which has dozens of parameters, each with default values.

I bet 90+% of coders are ignorant to this fact. The KorGE designers think this is "good" that we are ignorant of what we are calling, because it's part of a DSL (Domain Specific Language). How it works isn't important. What's important is getting the job done in as few keystrokes as possible.

But IMHO, this code would be easier to understand :

  1. suspend fun main() {
  2. Korge.initialise( width = 512, height = 512, bgcolor = Colors["#2b2b2b"] )
  3. }

Worse to Come

So what about the block of code just after ... Colors["#2b2b2b"] )

This is a lambda passed to invoke (or initialise in my make believe alternative).

The insides of this block have a new receiver (of type Stage).

The IntelliJ IDE helpfully shows this, but is completely absent in all other contexts (e.g. using a different editor or reading the code on line, such as here, or on GitLab/GitHub etc).

Am I being an old-codger, harking back to the Good-Old-Days, when code was a series of instructions? Easy to comprehend, and slightly verbose.

DSLs can be Excellent

I'm not against DSLs, I think they can be excellent.

I've been using Ktor's HTML DSL, and I love it.

Many years ago, I wrote code which generated HTML using JSP, and also using Templates. Both are horrible. A Frankenstein mishmash of code and plain-text.

Using Ktor's HTML DSL is a breath of fresh air. You can never accidentally forget to close a <div> tag, You can never accidentally have a typo in an attribute name. You can use all of the power of a "proper" programming language, such as for loops, if statements, function calls etc.

So What's the Difference?

Here's a tiny snippet of a HTML DSL :

  1. ul {
  2. li { +"Artists : $artists" }
  3. li { +"Albums : $albums" }
  4. li { +"Songs : $songs" }
  5. }

Inside the first block we see some DSL magic, li { ... }. It is clear that li is a method call, you may not know the class name. You might guess that the class is called Ul, and you'd be nearly right, it is UL (all caps). This convention holds for the whole DSL.

There is no weirdness.

Compare this with KorGE's. There is no method name to click on. There is nothing to suggest that the big block of code has a receiver of type Stage. It could just as easily have been Scene, or a dozen other things.

The Rant Continues

This code looks easy enough...

  1. val image = image(resourcesVfs["korge.png"].readBitmap()) {

The name is bad though. In English "image" and "bitmap" are synonyms, but in KorGE, they are very different. An "Image" has a Bitmap, a position, a scale etc.

Ok, so how do we add it to the Stage?

Gotcha! we don't. The image method adds it to the stage.

To be fair, image is almost exactly like the HTML DSL img(src="...") { ... } (which I like).

So why don't I like KorGE's?

Because it doesn't look like we are doing DSL stuff. It looks like a simple assignment.

This is also valid KorGE code - spot the difference :

  1. val image = Image(resourcesVfs["korge.png"].readBitmap()) {

It does the same as the previous version, without adding it to the stage. And we could add it to the stage using :

  1. this += image

I would have preferred they used plus rather than plusAssign, so that we could do this :

  1. + image

Summary

I suppose I will get used to it quite quickly, but my code will never do what it looks like it is doing.

I've been wanting to write a game with my nephew (can program, but isn't fluent).

There's no way in hell I'd show him KorGE. If I'm struggling to understand what a small demo is doing, there's zero chance of him understanding it.

I'm sure he would be able to write a game in KorGE, but I want him to understand how to program, and KorGE adds massive roadblocks.