Button Class with Sprites

Hello all,
Just thought I’d show what I have for a button class that uses sprites and open it up for improvements or suggestions. Anything would be appreciated. I used some methods from @Reefwing’s button tutorial. I hope it’s all right :slight_smile:

Button = class()

function Button:init(btnNorm,btnSel,x,y)
    self.pos = vec2(x,y)
    self.btnNorm = btnNorm
    self.btnSel = btnSel
    self.selected = false
    self.action = nil
    self.w,self.h = spriteSize(self.btnNorm)
end

function Button:draw()
    if self.selected == true then
        sprite(self.btnSel,self.pos.x,self.pos.y,self.w,self.h)
    elseif self.selected == false then
        sprite(self.btnNorm,self.pos.x,self.pos.y,self.w,self.h)
    end
end

function Button:touched(touch)
    if touch.state == BEGAN or touch.state == MOVING then
        if math.abs(self.pos.x - touch.x) <= (self.w/2)
        and math.abs(self.pos.y - touch.y) <= (self.h/2) then
            self.selected = true
        else
            self.selected = false
        end
    elseif touch.state == ENDED then
        if self.selected == true and self.action then
            self.action()
        end
        self.selected = false
    end
end

And here’s a little example

-- Use this function to perform your initial setup
function setup()
     print("Hello World!")
     button = Button("Planet Cute:Chest Closed","Planet Cute:Chest Open",WIDTH/2,HEIGHT/2)
     button.action = function() buttonPressed() end
end

function draw()
     -- This sets a dark background color
     background(40, 40, 50)
     button:draw()
end

function buttonPressed()
     print("Button pressed")
end

function touched(touch)
     button:touched(touch)
end

EDIT: Juuuuuust kidding.
Again, any improvements or suggestions are more than welcome.

@ChrisF: you can use Codea’s spriteSize() function to get the dimensions of a sprite.

@toadkick Thanks. I did not see that in there. That was far too simple haha.

Heh, don’t mean to be a pain but you got a bug in your revision…w and h are globals, which is probably not what you want. You probably want to do:

self.w, self.h = spriteSize(self.btnNorm)

As well as fix any references to them everywhere else.

Oh no problem. Thanks for your help

@ChrisF - copying the examples and extending or improving the code is exactly what it is there for. @Simeon wrote the button class, I was just explaining how it works. I will link in this post from the Tutorial so that other people learning can see another approach. That is the beauty of coding, there are lots of ways to skin that cat and the search for the most elegant solution is never ending.

However, you do raise an interesting point. Is the code on these forums and elsewhere released under any particular licence? I’m assuming it is the DWTHYLWMCJDSM licence (Do What The Hell You Like With My Code Just Don’t Sue Me) but perhaps it should be explicitly stated somewhere (if it isn’t already). There is probably not too much code being written to run Nuclear Reactors using Codea (yet), so the risk is low but nevertheless…

Thanks ChrisF, thats what I was looking for. i extended the code a bit to have a matrix of buttons, e.g. As level selector. Maybe its useful for somebody:


Button = class()

function Button:init(btnNorm,btnSel,x,y,sizex, sizey)
    self.pos = vec2(x,y)
    self.btnNorm = btnNorm
    self.btnSel = btnSel
    self.selected = false
    self.action = nil
    --self.w,self.h = spriteSize(self.btnNorm)
    self.w = sizex
    self.h = sizey
end

function Button:draw()
    if self.selected == true then
        sprite(self.btnSel,self.pos.x,self.pos.y,self.w,self.h)
    elseif self.selected == false then
        sprite(self.btnNorm,self.pos.x,self.pos.y,self.w,self.h)
    end
end

function Button:touched(touch)
    if touch.state == BEGAN or touch.state == MOVING then
        if math.abs(self.pos.x - touch.x) <= (self.w/2)
        and math.abs(self.pos.y - touch.y) <= (self.h/2) then
            self.selected = true
        else
            self.selected = false
        end
    elseif touch.state == ENDED then
        if self.selected == true and self.action then
            self.action()
        end
        self.selected = false
    end
end


-- Use this function to perform your initial setup
function setup()
     buttons = {}
     local button
     xPos = 100
     for x = 1, 7 do
        yPos = 100
        for y = 1, 5 do
            button = Button("Planet Cute:Chest Closed","Planet Cute:Chest Open",xPos, yPos, 70, 70)
            button.action = function() buttonPressed(x, y) end
            table.insert(buttons, button)
            yPos = yPos + 80
        end
        xPos = xPos + 80
    end
end

function draw()
     -- This sets a dark background color
     background(40, 40, 50)

    for i = 0, table.maxn(buttons) do
        if buttons[i] == nil then
        else
            buttons[i]:draw()
        end
    end
end

function buttonPressed(x, y)
     print(string.format("Button pressed %i, %i", x, y))
end

function touched(touch)
    for i = 0, table.maxn(buttons) do
        if buttons[i] == nil then
        else
            buttons[i]:touched(touch)
        end
    end
end

@KilamMalik That’s interesting. I was actually looking to do the same thing when I had the chance. You made it much easier. Thanks

@KilamMalik How can you put in each box a random number in the table?

I dont quite understand your question. In which table do you want a random number?

@kilamMalik … To every Button a random number. For example open 5 Buttons and add The Numbers together. The max number wins.

if one assigns a random number to each box and on opening the box, this number is displayed you can create a game of it.

Ok, understand. You can add a variable with the number in the button class. In the render function of the button you draw the nimber over the button.

Nice! With your ideas, I would like to do something like letting out of the treasure box a sprite for using it later, like position it on different places any time… But I’m a newbie… and I hope I’ll find the way soon. :smiley:

Bellow is an example of two Players

-- Star selection matox
-- 

-- Use this function to perform your initial setup
function setup()
    show1 = 0
    show2 = 0
    show3 = 0
    show4 = 0
    a = 0; c = 0
    b = 0; d = 0
    e = 0; f = 0
    hit = 0
    rects = {}
    w,h = spriteSize("SpaceCute:Star")
    
    for i = 1, 4 do
      rects[i] = {}
      rects[i].x = 100 * i * 1.5
      rects[i].y = 200
      rects[i].id = i
      rects[i].p = math.random(100)
    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)

    -- Do your drawing here
    drawSprite()
    font("Georgia")
    fontSize(50)
    fill(255)
    text("1. Player           2. Player", 300, 700)
    text(show1,150,600)
    text(show2,450,600)
    text(show3,150,500)
    text(show4,450,500)
    line(100,450,700,450)
    text(e,150,400)
    text(f,450,400)
end

function drawSprite()
    for i = 1, #rects do
        sprite("SpaceCute:Star", rects[i].x,rects[i].y,80,100)
    end
end
        
function touched(touch)
    local TouchX = CurrentTouch.x
    local TouchY = CurrentTouch.y
    if touch.state == ENDED then
        local toRemove = {}
           for i = 1, #rects do
            if TouchX >= (rects[i].x - (w/2))and 
                TouchX <= (rects[i].x + (w/2)) and 
                TouchY >= (rects[i].y - (h/2)) and 
                TouchY <= (rects[i].y + (h/2)) then
                print(rects[i].id,rects[i].p)
                hit = hit + 1
                if hit ==1 then
                    show1 = (rects[i].p)
                elseif hit == 2 then
                    show2 = (rects[i].p)
                elseif hit == 3 then
                    show3 = (rects[i].p)
                elseif hit == 4 then
                    show4 = (rects[i].p)   
                end
                a = show1
                b = show2
                c = show3
                d = show4
                e = a + c
                f = b + d
                table.insert(toRemove, i)
            end
        end
        for i = 1, #toRemove do
            table.remove(rects,toRemove[i])
        end
    end
end

Will do, thank you.

@Robto - you have revived an 18 month old thread. Please start a new discussion if you want to talk about this.

Hi great class, thank all of you for your efforts.

I have a question for the main section, how would one go about if you wanted to keep the chest open for a certain amount of time/frames before it changes back to the closed chest?