I’ve decided how buttons should work. It only remains to make it so.

I’ve managed to get buttons displayed on the screen, where I actually intend them to be. I spoke last time about various options, and about my feeling that I’d have moved to objects by now if not sooner. But maybe there’s no reason to do it yet, and I’ve come up with an idea for how I’d like them to work, and an idea for how to do that.

It seems to me that one way or another, we want to know things like *if the ‘left’ button is pressed”. Just what we’ll do isn’t entirely clear, but it seems like if the ‘left’ button is pressed, we’ll add a bit to the Ship’s current angle. And so on.

So I want to be able to code roughly like this:

``````  if Button.left then
Ship.angle = Ship.angle + angleIncrement
end
``````

So the job of our button code will be to maintain an object called `Button`, with fields like `fire` and `left`, setting those fields to `true` if the button is pressed. We already have a table called Buttons that knows the button locations. We’ll extend that to be a table that knows the button’s name as well, and use that name to set the fields of the Button object.

Here’s the button setup now:

``````function createButtons()
local dx=50
local dy=200
table.insert(Buttons, vec2(dx,dy))
table.insert(Buttons, vec2(dy,dx))
table.insert(Buttons, vec2(WIDTH-dx,dy))
table.insert(Buttons, vec2(WIDTH-dy,dx))
end
``````

We ask each button for its x and y when we draw it:

``````function drawButtons()
pushStyle()
stroke(255)
strokeWidth(1)
for i,b in ipairs(Buttons) do
pushMatrix()
translate(b.x,b.y)
ellipse(0,0, 50)
popMatrix()
end
popStyle()
end
``````

So let’s preserve that and make each of the buttons a table with x, y, and name. (It’s worth noting that `vec2` is just a name for a kind of table that yas x and y, no more than that. Well, a bit more, because the secret tables for `vec2` include pointers to handy vector functions. We’ll ignore that fact for now, because we’re not using anything really vectorish. Here’s the new create:

``````function createButtons()
local dx=50
local dy=200
table.insert(Buttons, {x=dx, y=dy, name="left"})
table.insert(Buttons, {x=dy, y=dx, name="right"})
table.insert(Buttons, {x=WIDTH-dx, y=dy, name="fire"})
table.insert(Buttons, {x=WIDTH-dy, y=dx, name = "go"})
end
``````

And I improved the draw a bit:

``````function drawButtons()
pushStyle()
textMode(CENTER)
stroke(255)
strokeWidth(1)
for i,b in ipairs(Buttons) do
pushMatrix()
translate(b.x,b.y)
ellipse(0,0, 50)
pushStyle()
fill(255)
fontSize(30)
text(b.name,0,0)
popStyle()
popMatrix()
end
popStyle()
end
``````

That’s getting pretty long, by the way. We should extract its insides. And I am getting the feeling that the styles are out of control, but as long as we push and pop at the right times, we’ll be OK. The effect is pretty good: Commit: “labeled buttons”.

## Let’s make the buttons work

Recall what we have for touches:

``````function touched(touch)
if touch.state == ENDED or touch.state == CANCELLED then
Touches[touch.id] = nil
else
Touches[touch.id] = touch
end
end
``````

This maintains a table of as many touches as are present, indexed by their `id`, which Codea maintains for continuity. (I imagine that in fact it’s iPadOS that takes care of that.) Each touch knows many things, the most important to us being the field `pos`, its position.

Our buttons are conveniently round, with a radius of 50. So if a touch’s position is within 50 of a button’s position, you’re pressing the button. I think the best thing will be to sort out the buttons at the beginning of each draw cycle. We’ll just loop over touches and buttons and see what’s what. Let me try to write that:

That went easily:

``````function draw()
checkButtons()
pushStyle()
background(40, 40, 50)
drawButtons()
drawShip()
moveShip()
drawAsteroids()
popStyle()
end

function checkButtons()
Button.left = false
Button.right = false
Button.go = false
Button.fire = false
for id,touch in pairs(Touches) do
for i,button in ipairs(Buttons) do
if touch.pos:dist(vec2(button.x,button.y)) < 50 then
Button[button.name]=true
end
end
end
end

function drawButtons()
pushStyle()
textMode(CENTER)
stroke(255)
strokeWidth(1)
for i,b in ipairs(Buttons) do
pushMatrix()
pushStyle()
translate(b.x,b.y)
if Button[b.name] then
fill(128,0,0)
else
fill(128,128,128,128)
end
ellipse(0,0, 50)
fill(255)
fontSize(30)
text(b.name,0,0)
popStyle()
popMatrix()
end
popStyle()
end
``````

We call `checkButtons` at the beginning of draw. In `checkButtons` we clear all the button flags, then we check each touch against each button, and if the touch is in range, we set that button flag to true.

I tweaked the `drawButton` to color the button red when it’s pressed, by way of a test. And it goes like this: Commit: “colored active buttons”.

## Rotation

Just to complete the morning, let’s see if we can make the left and right buttons make the ship rotate. That’s about the right size for the time I have left.

Turning logic goes in `moveShip`, which is presently empty. I’ll try just adjusting the angle by 1 degree when the button is down:

``````function moveShip()
if Button.left then Ship.ang = Ship.ang + 1 end
if Button.right then Ship.ang = Ship.ang - 1 end
end
``````

And it works just about as one might like: Commit: “ship turns”.

## Summing Up

That’ll do for today. We have buttons implemented fairly cleanly, and we’ve pretty seriously munged up their drawing. So that could use a bit of cleaning.

Other than that, which is localized in any case, we might want to rename one or both of `Button` and `Buttons`, lest there be confusion.

I think we’re almost ready to fly the ship and then to shoot at the asteroids.

### By the way …

I’ve found some nice information about the old version, including the original 6502 source code on computerarcheology.com. I’d not discovered that site before. It’s really quite interesting. Among the things that will be useful will be that it includes the original patterns for the shapes of the asteroids, plus the graphics chip’s code for them, for example:

``````; Rock Pattern 1
09E6: 08 F9          SVEC scale=03(/64)  bri=0     x=0       y=1       (0.0000, 0.0156)
09E8: 79 F9          SVEC scale=03(/64)  bri=7     x=1       y=1       (0.0156, 0.0156)
09EA: 79 FD          SVEC scale=03(/64)  bri=7     x=1       y=-1      (0.0156, -0.0469)
09EC: 7D F6          SVEC scale=02(/128) bri=7     x=-1      y=-2      (-0.0078, -0.0234)
09EE: 79 F6          SVEC scale=02(/128) bri=7     x=1       y=-2      (0.0078, -0.0234)
09F0: 8F F6          SVEC scale=02(/128) bri=8     x=-3      y=-2      (-0.0234, -0.0234)
09F2: 8F F0          SVEC scale=02(/128) bri=8     x=-3      y=0       (-0.0234, 0.0000)
09F4: 7D F9          SVEC scale=03(/64)  bri=7     x=-1      y=1       (-0.0156, 0.0156)
09F6: 78 FA          SVEC scale=03(/64)  bri=7     x=0       y=2       (0.0000, 0.0313)
09F8: 79 F9          SVEC scale=03(/64)  bri=7     x=1       y=1       (0.0156, 0.0156)
09FA: 79 FD          SVEC scale=03(/64)  bri=7     x=1       y=-1      (0.0156, -0.0469)
09FC: 00 D0          RTS
;
``````

So that’s nice, isn’t it? We’ll just code that right up.

But that’s for another day. For today, we’re good to go. See you next time, I hope!

``````-- Asteroids
-- RJ 20200511

local Asteroids = {}
local Vel = 1.5
local Ship = {}
local Touches = {}
local Buttons = {}
local Button = {}

function setup()
print("Hello Asteroids!")
displayMode(FULLSCREEN_NO_BUTTONS)
createButtons()
createAsteroids()
createShip()
end

function createAsteroids()
for i = 1,10 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
return a
end

function createButtons()
local dx=50
local dy=200
table.insert(Buttons, {x=dx, y=dy, name="left"})
table.insert(Buttons, {x=dy, y=dx, name="right"})
table.insert(Buttons, {x=WIDTH-dx, y=dy, name="fire"})
table.insert(Buttons, {x=WIDTH-dy, y=dx, name = "go"})
end

function createShip()
Ship.pos = vec2(WIDTH, HEIGHT)/2
Ship.ang = 0
end

function draw()
checkButtons()
pushStyle()
background(40, 40, 50)
drawButtons()
drawShip()
moveShip()
drawAsteroids()
popStyle()
end

function checkButtons()
Button.left = false
Button.right = false
Button.go = false
Button.fire = false
for id,touch in pairs(Touches) do
for i,button in ipairs(Buttons) do
if touch.pos:dist(vec2(button.x,button.y)) < 50 then
Button[button.name]=true
end
end
end
end

function drawButtons()
pushStyle()
textMode(CENTER)
stroke(255)
strokeWidth(1)
for i,b in ipairs(Buttons) do
pushMatrix()
pushStyle()
translate(b.x,b.y)
if Button[b.name] then
fill(128,0,0)
else
fill(128,128,128,128)
end
ellipse(0,0, 50)
fill(255)
fontSize(30)
text(b.name,0,0)
popStyle()
popMatrix()
end
popStyle()
end

function drawShip()
local sx = 10
local sy = 6
pushStyle()
pushMatrix()
translate(Ship.pos.x, Ship.pos.y)
rotate(Ship.ang)
strokeWidth(2)
stroke(255)
line(sx,0, -sx,sy)
line(-sx,sy, -sx,-sy)
line(-sx,-sy, sx,0)
popMatrix()
popStyle()
end

function moveShip()
if Button.left then Ship.ang = Ship.ang + 1 end
if Button.right then Ship.ang = Ship.ang - 1 end
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)
end
popStyle()
end

function drawAsteroid(asteroid)
rect(asteroid.pos.x, asteroid.pos.y, 120)
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

function touched(touch)
if touch.state == ENDED or touch.state == CANCELLED then
Touches[touch.id] = nil
else
Touches[touch.id] = touch
end
end
``````