# Help a newbie with buttons and understanding touches?

Hello all, I’m rather new to Codea and Lua and haven’t dabbled in programming for over a decade and am learning the ropes (or trying, anyway). Working my way through various tutorials and thinking up little exercises to try and test out skills, one runs into a paucity of input methods for user input as things are, so I said to myself: “let’s make a button!” For easy rapid input for choosing between options. I realize many have come before me and made button classes, but I wish to learn how to do this myself (conceptually speaking) and the buttons that others make are rather advanced for my current level. I have banged my head against this rather hard, and would love to have explained to me how people approach this problem that I’ve found. My problem is that the currentTouch variable stays in the ENDED state at its last touched location and I can’t figure out a good way to handle this. I’ve written a bit of code to demonstrate (that is obviously noob stuff - I’m a noob! It should certainly belong in a class also, but am just demonstrating).

``````-- buttons experiment

-- Use this function to perform your initial setup
function setup()
button = {}
button.x = WIDTH/2
button.y = HEIGHT/2
button.diameter = 200
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)

-- This sets the line thickness
strokeWidth(5)
font("AmericanTypewriter")
fontSize(40)
fill(88, 89, 108, 255)
ellipse(button.x, button.y, button.diameter)
fill(203, 78, 78, 255)
text("whatev", WIDTH/2, HEIGHT/2)
if IsPressed(button) then
print("hit")
end
end

function IsPressed(anyButton)
local left = anyButton.x - anyButton.diameter/2
local right = anyButton.x + anyButton.diameter/2
local bottom = anyButton.y - anyButton.diameter/2
local top = anyButton.y + anyButton.diameter/2

if CurrentTouch.x > left and CurrentTouch.x < right and
CurrentTouch.y > bottom and CurrentTouch.y < top
and CurrentTouch.state == ENDED
then
return true
else return false
end
end

``````

Again, sorry for noobishness of this, just want to know a reasonably elegant way to handle it. I saw one person’s class that checked for the length of time that had passed in the ENDED state and I mostly got it, but just kind of wanted to see if that’s the way people really do this. Also, I apologize that there are ample examples included with the (rather complicated) codea programs like the sounds one, I just don’t fully grok that one either. Thanks!

Welcome on the forum ! This is an example of how you can handle touch :

``````-- buttons experiment

-- Use this function to perform your initial setup
function setup()
button = {}
button.x = WIDTH/2
button.y = HEIGHT/2
button.diameter = 200
button.touched = function(self, touch)
if vec2(touch.x, touch.y):dist(vec2(self.x, self.y)) < self.diameter*.5 then
if touch.state == BEGAN then
print("touch BEGAN")
elseif touch.state == MOVING then
print("touch MOVING")
elseif touch.state == ENDED then
print("touch ENDED")
end
end
end
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)

-- This sets the line thickness
strokeWidth(5)
font("AmericanTypewriter")
fontSize(40)
fill(88, 89, 108, 255)
ellipse(button.x, button.y, button.diameter)
fill(203, 78, 78, 255)
text("whatev", WIDTH/2, HEIGHT/2)
end

-- this function is called when you touch the screen
function touched(touch)
button:touched(touch) -- : is a sugar syntax for button.touched(button,touch)
end
``````

Here’s a really crummy (but working) button class I made. It isn’t very good, or very well made, actually it really doesn’t have much going for it at all :p. That said, it IS really simple and doesn’t use any fancy techniques so it should be easy to understand for beginners (as I myself am a beginner)
You need to set up the button in setup, call button:draw() in the main class’s draw function, and call button:touched(touch) in the main class’s touched function (also, after calling button:touched(touch) you need to do button:callafterpressed()). I’m aware there are a lot of variables in the init, I did that to make every aspect easier to mess around with. I hope this helps

``````Button = class()

function Button:init(circ, width, height, xloc, yloc, namestring, namecolour, colour, strokecolour, strokewidth, timedbool, timelen, togglebool, defaultinvis, defaultoff, istag, fontsize)
self.circle = circ
if circ == true then
self.dia = width
else
self.wid = width
self.hei = height
end
self.x = xloc
self.y = yloc
self.loc = vec2(self.x,self.y)
self.name = namestring
self.namecol = namecolour
self.col = colour
self.strokewid = strokewidth
self.strokecol = strokecolour
self.timed = timedbool
if self.timed then
self.time = timelen
end
self.toggle = togglebool
if defaultoff then
self.on = false
else
self.on = true
end
if defaultinvis then
self.visible = false
else
self.visible = true
end
self.timer = false
self.elapsed = 0
self.pressed = false
self.originid = nil
self.halfpressed = false
self.pressable = true
self.tag = istag
self.fsize = fontsize
end

function Button:draw()
fontSize(self.fsize)
textMode(CENTER)
ellipseMode(CORNER)
if self.visible then
fill(self.col)
strokeWidth(self.strokewid)
stroke(self.strokecol)
if self.circle then
ellipse(self.x,self.y,self.dia)
fill(self.namecol)
else
rect(self.x,self.y,self.wid,self.hei)
fill(self.namecol)
text(self.name, self.x+(self.wid/2), self.y+(self.hei/2))
end
end
if self.halfpressed and self.on and self.visible then
fill(0, 0, 0, 120)
strokeWidth(0)
if self.circle then
ellipse(self.x,self.y,self.dia)
else
rect(self.x,self.y,self.wid,self.hei)
end
end
if not self.on or not self.pressable and self.visible then
fill(0, 0, 0, 120)
strokeWidth(0)
if self.circle then
ellipse(self.x,self.y,self.dia)
else
rect(self.x,self.y,self.wid,self.hei)
end
end
if self.timer then
self:processTimer()
lineCapMode(PROJECT)
local vlorp = WIDTH-(((ElapsedTime-self.elapsed)/self.time)*self.wid)
stroke(255,0,0,255)
strokeWidth(5)
if vlorp > self.x+self.wid-5 then
vlorp= self.x+self.wid-5
elseif vlorp < self.x+5 then
vlorp = self.x+5
end
if self.timer then
line(self.x+5, self.y+5,vlorp,self.y+5)
end
lineCapMode(ROUND)
end
end

function Button:ispressed(touch)
if not self.tag then
if self.visible and self.pressable then
t = vec2(touch.x, touch.y)
if touch.state == BEGAN and self.originid == nil then
if self.circle then
self.originid = touch.id
sound("Game Sounds One:Dropzone", .5)
self.halfpressed = true
end
else
if t.x > self.x and t.x < self.x+self.wid and t.y > self.y and t.y < self.y+self.hei then
self.originid = touch.id
sound("Game Sounds One:Dropzone", .5)
self.halfpressed = true
end
end
elseif touch.state == ENDED and touch.id == self.originid then
if self.circle then
self.pressed = true
self.halfpressed = false
end
else
if t.x > self.x and t.x < self.x+self.wid and t.y > self.y and t.y < self.y+self.hei then
self.pressed = true
self.halfpressed = false
end
end
self.halfpressed = false
self.originid = nil
else return end

if self.pressed then
self:processBehaviour()
end
end
return self.pressed
end
end

function Button:processTimer()
if ElapsedTime - self.elapsed > self.time then
self.timer = false
if not self.toggle then
self.on = true
elseif self.toggle then
self.pressable = true
end
end
end

function Button:togglevisible()
if self.visible then self.visible = false else self.visible = true end
end

function Button:processBehaviour()
if self.toggle and self.pressable then
if not self.on then
self.on = true
elseif self.on then
self.on = false
end
end
if self.timed and self.toggle and self.pressable then
self.elapsed = ElapsedTime
self.pressable = false
self.timer = true
end
if self.timed and not self.toggle and self.on then
self.elapsed = ElapsedTime
self.on = false
self.timer = true
elseif not self.toggle and not self.on then
self.pressed = false
end
end

function Button:callafterpressed()
self.pressed = false
end
``````

Thank you both for your replies! I’m working at present and intermittently trying to parse your suggestions (my day job does not involve programming but does provide the occasional 10 minute burst of downtime). I’ll meditate upon your approaches and report back on progress when I have assimilated (might be a day or two). It looks as if (on my quick scan) you both avoid CurrentTouch, and perhaps that was my main error. Quick clarification question - the individual touch disappears when you stop touching, unlike CurrentTouch? Seems that way. I note you both use the vec2:dist function instead of my rather more clumsy method, so thanks for showing me that (I’ll have to learn vec2 more!). Also I had never heard the term sugar syntax before, funny!

@Therighttoarmbears See this link where I show the use of buttons. Let me know if you end up with a blank screen when you return from a URL call after pressing “done” in the upper left corner of the URL screen. That might be a Codea bug with url’s returns.

``````
http://codea.io/talk/discussion/4664/buttons-on-multiple-screens/p1

``````

CurrentTouch, when you stop touching, will list itself as ended. If you instead track individual touches with touch.id then you can find when the touch of the id you’ve saved is ended then set the saved id to nil. This ensures that multiple touches don’t interfere and you have four states for your touch (nil being the fourth, a very helpful state to have)