Let’s see if we can shoot down the saucer. That shouldn’t be too difficult, except that I can’t remember what the score is supposed to be.

I’ll have to relearn how collisions work. Easily done, we’ll just review a bit of code:

``````private fun checkCollisions() {
checkAllMissilesVsAsteroids()
if ( Ship.active ) checkShipVsAsteroids(Ship)
}

private fun checkAllMissilesVsAsteroids() {
for (missile in activeMissiles(SpaceObjects)) {
checkMissileVsAsteroids(missile)
}
}

private fun checkMissileVsAsteroids(missile: SpaceObject) {
for (asteroid in activeAsteroids(SpaceObjects)) {
}
}

private fun checkShipVsAsteroids(ship: SpaceObject) {
for (asteroid in activeAsteroids(SpaceObjects)) {
}
}

fun checkOneAsteroid(asteroid: SpaceObject, collider: SpaceObject, colliderKillRadius: Double) {
if (colliding(asteroid, collider,colliderKillRadius)) {
Score += getScore(asteroid,collider)
splitOrKillAsteroid(asteroid)
deactivate(collider)
}
}

fun colliding(asteroid: SpaceObject, collider: SpaceObject, colliderSize: Double): Boolean {
val asteroidSize = U.AsteroidKillRadius * asteroid.scale
return collider.position.distanceTo(asteroid.position) <= asteroidSize + colliderSize
}
``````

OK, it seems that we might go a couple of different ways. We might just do a `checkSaucerAgainstMissiles` kind of thing. Or maybe we could plunk the Saucer in with the Asteroids and let it drop through there. For that to work, we’d need `colliding` to be changed so as not to assume so much about its first parameter. If each SpaceObject knew its kill radius, that might work. It would also simplify the `colliding` calling sequence.

Could we bend our rules enough to have a “method” on SpaceObject that returns its kill radius? It would have to be a function, because the radius of an asteroid varies with its scale.

I suppose we could redefine `scale` to be kill radius and then adjust drawing … but no.

I think I’ll try something. Here’s the SpaceObjectType enum:

``````enum class SpaceObjectType(val points: List<Vector2>) {
ASTEROID(asteroidPoints),
SHIP(shipPoints),
SAUCER(saucerPoints),
MISSILE(missilePoints)
}
``````

Can we provide a second parameter there, a function from SpaceObject to Double? Let’s try.

``````val asteroidRadius = { asteroid: SpaceObject ->
val missileRadius = { _: SpaceObject -> U.MissileKillRadius }
val saucerRadius = { _: SpaceObject -> U.SaucerKilLRadius }
val shipRadius = { _: SpaceObject -> U.ShipKillRadius }

enum class SpaceObjectType(
val points: List<Vector2>,
{
}
``````

I have no test for this and I seriously want one.

``````    @Test
fun `kill radius tests`() {
val missile = newMissile()
}
``````

I start easy. What surprises me greatly is that three other tests fail, the ones checking Asteroid score!

``````    @Test
fun `scale 1 asteroid increases score by 100`() {
val asteroid = newAsteroid()
asteroid.position = Vector2(100.0, 100.0)
asteroid.active = true
asteroid.scale = 1.0
val missile :SpaceObject = newMissile()
missile.position = Vector2(100.0,100.0)
missile.active = true
val oldScore = Score
assertThat(asteroid.active).isEqualTo(false)
assertThat(Score - oldScore).isEqualTo(100)
}
``````

The failure is that it gets zero, not 100. Oh! Whew! I was experimenting with something else last night and didn’t revert it. Reverting that, let’s see how we do. We’re green.

I think I’d like to have a nice little function to get the killRadius of a SpaceObject. Let’s posit it in the test and continue.

``````    @Test
fun `kill radius tests`() {
val missile = newMissile()
}

}

``````

That passes nicely so far. I’ll move it over into … the SpaceObject file, I guess.

Let’s test the asteroids, they’re the tricky ones:

``````    @Test
fun `asteroid radii`() {
val asteroid = newAsteroid()
asteroid.scale = 1.0
}

@Test
fun `ship radius`() {
val ship = newShip()
}

@Test
fun `saucer radius`() {
val saucer = newSaucer()
}
``````

So that’s nice. Now I can change this:

``````fun colliding(asteroid: SpaceObject, collider: SpaceObject, colliderSize: Double): Boolean {
val asteroidSize = U.AsteroidKillRadius * asteroid.scale
return collider.position.distanceTo(asteroid.position) <= asteroidSize + colliderSize
}
``````

First, to this:

``````fun colliding(target: SpaceObject, collider: SpaceObject, colliderSize: Double): Boolean {
}
``````

This should work fine. Test and try game. We’re good. Now we can change the signature of colliding, since it no longer uses the provided radius.

We’re good. Commit: change `colliding` to use new `killRadius()` function.

Let’s catch our breath and reflect a bit.

## Reflection

It just seemed like a good idea to make `colliding` able to check any two objects, because it seemed likely that we’d need something like it for checking saucer against missiles. Now we can use it.

The provision of a function as a member of our enum is perilously close to violating our arbitrary rule against methods, but we can rationalize that we could store a function pointer in the enum, which is basically what we have done anyway.

This is an example Kent Beck’s notion of making a hard change by first making the hard change easy and then making the easy change.

## Moving on

I think we could probably just dump the saucer in with the asteroids and let missiles kill it, but I’m concerned about score. How does that happen?

``````fun checkOneAsteroid(asteroid: SpaceObject, collider: SpaceObject, colliderKillRadius: Double) {
if (colliding(asteroid, collider)) {
Score += getScore(asteroid,collider)
splitOrKillAsteroid(asteroid)
deactivate(collider)
}
}
``````

We’d wind up here, with `asteroid` being the saucer. We’ll want to rename the method if we use it. How does `getScore` work?

``````private fun getScore(asteroid: SpaceObject, collider: SpaceObject): Int {
if (collider.type != SpaceObjectType.MISSILE) return 0
return when (asteroid.scale) {
4.0 -> 20
2.0 -> 50
1.0 -> 100
else -> 0
}
}
``````

No, it’s too messy, we’d have to fiddle score and splitOrKill as well. We’ll use `colliding`but with a separate function.

I know I don’t have decent tests so I’m just going to put this in. This is troubling, but I am confident. And this works, the first time:

``````private fun checkCollisions() {
checkAllMissilesVsAsteroids()
if ( Ship.active ) checkShipVsAsteroids(Ship)
if ( Saucer.active ) checkAllMissilesVsSaucer(Saucer)
}

private fun checkAllMissilesVsSaucer(saucer: SpaceObject) {
for (missile: SpaceObject in activeMissiles(SpaceObjects)) {
if (colliding(saucer, missile)) {
Score += 99
deactivate(Saucer)
deactivate(missile)
}
}
}
``````

I’m not sure what the score should really be, and I’m not sure about the kill radius I used: I just picked 24. I’ll review the other version. The kill radius in the other game is 10, and the comments say that 12 would be better. I think our current version is larger. Playing the game a bit, I think 20 might be better. The saucer score is 200, so I’ll set that.

``````private fun checkAllMissilesVsSaucer(saucer: SpaceObject) {
for (missile: SpaceObject in activeMissiles(SpaceObjects)) {
if (colliding(saucer, missile)) {
Score += U.SaucerScore
deactivate(Saucer)
deactivate(missile)
}
}
}
``````

I think we can now kill the saucer and score correctly. Game play confirms. Let’s commit this and then see about tests. I do think I have some small ability to check this. Commit: saucer can be shot down for 200 points.

A warning reminds me that I can remove the `colliderKillRadius` from `checkOneAsteroid`. I’ll do that and see what else might arise. Commit: remove unneeded parameter.

I am reminded that `MissileTime` is unused. I must still be referring to the literal?

``````fun newMissile(): SpaceObject {
return SpaceObject(SpaceObjectType.MISSILE, 0.0, 0.0, 0.0, 0.0, 0.0, false)
.also { addComponent(it, Timer(it, 3.0)) }
}
``````

Aha! Fix that:

``````fun newMissile(): SpaceObject {
return SpaceObject(SpaceObjectType.MISSILE, 0.0, 0.0, 0.0, 0.0, 0.0, false)
.also { addComponent(it, Timer(it, U.MissileTime)) }
}
``````

Commit: remove magic number in favor of U.MissileTime.

Now that test. We have this test that’s perhaps a template:

``````    @Test
fun `scale 1 asteroid increases score by 100`() {
val asteroid = newAsteroid()
asteroid.position = Vector2(100.0, 100.0)
asteroid.active = true
asteroid.scale = 1.0
val missile :SpaceObject = newMissile()
missile.position = Vector2(100.0,100.0)
missile.active = true
val oldScore = Score
checkOneAsteroid(asteroid, missile)
assertThat(asteroid.active).isEqualTo(false)
assertThat(Score - oldScore).isEqualTo(100)
}
``````

Let’s replicate that for the Saucer:

``````    @Test
fun `saucer increases score by 200`() {
val saucer = newSaucer()
saucer.position = Vector2(100.0, 100.0)
saucer.active = true
saucer.scale = 1.0
val missile :SpaceObject = newMissile()
missile.position = Vector2(120.0,100.0)
missile.active = true
val oldScore = Score
checkSaucerVsMissile(saucer, missile)
assertThat(saucer.active).isEqualTo(false)
assertThat(Score - oldScore).isEqualTo(200)
}
``````

I don’t have `checkSaucerVsMissile`. I have this, to refactor:

``````private fun checkAllMissilesVsSaucer(saucer: SpaceObject) {
for (missile: SpaceObject in activeMissiles(SpaceObjects)) {
if (colliding(saucer, missile)) {
Score += U.SaucerScore
deactivate(Saucer)
deactivate(missile)
}
}
}
``````

Extract function:

``````private fun checkAllMissilesVsSaucer(saucer: SpaceObject) {
for (missile: SpaceObject in activeMissiles(SpaceObjects)) {
checkSaucerVsMissile(saucer, missile)
}
}

fun checkSaucerVsMissile(saucer: SpaceObject, missile: SpaceObject) {
if (colliding(saucer, missile)) {
Score += U.SaucerScore
deactivate(Saucer)
deactivate(missile)
}
}
``````

Expect green. Don’t get it. Reversing the asserts, I find that the score is OK but the saucer is still active. I see the upper case in the `deactivate`. Fix that.

``````fun checkSaucerVsMissile(saucer: SpaceObject, missile: SpaceObject) {
if (colliding(saucer, missile)) {
Score += U.SaucerScore
deactivate(saucer)
deactivate(missile)
}
}
``````

Expect green. Get it. Commit: add test for saucer-missile collision.

Interesting. Wasn’t really a bug … in the game it would work OK. But it wasn’t right and the test found it. If I had written the test first … who knows, the universe would be entirely different by now.

I wonder whether it’s a Pretty Bad Idea to name the official ship capital Ship and use lower case ship as a variable, ditto saucer/Saucer. Probably it is Pretty Bad if not Quite Bad or at least Pretty Darn Bad.

Let’s sum up and get outa here.

## Summary

We set out to provide for shooting down the saucer and we got ‘er done. Along the way we generalized the `colliding` function to handle any two space objects, using a moderately deep-in-the-bag function pointer in the `enum`. We have declared that to be righteous in view of the fact that even in C we could have put a function pointer in the enum to provide for the radius.

I have a vague feeling that we should do the same thing for scoring but the way the code breaks out now there’s no ambiguity so no need for that yet.

We do have one bit of inefficiency in that we loop over the missiles twice, once for asteroids and once for saucer. The cost of that? A bit more code, which we don’t care about, and one more initializing of a loop, which we also don’t care about. If we were programming a 6502 we might care about both, but we’re not and we don’t.

One more feature down. A decent morning. See you next time!