Displaying different shaped asteroids is nice, but we have an issue of size we might work on for a bit. And let’s split them!

There are only four asteroid shapes in the original game, but there are three sizes, large, medium, and small. Mediums are twice the size of smalls, and large ones are twice the size of mediums. And there’s every reason to believe that in the original game, the values were handy powers of two, so that arithmetic could be done just by shifting the values. I’ll look up the source code if I remember. Anyway, let’s experiment with size.

I think I’ll start by adding a parameter to the app,letting me slide the size up and down to see what we like.

The asteroids right now are size 10, which looks a bit small to me. So I’ll let the slider go from 1 to 16 and see how that looks. In setup, I’ll add this:

    parameter.integer("SIZE", 1, 16, 16)

That’s an integer parameter that goes from 1 to 16 and starts at 16. I’ll also need to turn off the full screen option so that we can see the switches. And in the draw code, access the size:

function drawAsteroid(asteroid)
    pushMatrix()
    pushStyle()
    translate(asteroid.pos.x, asteroid.pos.y)
    scale(SIZE)
    strokeWidth(1/SIZE)
    for i,l in ipairs(asteroid.shape) do
        line(l.x, l.y, l.z, l.w)
    end
    popStyle()
    popMatrix()
end

Let’s see what happens. Here’s 16, 8, and 4:

sixteen eight four

Close enough. Of course we can’t really control the size that way, so I’ll back out that parameter and set the scale as a variable in the asteroid table for now:

Supper is getting close, so I can just do a bit more. It’s too hard to implement bullets in the time I have left, but what if we allowed asteroids to randomly explode?

When an asteroid is hit in the game, it breaks into two smaller asteroids that move off in random directions. I think what I’ll try is to give each asteroid a chance of one in 120 of breaking up. That should be about one explosion per asteroid every two seconds. The small ones, of course, will not explode again.

Let’s just try to slam that in:

-- Asteroid
-- RJ 20200520

local Asteroids = {}
local Vel = 1.5

function createAsteroids()
    for i = 1,4 do
        table.insert(Asteroids, createAsteroid())
    end
end

function createAsteroid()
    local a = {}
    a.pos = vec2(math.random(WIDTH), math.random(HEIGHT))
    a.angle = math.random()*2*math.pi
    a.shape = Rocks[math.random(1,4)]
    a.scale = 16
    return a
end

function drawAsteroids()
    pushStyle()
    stroke(255)
    fill(0,0,0, 0)
    strokeWidth(2)
    rectMode(CENTER)
    for i,asteroid in ipairs(Asteroids) do
        drawAsteroid(asteroid)
        moveAsteroid(asteroid)
        splitAsteroid(asteroid)
    end
    popStyle()
end

function splitAsteroid(asteroid)
    if asteroid.scale == 4 then return end
    if math.random(1,960) ~= 1 then return end
    asteroid.scale = asteroid.scale//2
    asteroid.angle = math.random()*2*math.pi
    local new = createAsteroid()
    new.pos = asteroid.pos
    new.scale = asteroid.scale
    table.insert(Asteroids, new)
end

function drawAsteroid(asteroid)
    pushMatrix()
    pushStyle()
    translate(asteroid.pos.x, asteroid.pos.y)
    scale(asteroid.scale)
    strokeWidth(1/asteroid.scale)
    for i,l in ipairs(asteroid.shape) do
        line(l.x, l.y, l.z, l.w)
    end
    popStyle()
    popMatrix()
end

function moveAsteroid(asteroid)
    local step = vec2(Vel,0):rotate(asteroid.angle)
    local pos = asteroid.pos + step
    asteroid.pos = vec2(keepInBounds(pos.x, WIDTH), keepInBounds(pos.y, HEIGHT))
end

function keepInBounds(value, bound)
    return (value+bound)%bound
end

I wound up splitting every 1 of 960, because they split so fast I couldn’t watch them at all. Now it looks like this:

splitting

I reduced the count of starting asteroids to 4, which is where the original game starts, again, to make it easier to see what’s going on.

The implementation is pretty straightforward, in the new function splitAsteroid:

function splitAsteroid(asteroid)
    if asteroid.scale == 4 then return end
    if math.random(1,960) ~= 1 then return end
    asteroid.scale = asteroid.scale//2
    asteroid.angle = math.random()*2*math.pi
    local new = createAsteroid()
    new.pos = asteroid.pos
    new.scale = asteroid.scale
    table.insert(Asteroids, new)
end

If the asteroid is already size 4, no split. If it doesn’t roll a one on a 960-sided die, it doesn’t split. If it does, we cut its scale in half, change its direction randomly, create a new asteroid,put it in the same position as we are, and add it to the Asteroids table.

A bit dirty but shows us what we need. In addition, the game has a bit of a splash of fragments that appears when an asteroid is it. We’ll deal with that in due time.

For now, the pizza is ready and we’ve learned a bit and impressed the boss.

See you next time!