Skip to content

144. Asteroid cannon

January 20, 2014


I previously did posts on creating an asteroid field, both in simulated 3D and real 3D. In this post, I add the ability to shoot asteroids and make a game out of it, and explain how I did it.

I’m going to keep it fairly simple, for people who may not have a lot of experience.

As before, the asteroids will come flying out of the screen. Your job is to destroy the asteroids which will hit your ship and damage your shields, using a laser cannon. You aim the cannon by tilting the iPad.

I already have a project that simulates the asteroids, both in 2D and in 3D. So what else do I need?

Game states

All games need several states, and at least the following

  • an introduction, and explanation of the game
  • the game itself
  • an ending (maybe with an option to replay)

This is really easy. You just need a variable that tells you which “state” your game in. It helps to give names to the states, so you can see what is going on – look at these two lines of code, and think which you would prefer to see when trying to understand the code.

if state==INTRO then
if state==1 then

I set up the named state constants at the top of the code like this


So when I write state=INTRO, I am actually setting state=1. It doesn’t matter what numbers I use, as long as they are different.

I could just as easily not bother with constants, and just use text, ie state=”INTRO”.

The only place I need to check the state is in the draw function, and it looks like this.

    if state==INTRO then DrawIntro()
    elseif state==PLAY then DrawPlay()
    elseif state==END then DrawEnd() end

So depending on the state of the game, I run one of three functions. Doing it like this keeps the draw function very clean, and if I ever want to change anything, it makes it much easier if each state is in its own function.

Introduction and ending

These two states are very similar. They both show the game title, some text, and then tell the user to touch the screen to play.

The introduction text explains how the game works.

The ending text tells you how long you survived.


And that’s all. Because these two states are so similar, I wrote a function called DrawTextScreen, which draws the text screen and puts whatever text you give it, in the middle – so it can handle both the introduction and the ending.

The game

I don’t have to change anything about the asteroids flying out of the screen, because they fly in quite realistic paths, and all I need to do is

  1. figure out which ones will hit my ship and what damage they cause, and
  2. figure out if any asteroids are in the sights of my laser

First, I’ll draw some laser sights, just a couple of circles with cross hairs. The image below shows how they look. (I’ll explain the yellow halo round two of the asteroids later).


Aiming the laser by tilting the iPad

This is surprisingly easy. The Gravity variable provided by Codea has a value for x and y that tells you which way up the iPad is tilted. The x value varies from -1 when the iPad is tilted to vertically to the left, to +1 when it is tilted vertically to the right. Similarly, the y value varies from -1 to +1.

All I need to do is multiply the x value by half of the screen width, and add half the screen width, and then do the same for the y value, to give me the position for the laser sights, so tilting moves the sights around the screen.

Actually, doing this makes it quite difficult to get the sights to the edge of the screen, because you have to tilt the iPad nearly 90 degrees, so I made the sights more sensitive to tilting by changing the formula like this (aim is the x,y position of the centre of the sights)


So I am multiplying the tilt effect by 3, so the iPad responds much more.

If you want to do something like this in your games, just play around until you get it right. If you want the tilt to move in the opposite direction, just use -Gravity.x or -Gravity.y.

Figuring out which asteroids are hit by the laser

If the centre of the laser sights moves over an asteroid, and it is in range (the distance is less than some figure I decide), then it gets destroyed. I could have included an onscreen trigger, but I like to keep the controls simple.

So each time we draw, I need to check if any of the asteroids are under the laser sights. This is different in 2D and 3D.

2D intersections

In 2D, we are drawing all our asteroids on a flat screen. There is no distance, because we are just faking 3D. So all I need to do is check for each asteroid, whether the position of the laser sights is closer to the asteroid’s centre than its radius, and if it is, I destroy the asteroid.

The code looks like this. I check the asteroid distance (a.d) is in range of the cannon, and if the distance from the asteroid’s position (xx,yy) to the aiming point (aim) is less than the width of the asteroid (w).

if a.d<laserRange and vec2(xx,yy):dist(aim)<w then
    sound(SOUND_SHOOT, 39124)

3D intersections

This is way, way more difficult, because now everything we are drawing is in the distance, out in front of us.

Imagine if you put your finger out in front of you and look through it into the distance, to the first object behind it. That’s what we want to do – trace a line from the camera through the laser sights and out into the distance, checking if we hit any of the asteroids along the way. This is pretty difficult.

It can be done, and there are a few threads on the Codea forum about doing it. I’m not going to do it here, because I had the much easier option of doing it in 2D.

Figuring out which asteroids will hit the ship

I know is that the asteroids are flying toward me, but only the ones that start in the very middle of the screen will hit the ship. The others will spread out and miss.

So I calculated a fairly arbitrary HitRadius variable. Any asteroid which started within this distance of the middle of the screen would hit the ship. When I create each asteroid, I figure out if it’s going to hit the ship eventually, and if so, I also calculate the damage it will do to the shields, based on its size. This just saves effort when I’m doing the drawing process.

I used this knowledge when drawing the asteroids, to draw a yellow halo around each asteroid that is within range and will hit the ship, to alert the user that this is an asteroid that needs to be hit. I made the halo get bigger and smaller to make it noticeable. I just used a simple tween for this. If you’ve never used tweens before, don’t be scared of them. They simply interpolate one or more numbers for you, and while they can have some fancy effects, most of the time, a simple tween does the job fine. So my tween just makes the variable warning.s vary between 1 and 5, and back again, over and over, and I use this to set the size of the halo. (By the way, I can’t remember the correct wording for tweens, so I usually go into the Animation demo app and copy some code out of there!).

So as part of that drawing process, having checked that an asteroid hasn’t been destroyed by the laser, I check if it’s gone off the edge of the screen, and if so, I remove it from my table and ignore it from then on.

Then if it is very close to the ship, I check if it was going to hit, and if so, I deduct the damage from the shield score and delete the asteroid. If the shield score is negative, I set the state to END.

Further improvements

I could do a lot of things to improve the game, like making visible explosions when I hit an asteroid (there are some forum users who are very good at this), or making big asteroids break into smaller ones, making the user actually fire the laser, and maybe only giving the laser a certain amount of power that has to recharge, so you can’t shoot all the time – and so on.

And I’m sure you could think of some good improvements, too. Feel free to have a go. There are only about 150 lines of code in total, so it’s not too scary.

The code is here.


From → animation, Games, Graphics

One Comment

Trackbacks & Pingbacks

  1. Index of posts | coolcodea

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: