Spacewar! 03 - A wild Tozier appears!
I’m pairing today with Bill Tozier, who prefers to be styled “Tozier” in writings like this. @Vaguery on Twitter. I may accidentally refer to him as Bill, for which I apologize in advance and will surely fix the problem in subsequent editions. Bill1 will be pairing with me frequently, we both hope, and he’ll probably be wanting a byline before you Know it.
We looked at our previous version with the dot moving up the screen. We’re interested in something better than that, including variable velocity, acceleration and deceleration, turning, and the like. Tozier’s first concern, looking at the program for the first time, was to see which way the ship was pointing. Since it’s round, I could see his point. So I made it oval. Note the ellipse call now makes it 15 points high instead of ten. We tried just that but Tozier still couldn’t figure out which way was up, so I added a little line to indicate the nose of the ship:
-- S3 Spacewar
function setup()
pos = vec2(WIDTH/2, HEIGHT/2)
end
function draw()
background(40, 40, 50)
strokeWidth(2)
pos = clip_to_screen(pos + vec2(1,1))
translate(pos:unpack())
ellipse(0,0,10,15)
line(0,0,0,10)
end
function clip_to_screen(vec)
return vec2(vec.x%WIDTH, vec.y%HEIGHT)
end
As we spoke, I realized that most of our variables are global. (They default to global in Lua unless you say local
or do some other trick which we’ll see later. Globals are bad, but right now I felt we had little choice, since there’s nowhere else to stand. We have to init them in setup
and refer to them in draw
. Anyway, I foresee that we’ll go to objects “soon” and then the globals will become member variables in the instances. Note, however, that this is speculation. Whatever the case, it’s globals for now.
Tozier was also new to the translate
function, so I explained that it is the usual affine geometry transformations that one so often finds in a graphical library. He knew those words and was therefore satisfied. Suffice to say that rotate
and translate
and others basically move the screen under what you are about to draw so that to draw at location x, y, you can translate to x,y and draw at 0,0. And so on.
Rotate? Move in direction pointed?
We thought a good next thing to learn about would be rotating the ship, because it would help us practice with the graphical transforms, and because ships that only go in one direction would be pretty boring. We began by adding a variable theta
, which as an old math guy means angle to me, and just incrementing it as we go through the loop. We expected the ship to go spinning off the screen instead of sliding, and sure enough it does.
-- S3 Spacewar
function setup()
pos = vec2(WIDTH/2, HEIGHT/2)
vel = vec2(0,0)
theta = 0
end
function draw()
background(40, 40, 50)
strokeWidth(2)
theta = theta + 1
vel = vec2(1,1)
pos = clip_to_screen(pos + vel)
translate(pos:unpack())
rotate(theta)
ellipse(0,0,10,15)
line(0,0,0,10)
end
function clip_to_screen(vec)
return vec2(vec.x%WIDTH, vec.y%HEIGHT)
end
PLACE VIDEO HERE
You’ll notice that we added a rotate(theta)
call, which turns the screen underneath us and so when we draw the ship it appears as rotated. The rotate
function is defined so that your objects appear rotated by that many degrees, which is useful. It also means that the space is really rotating by the negative of that many degrees. I recommend that you forget that immediately.
So that was pretty fine. This game is getting to be really interesting and playable now. But, you know, just to make it more playable, let’s see if we can figure out how to actually control the rotation. Codea has a feature called parameter
that displays a sliding control on the screen, which you can drag with your finger to control a variable. So we defined one:
...
parameter.integer("Turn", -1,1,0)
...
theta = theta + Turn
It looks like this, and sure enough, if you slide that slider, the ship turns as expected.
The code now:
-- S3 Spacewar
function setup()
pos = vec2(WIDTH/2, HEIGHT/2)
vel = vec2(0,0)
theta = 0
parameter.integer("Turn", -1, 1, 0)
end
function draw()
background(40, 40, 50)
strokeWidth(2)
theta = theta + Turn
vel = vec2(1,1)
pos = clip_to_screen(pos + vel)
translate(pos:unpack())
rotate(theta)
ellipse(0,0,10,15)
line(0,0,0,10)
end
function clip_to_screen(vec)
return vec2(vec.x%WIDTH, vec.y%HEIGHT)
end
-
oops! ↩