GitHub Repo

I want to break all the Solid objects out into separate classes. Have not yet found a smooth way to do that.

I am not seeing easy steps to breaking these objects out from SolidObject. The Splat should be about as simple as possible, let’s try it.

I see that it, like the Missile, uses the LifetimeClock to destroy itself. Let’s remove the Lifetime clock and make objects destroy themselves. We’ll start with Missile, then do Splat in situ or replace it as seems needed. I’ll take the LifetimeClock out of the mix:

    fun createContents(controls: Controls) {
        val ship = newShip(controls)
        add(ship)
        add(ShipChecker(ship))
        add(ScoreKeeper())
//        add(LifetimeClock())
        add(WaveChecker())
    }

Now Missiles will run forever or until they hit something. We don’t seem to have a test for that. What should they do?

    override fun update(deltaTime: Double, trans: Transaction) {
        position = (position + velocity * deltaTime).cap()
        if (elapsedTime > lifetime ) {
            trans.remove(this)
        }
    }

This will do the job. I need tests for this thing.

class MissileTest {
    @Test
    fun `can be created, dies on time`() {
        val ship = SolidObject.ship(U.randomPoint())
        val missile = Missile(ship)
        val trans = Transaction()
        missile.tick(0.1, trans)
        assertThat((trans.removes.size)).isEqualTo(0)
        missile.tick(3.1, trans)
        assertThat((trans.removes.size)).isEqualTo(1)
    }
}

This passes, no surprise given the difficulty of the code.

Do Splats already auto-destruct? No … they just shrink to the point of invisibility. Let’s create a new Splat and make it work like the old one.

I produce a few tests for Missile and Splat:

class MissileTest {
    @Test
    fun `can be created, dies on time`() {
        val ship = SolidObject.ship(U.randomPoint())
        val missile = Missile(ship)
        val trans = Transaction()
        missile.tick(0.1, trans)
        assertThat((trans.removes.size)).isEqualTo(0)
        missile.tick(3.1, trans)
        assertThat((trans.removes.size)).isEqualTo(1)
    }

    @Test
    fun `splat creation`() {
        val ship = SolidObject.ship(U.randomPoint())
        val missile = Missile(ship)
        val splat = Splat(missile)
    }

    @Test
    fun `splat death`() {
        val ship = SolidObject.ship(U.randomPoint())
        val missile = Missile(ship)
        val splatList = missile.finalize()
        val splat = splatList[0]
        assertThat(splat is Splat).isEqualTo(true)
        val trans = Transaction()
        splat.tick(4.0, trans)
        assertThat(trans.removes.size).isEqualTo(1)
    }
}

And Splat class and SplatView:

class Splat(missile: Missile): ISpaceObject {
    override var elapsedTime = 0.0
    override val lifetime = 2.0

    var position = missile.position
    var view = SplatView(2.0)

    override fun tick(deltaTime: Double, trans: Transaction) {
        elapsedTime += deltaTime
        update(deltaTime, trans)
    }

    override fun update(deltaTime: Double, trans: Transaction) {
        if ( elapsedTime > lifetime ) trans.remove(this)
    }

    override fun beginInteraction() {
    }

    override fun interactWith(other: ISpaceObject): List<ISpaceObject> {
        return emptyList()
    }

    override fun finishInteraction(trans: Transaction) {
    }

    override fun draw(drawer: Drawer) {
        drawer.fill = ColorRGBa.MEDIUM_SLATE_BLUE
        drawer.translate(position)
        view.draw(this, drawer)
    }

    override fun finalize(): List<ISpaceObject> {
        return emptyList()
    }

}

class SplatView
    fun draw(splat: Splat, drawer: Drawer) {
        drawer.stroke = ColorRGBa.RED
        drawer.fill = ColorRGBa.RED
        drawer.rotate(rot)
        for (point in points) {
            val size = sizeTween.value(splat.elapsedTime)
            val radius = radiusTween.value(splat.elapsedTime)
            drawer.circle(size*point.x, size*point.y, radius)
        }
    }

Tests are green, Splats are now red, and all seems well. Commit: new Splat object and view.

I can remove the missile and splat companions from SolidObject, and the old MissileView. I delete LifetimeClock and its test. Rename NewMissileView to MissileView. Test. Commit: remove residue of old missile and splat. remove lifetimeClock.

I’m still not as good as Hill at doing micro changes and tiny commits. Getting better, but this has felt ragged. Let’s sum up.

Summary

It was pretty straightforward creating Splat, I basically had to induce IDEA to create the class and then filled it in. There’s too much stuff up in the SolidObject that has to be replicated down but it’s not terrible at all.

I feel like Hill would have done this more smoothly. I basically just created the class, filled it in, made it work. I tink he’d have bridged it in smaller steps, each one working and leaving him green. Maybe I’ll ask him to walk thru one with me, maybe tonight, maybe tomorrow. I think we’ll be reviewing his branch tonight.

But all that said, the new class is pretty simple and it was easy to do. Not inch by inch, maybe, but step by step.

Tomorrow, even better. See you then!