For something to do, and because it might be helpful to new Codea users, I’m going to implement an homage to the old Asteroids game.
It’s day 15,000, or 61 of lockdown, and I’m looking for something fun to do. Somehow, I’ve chosen to build something like the old arcade Asteroids game. I’m not shooting to match it exactly, but my current plan is to be pretty close, and then, perhaps, to move it just a bit toward something modern, like late 20th century. We’ll see. I’ll stop when it stops being fun.
Now, faithful readers will remember that I’ve already built a Spacewar, and the obvious thing to do would be to remove one ship and add asteroids to that game. So, of course, I’m not going to do that.
Instead, I’m going to do it from scratch, starting simply and building it up. I have some hope that what I do here will be useful to new Codea users.
The original game was terribly rudimentary by today’s standards, but it was a marvel of its time, 1979. You fly a small triangular spaceship in a field of moving asteroids. You survive and earn points by shooting the asteroids, which break up into smaller ones, until finally you destroy the smallest pieces.
Meanwhile flying saucers appear from time to time and shoot at you. You need to destroy those as well.
The ship can rotate right and left, accelerate, and shoot forward. To slow down, no problem, rotate tail first and accelerate the other way. To move in an arc, again no problem, rotate and accelerate sideways.
You start with some number of lives, and can earn new lives as your score increases. Each collision costs you a life, as does getting hit by a saucer’s fire. Lose all your lives, and the game’s over.
We’ll look up details as we go forward. For now that’s more than enough to get started. Here’s a pic of the game running. A little surfing will find you more information if you wish.
A Bit of Planning
We’ll get to coding very soon, but I do always recommend thinking, before, during, and after coding. I prefer “during” but it seems to me to be silly to imagine that we can start coding without first thinking a bit about what we’re going to do.
Since this is intended to be a multi-stage effort, covering I don’t know how many articles and little versions, I’ll want the code under version control. I’ll use the iPad Working Copy app for that, as usual, and will set that up as soon as possible.
I don’t know how much micro-testing I’ll be able to do. Graphical games are always hard for me to test, because you can look at the screen and if it looks right, it generally is right. However, if I set up CodeaUnit from the beginning, at least there won’t be much excuse when I get to thinking that something needs testing.
Basic Starting Point
I figure I’ll start with simple round asteroids, moving across the screen. We can give them clever asteroid shapes later. Once those are sorted, I’ll move to the ship. It’ll probably be more fun to make the ship fire bullets as soon as possible, since that’s when it turns into a game. Or, maybe we’ll do turning and acceleration first and it can be a space version of dodgeball. No need to decide now.
Let’s get started.
I create a new default project named Asteroids, and edit some of Codea’s starting file, until it looks like this:
-- Asteroids -- RJ 20200511 function setup() print("Hello World!") end function draw() background(40, 40, 50)C end
I’ll exit that now, to save the project, and see about setting up Working Copy. Working Copy is a Git app for the iPad and it works delightfully. Setting it up for Codea is a bit odd but I have instructions somewhere on how to do it. Here’s the drill that works for me.
- Create and save the initial Codea project (Asteroids)
- In Working Copy, initialize a new repo, giving it a suitable project name (like Asteroids).
- Fill in the README that Working Copy offers, if you like.
- Click the share icon (top right) and choose Setup Package Sync. (See pic below.)
- Working Copy will prompt you to select the folder to sync and bring up a file browser window.
- Navigate to the Codea projects and select your new project.
Here’s your correct sharing button:
Voila, you’re set up:
Now do your first commit before you forget!
Now to set up CodeaUnit and an initial test. We do that back in Codea, setting a dependency on CodeaUnit and adding a tab for our tests.
-- TestAsteroids -- RJ 20200511 function testAsteroids() CodeaUnit.detailed = true _:describe("Asteroids First Tests", function() _:before(function() -- Some setup end) _:after(function() -- Some teardown end) _:test("Hookup", function() _:expect( 2+2 ).is(3) end) end) end
I have a starting test page saved away that I pasted in as the starting point. This gives me a test button to press whenever I run the program, and pressing it, we see that my implementation of “3” is erroneous:
I fix that:
_:test("Hookup", function() _:expect( 2+1 ).is(3) end)
And the tests are “green” in a black-and-white sort of way. Time to commit the code as “Hookup Test Runs”.
OK, all that took less time than it took to write it up. Now let’s get to work.
A Very Limited Asteroid
Now, I’m an old hand with Codea and with object-oriented code in general, so I’d probably start right off with an Asteroid class. But today we want to build up to that a bit, so we’ll start with a simple “asteroid” right in the main program.
To begin, let’s draw a circle somewhere:
-- Asteroids -- RJ 20200511 function setup() print("Hello World!") end function draw() background(40, 40, 50) stroke(255) fill(255) ellipseMode(CENTER) ellipse(200,300, 20, 20) end
Let’s quickly go through those lines in
- This sets the background color to a kind of dull gray, RGB = 40, 40, 50.
- This sets the stroke color to white. If you give it just one number, it’s a gray scale from 0 to 255. You can also give it an RGB color and other options.
- This sets the fill color similarly.
- This sets the drawing of ellipses such that the position coordinates given will be the center of the ellipse, and “diameter mode”. We’ll come to that in just a moment. You can set other options
- This draws an ellipse with its center at x = 200, y = 300, with x and y diameter both 20. This should draw a circle 40 pixels across:
OK, well, wonderful. I hate everything about this It’s too small and it is solid. Our asteroids will be made of just white lines on black background. So I’ll set a fill of zero (or should I use that 40,40,50?) and draw it larger and more toward the center. A little tweaking gives me this:
function draw() background(40, 40, 50) strokeWidth(1) stroke(255) fill(40, 40,50) ellipseMode(CENTER) ellipse(400,500, 120) end
That’s close enough for now. I’m anxious to make this circle move. To do that, I’ll have to adjust its position. Naively, we can do it this way:
-- Asteroids -- RJ 20200511 function setup() print("Hello Asteroids!") X = 400 Y = 500 end function draw() background(40, 40, 50) strokeWidth(1) stroke(255) fill(40, 40,50) ellipseMode(CENTER) ellipse(X,Y, 120) X = X + 1 Y = Y + 2 end
This moves the circle up and to the right, maybe a bit too fast but not bad:
So that’s nice. But we want our screen to wrap around. So if X is greater than the width of the screen we want to set it back to near zero and if Y is greater than the height, ditto. We can do that, again naively, like this:
function draw() background(40, 40, 50) strokeWidth(1) stroke(255) fill(40, 40,50) ellipseMode(CENTER) ellipse(X,Y, 120) X = X + 1 if X > WIDTH then X = X - WIDTH end if X < 0 then X = X + WIDTH end Y = Y + 2 if Y > HEIGHT then Y = Y - HEIGHT end if Y < 0 then Y = Y + HEIGHT end end
So that looks to me to be a decent spike for an asteroid moving across the screen, wrapping around as they’re supposed to.
Well past time to commit this code isn’t it? “Moving Circle Wraps Around” is the commit name this time.
This is probably pretty close to the first little graphical thing I wrote in Codea. All the work is done in the Main tab, there’s no particular abstraction, and by golly we’ve got a thing moving on the screen.
Here are a few things to think about for next time, especially if you’re a beginner with Codea, or even if you’re just following along:
- Suppose we wanted two asteroids, or many of them. What are some ways we might do that?
- Are there better ways to handle the boundary checking?
- Game asteroids are odd polygons, and there are a few different shapes. How will we handle that?
- Game asteroids split when shot, making a number of smaller asteroids. The smaller ones use similar shapes to the original ones but smaller. How might we handle that?
There are surely many more questions to mull over until next time. I’m slightly tempted to keep going on this procedural way, as a new user to Codea might. Anyway we’ll find out next time!
Stay tuned and if you find this interesting do let me know. It’s lonely in here!