GitHub Decentralized Repo
GitHub Centralized Repo

I have a little time. Let’s try another experiment.

It’s 1545 and I have a little time. I wonder if I can spike something to detect a missing ship and create one. I’ll begin without much detail, just enough to see what it looks like to do it.

OK, this is interesting. I added this:

class Game ...
    private lateinit var ship: Ship

    private val waveOneShot = OneShot(4.0) { makeWave(it) }
    private val saucerOneShot = OneShot( 7.0) {it.add(saucer)}
    private val shipOneShot = OneShot( U.SHIP_MAKER_DELAY) { it.add(ship)}
    // all OneShot instances go here:
    private val allOneShots = listOf(waveOneShot, saucerOneShot, shipOneShot)

Changed the init:

    private fun createInitialObjects(
        trans: Transaction,
        shipCount: Int,
        controls: Controls
    ) {
        cancelAllOneShots()
        trans.clear()
        val scoreKeeper = ScoreKeeper(shipCount)
        knownObjects.scoreKeeper = scoreKeeper
        val shipPosition = U.CENTER_OF_UNIVERSE
        ship = Ship(shipPosition, controls)
//        val shipChecker = ShipChecker(ship, scoreKeeper)
//        trans.add(shipChecker)
    }

With that in place, there would be no ship, ever. So then, this:

    fun cycle(elapsedSeconds: Double, drawer: Drawer? = null) {
        val deltaTime = elapsedSeconds - lastTime
        lastTime = elapsedSeconds
        tick(deltaTime)
        beginInteractions()
        processInteractions()
        finishInteractions()
        U.AsteroidTally = knownObjects.asteroidCount()
        createNewWaveIfNeeded()
        createSaucerIfNeeded()
        createShipIfNeeded()
        drawer?.let { draw(drawer) }
    }

    private fun createShipIfNeeded() {
        val ship = knownObjects.targets.find { it is Ship}
        if (ship is Ship) return
        val trans = Transaction()
        shipOneShot.execute(trans)
        knownObjects.applyChanges(trans)
    }

And now the ship appears at center screen after 3 seconds, SHIP_MAKER_DELAY. It doesn’t check for safety, but the game works fine. Some tests will surely break. One is objecting to the lateinit variable not being initialized, that’ll just be something to add to the test I expect. The other is this one:

    @Test
    fun `game-centric NO MAKER saucer appears after seven seconds`() {
        // cycle receives ELAPSED TIME!
        val mix = SpaceObjectCollection()
        val game = Game(mix) // makes game without the standard init
        game.cycle(0.1) // ELAPSED seconds
        assertThat(mix.size).describedAs("mix size").isEqualTo(0)
        assertThat(mix.deferredActions.size).describedAs("deferred size").isEqualTo(2)
        val deferred = mix.deferredActions.find { (it as DeferredAction).delay == 7.0 }
        assertThat(deferred).isNotNull
        game.cycle(7.2) //ELAPSED seconds
        val saucer = mix.targets.find { it is Saucer }
        assertThat(saucer).isNotNull
    }

The deferred size is 3 instead of two. That is probably OK.

Good spike. I will in fact throw this one away, because I don’t see yet how to manage safe entry, but it shows that the basic issue is easily resolved. I am rolling back … now.

Summary

This has gone swimmingly. This morning’s spike was so clean that I kept it. This afternoon’s worked exactly as intended, the first time. If we didn’t want safe entry, we’d be done now and the code would be just fine. The thing with safe entry, however, is that we have to try multiple times, once the initial timer has elapsed, until we finally get the job done.

I’m not sure just how I’ll do that. Perhaps a flag in Game? Some kind of switch saying whether to look for the ship or try to create it again? I don’t know, needs some thought. But it surely can’t be all that difficult … can it?

Stop by next time and we’ll find out!