GitHub Decentralized Repo
GitHub Centralized Repo
GitHub Flat Repo

Today I am quite tired of Asteroids, and particularly tired of this version with its very weak structuring. The foregoing does not constitute a plan.

What would constitute a plan? I’m not sure. What are the benefits that might possibly accrue from doing whatever this is that I do?

It keeps the demons out of my head.
I have legit things to worry about, I suppose, and a tendency to worry about things over which I have no control, and to worry about things over which I might have some influence yet do not do the things I “should” do about them, and so on. Perhaps you have similar worries. I hope that you have no idea what I’m talking about.

I’ve formed the habit of getting up when my mind starts to wander down undesirable paths, and focusing on programming and writing, which displaces pretty much any other more harmful thoughts out of my head. That seems to me to be a good thing.

I really enjoy working with code.
I like causing the computer to do what I imagine it might do. I’ve enjoyed it for about six decades, in fact. I learn new ways of doing things, I occasionally learn a new language, and I discover, time and again, ways of doing the work that are better, for me, and worse, for me. I repeat old mistakes, make new ones, and generally express my humanity and creativity in code.
I really enjoy writing these articles.
I’ve developed this relatively unique style of putting down words that are as close as I can manage to my stream of consciousness, to my actual thoughts. Intentionally, I write about what actually happens when I program, rather than carefully eliminate all my human error from the articles. Rather than present you with a carefully crafted “here’s how you do that”, I try to write “here’s how I really do that”, in the hope that it’ll be a bit like what happens to you, and help you see that your imperfections, if any, are perfectly OK, even though we could use a little improvement.

I like to imagine that together, we discover the things we do well, the things we do less well, and the approaches we can take to provide better results.

I hope the articles bring some kind of joy to you.
I do want people to read these things and get some kind of benefit from them, even if it’s just laughter at how awful I am, though I hope it’s more a kind of friendly laughter at how ridiculously human we all are.

I hope that readers like you see mistakes that I make and recognize mistakes that you make, and that you derive an understanding that these things happen. Ideally, I hope that you’ll get ideas for what to do to avoid mistakes, what to do to produce better code, faster than you did before. Ideally, using some of the ideas I present, but however you might benefit, I hope that you do.

I think those are the main dimensions. It’s clear that it makes little difference what language I choose or what program I write, except insofar as different choices might attract different readers. But all these articles seem to follow the same rough outline:

  1. Observe what the program looks like now.
  2. Typically discover it’s not quite what I thought it was.
  3. We want to accomplish this new thing.
  4. Maybe we write a test, maybe we don’t. Either way, we’ll see what happens.
  5. Write some code; discover something; think about it; loop a while.
  6. Frequently get diverted to some new shiny idea. Discover, think, loop.
  7. Stop when tired, or when frustrated, or when the article gets too long.
  8. Observe what the program looks like now. It’s typically better on some dimension.
  9. Sum up events, mistakes, learnings. Observe that what happened wasn’t quite what we expected. Maybe plan a bit.
An Obstacle
I don’t really have an idea for another Kotlin program to write, though Hill (damn him) has suggested one.

But what’s really holding me back from that is the pain of creating a new empty project. It throws me into the world of Gradle, which is not a world I care to be in. In fact, even now in the Flat Asteroids program, the Gradle build is horribly broken, I know not why, and while I am sure Hill, or someone, would help me sort through it, it’s so awful, so painful, that I am living with it.

That obstacle is keeping me in Asteroids, though I could probably go back to one of the other versions and work on that if I cared to.

Maybe I could refactor Asteroids into Space Invaders or something. (No.)

Another Obstacle
I’d like to have sounds in the Asteroids program. Sounds amount to “play a .wav file asynchronously from time to time”. I have not found a decent description of how to do that within Kotlin / OPENRNDR, and I’ve not had the energy to suffer on my own, nor a sufficient desire to ask one of my pals to work on it with me. Perhaps one day.

So … What, Exactly?

I don’t know. If you have ideas to offer, questions to ask, tweet or toot me up. I typically at least respond politely, and sometimes I even answer questions, sometimes I even try something. I have been trying ECS because Bruce suggested it, and I don’t hate him for it.

For now, there are things the Flat Asteroids program needs, and we have at least one more, if not 24 more assessments to make comparing this style to the other two, the “centralized” and “decentralized” versions.

I still love the decentralized version best.

Let’s Do Something

Right. I realized yesterday that the ship is getting six shots. That is a bug that cam about when I installed saucer missiles, changing the main game constructor createGame to accept three parameters, number of saucer missiles, number of ship missiles, and number of asteroids. I had been creating six missiles, intending two for the saucer and four for the ship, and somehow along the way, the code turned out like this:

object U {
	...
    const val MissileCount = 6
    ...
}

    program {
        val font = loadFont("data/fonts/default.otf", 64.0)
        createGame(4, U.MissileCount, U.AsteroidCount)
        ...

Magic number 4, and we see where the 6 came from. Refactor to rename the MissileCount, change its value to 4 in U, and add and use SaucerMissileCount of 4 also.

object U {
	...
    const val SaucerMissileCount = 4
    ...
    const val ShipMissileCount = 4
    ...

        createGame(U.SaucerMissileCount, U.ShipMissileCount, U.AsteroidCount)

Test in game. I think it makes no sense to test for these values in a test, they’re configuration parameters. I could imagine testing to ensure that we do in fact create however many are asked for. But that’s not the path we’re on right now.

No, let’s do that.

We actually have a test that we can use as a model:

    @Test
    fun `game starts with four asteroids`() {
        createGame(U.ShipMissileCount, U.AsteroidCount)
        startGame(U.ScreenWidth, U.ScreenHeight)
        assertThat(activeAsteroids(SpaceObjects).size).isEqualTo(4)
    }

Let’s do this one:

    @Test
    fun `check game creates requested number of items`() {
        val saucerMissileCount = 3
        val shipMissileCount = 5
        val asteroidCount = 7
        createGame(saucerMissileCount, shipMissileCount, asteroidCount)
        assertThat(saucerMissiles(SpaceObjects).size).isEqualTo(saucerMissileCount)
        assertThat(missiles(SpaceObjects).size).isEqualTo(shipMissileCount)
        assertThat(asteroids(SpaceObjects).size).isEqualTo(asteroidCount)
    }

We see when we write this that we should probably rename the missiles function to shipMissiles. Let’s make sure the test runs first. It does. Rename:

fun activeShipMissiles(spaceObjects: Array<SpaceObject>): List<SpaceObject> =
    shipMissiles(spaceObjects).filter { it.active}

fun shipMissiles(spaceObjects: Array<SpaceObject>): List<SpaceObject> =
    spaceObjects.filter {it.type == SpaceObjectType.MISSILE}

I even remembered to rename the active version, yay me!

Test in game to observe 4 and 4. Works a treat. Commit: Fix issue where main created six ship missiles rather than intended four.

I think that’ll do for this morning. I have clocks to change and soon it will be breakfast and other Sunday rituals. Let’s sum up.

Summary

One tiny change, and with it, we improved the code a bit, providing suitable named constants, removing one magic number, and renaming functions more consistently. Every little bit counts.

Got ideas or questions? Tweet or toot me up.

See you next time!