And he did give to the cat of two fishes of the sea, the tuna and the whitefish. And the cat saw that it was good, and he did eat.

Now that that’s out of the way, let’s get down to it.

Perhaps we’ll try to fire a missile today. Unless something else comes up.

I am rather certain that the original Asteroids game had some finite number of missiles, including only one at a time for the saucer. I’ll try to suss out that number in the next day or so. Because we’re not doing objects, and we’re trying to do a very flat program using little more than functions, we’ll have a fixed number of missiles and asteroids. The number of asteroids, I think, is limited to 44, four times eleven, with eleven being the highest number the game would ever create in a wave. We’ll see about missiles.

We’ll allow the player to fire at most one missile per jab at the “k” key, which is our “fire” button. If there’s no missile to allocate, the player still has to lift their finger and tap again. Why? Just seems right to me.

We’ll inch up on this, of course. Let’s start with the controls, where we have this:

``````var controls_left: Boolean = false
var controls_right: Boolean = false
var controls_accelerate: Boolean = false
var controls_fire: Boolean = false
var controls_hyperspace: Boolean = false

keyboard.keyDown.listen {
when (it.name) {
"d" -> {controls_left = true}
"f" -> {controls_right = true}
"j" -> {controls_accelerate = true}
"k" -> {controls_fire = true}
"space" -> {controls_hyperspace = true}
//                "q" -> { insertQuarter()}
}
}
keyboard.keyUp.listen {
when (it.name) {
"d" -> {controls_left = false}
"f" -> {controls_right = false}
"j" -> {controls_accelerate = false}
"k" -> {controls_fire = false}
"space" -> {
controls_hyperspace = false
}
}
``````

So. We need another flag, I think, saying whether the ship can fire, which we’ll set to true at the beginning of things. When we see `control_fire`, we’ll check to see whether the player `can_fire`, and if so we’ll set `can_fire` to false and try to fire. We may or may not succeed, depending on whether there are missiles to be had. If, on the other hand, `control_fire` is false, we can set `can_fire` back to true.

Could we do something smarter?

Now, we could do something a bit more robust rather than this arm’s length setting of flags. We could change the `listen` code to call functions that we could implement over in the game tab. We could start with those functions just setting basically the same flags they set now, but we could make them more capable as needed.

But no …

As it happens, however, even in the more OO versions of the program, we just set flags, though those flags belong to the controls object over there. I think we’ll save the function-calling until we need it, if we ever do. This way is a bit like how it would be if we had an attached controller and all we could do is read out its switch values. More retro and we didn’t ever feel the need for more even in our other versions.

OK, so when do we want to do this? We’ll look at `gameCycle`:

``````fun gameCycle(
spaceObjects: Array<SpaceObject>,
width: Int,
height: Int,
drawer: Drawer,
deltaTime: Double
) {
for (spaceObject in spaceObjects) {
if (spaceObject.type == SpaceObjectType.SHIP) {
applyControls(spaceObject, deltaTime)
}
move(spaceObject, width, height, deltaTime)
}
for (spaceObject in spaceObjects) {
draw(spaceObject, drawer)
}
}

private fun applyControls(spaceObject: SpaceObject, deltaTime: Double) {
if (controls_left) spaceObject.angle -= 250.0 * deltaTime
if (controls_right) spaceObject.angle += 250.0 * deltaTime
if (controls_accelerate) {
val deltaV = Vector2(120.0, 0.0).rotate(spaceObject.angle) * deltaTime
spaceObject.dx += deltaV.x
spaceObject.dy += deltaV.y
}
}
``````

Well, it’s pretty clear roughly where the missile check needs to be.

Let’s sketch something in.

Hmm. While thinking, I refreshed my mind further on how we did this in other versions and it turns out we didn’t use another flag. Instead, if the game sees the `control_fire` flag as `true`, it sets it false and attempts to fire. Since the flag only goes `true` on the `keyDown` event, it won’t come up `true` again until we lift our finger and tap again. We’ll do that.

``````private fun applyControls(spaceObject: SpaceObject, deltaTime: Double) {
if (controls_left) spaceObject.angle -= 250.0 * deltaTime
if (controls_right) spaceObject.angle += 250.0 * deltaTime
if (controls_accelerate) {
val deltaV = Vector2(120.0, 0.0).rotate(spaceObject.angle) * deltaTime
spaceObject.dx += deltaV.x
spaceObject.dy += deltaV.y
}
if (controls_fire) fireMissile()
}
``````

Perfect, except we need to implement `fireMissile`. A mere bagatelle, I’m sure.

``````private fun fireMissile() {
controls_fire = false
println("BANG!")
}
``````

I can test this in the game. Remind me about writing tests, and TDD, and all that. Works perfectly, says

``````BANG!
BANG!
BANG!
``````

Each BANG! came out immediately when I hit the “k” key and not again until I tapped again. Trust me, I wouldn’t lie to you. At least not about anything so unimportant.

## A Digression

We’re about to create yet another kind of SpaceObject. We have them represented as an `enum` and a data class:

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

data class SpaceObject(
val type: SpaceObjectType,
var x: Double,
var y: Double,
var dx: Double,
var dy: Double,
var angle: Double = 0.0,
)
``````

We’ll want a `MISSILE`, and unless I miss my guess, it won’t be drawn as a set of points. So we’ll need to change how that `enum` works a bit.

And we should probably get around to some factory functions or something, pretty soon.

For now, I think I’ll make a missile be a very small rectangle.

``````private val missilePoints =
listOf(Vector2(-1.0, -1.0), Vector2(-1.0, 1.0), Vector2(1.0, 1.0),
Vector2(1.0, -1.0), Vector2(-1.0, -1.0))

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

Now I need to figure out how to create one on the fly as it were.

I think we need an `active` flag to help us here.

``````data class SpaceObject(
val type: SpaceObjectType,
var x: Double,
var y: Double,
var dx: Double,
var dy: Double,
val active: Boolean = true,
var angle: Double = 0.0,
)
``````

And I’ll create one, inactive, wherever we create our objects. Ah, yes, in `program`:

``````    program {
val ship = SpaceObject(
SpaceObjectType.SHIP,
width/2.0,
height/2.0,
0.0,
0.0,
0.0,
)
val asteroid = SpaceObject(
SpaceObjectType.ASTEROID,
300.0,
300.0,
74.0,
40.0,
)
val missile = SpaceObject(
SpaceObjectType.MISSILE,
0.0, 0.0,
0.0, 0.0
false
)
val spaceObjects = arrayOf(asteroid, ship,missile)
``````

That should allow me to set a missile on the screen, maybe even move it.

I realize immediately that I don’t have access to the space objects yet. For now, let’s make them global.

``````lateinit var spaceObjects: Array<SpaceObject>
// initialized as above

private fun fireMissile() {
controls_fire = false
val ship = spaceObjects[1]
val missile = spaceObjects[2]
missile.x = ship.x+ 50.0
missile.y = ship.y
missile.dx = 15.0
missile.dy = 0.0
missile.active = true
}
``````

One more thing will be needed but I think this might do something visible.

OK, that was a bit ragged. Here’s what I finally got working. The square missile you see is drifting slowly right as intended.

The final code had to be tweaked. I’m not sure where we should put active but I put it last for now:

``````lateinit var spaceObjects: Array<SpaceObject>

program {
val ship = SpaceObject(
SpaceObjectType.SHIP,
width/2.0,
height/2.0,
0.0,
0.0,
0.0,
)
val asteroid = SpaceObject(
SpaceObjectType.ASTEROID,
300.0,
300.0,
74.0,
40.0,
)
val missile = SpaceObject(
SpaceObjectType.MISSILE,
0.0, 0.0,
0.0, 0.0, 0.0,
false
)
spaceObjects = arrayOf(asteroid, ship,missile)

private fun fireMissile() {
controls_fire = false
val ship = spaceObjects[1]
val missile = spaceObjects[2]
missile.x = ship.x+ 50.0
missile.y = ship.y
missile.dx = 15.0
missile.dy = 0.0
missile.active = true
}
``````

It works as advertised, the square missile appears in front of the ship and drifts right. Of course, before you fire you can see it in the corner, because we’re not honoring the `active` flag. Let’s do that.

``````    for (spaceObject in spaceObjects) {
if (spaceObject.active) draw(spaceObject, drawer)
}
``````

And that’ll solve the dot in the corner. Let’s commit this baby. Commit: can fire rudimentary square missile due east.

We’ve left a bit of a mess. No, quite a lot of mess. But I think we’re done for the morning, so let’s see what we’ve learned and what looms before us:

## Summary

On the bright side, we added a new “type” of SpaceObject, the MISSILE, and arranged to draw it as a square. Kind of retro-cool, really, but we’ll want to change that to make it more of a dot.

We’ve made the array of space objects global, and honestly I think that’s OK, in the spirit of what we’re doing, which is a compact game implementation, basically limited to functions and simple struct type data. If we’re going to make it a public array, we shouldn’t also pass it to gameCycle. One thing or the other, not both.

However, we have a very ad-hoc way of deciding where the ship is, `spaceObjects[1]`, as well as the missile in `spaceObjects[2]`. That cannot long endure, but I do think we’ll need to know all the numbers for asteroid count, missile count, and so on, so one way or another those objects will have well-known locations.

Clearly we’ll need to set the position and velocity of the missile relative to that of the ship, but we have done that before. And we’ll want to search through all the missile slots to find an available one. And we’ll need to decide how to time them out, which is going to require a value in the missile, I suppose, or a separate missile-timing mechanism.

Possibly the missile table needs to be separate from the other objects. I’m sure that in the original version they didn’t waste any extra bytes storing unused information. I’ll do some research before next time. And next time I think we’ll move toward a more nearly final space object array, and see what we can clean up.

I can’t wait to find out what I do next!