Dynamic table for menu

Hi guys im trying to create a dynamic menu using a table. I send a table containing the items to be used in the menu to function createMenu(). CreateMenu then takes this info and sets the positions of the menu buttons and gets the size of the buttons which i then use in the touch function to detect button presses.

Im having trouble understanding how add the info to the dynamic table and how to read it.

-- table to store menu items
    m = {"test1", "test2", "test3"}
    createMenu(m)

function createMenu(menu)
    bp = HEIGHT/2
    bh = 0
    bw = 0
    mb = {}
    
    for a, b in pairs(menu) do
        bw, bh = textSize(b[a])
        mb[a] = {menu[a], bp, bw, bh}
        bp = bp + 75
    end
end

Then i dont know how to read the data in mb.

What am i missing here?

EDIT: changed the code to show 2 ways.


function setup()
-- table to store menu items
    m = {"test1", "test2", "test3"}
    createMenu(m)
    
    for a,b in pairs(mb) do
        print()
        for c,d in pairs(b) do
            print(d)
        end
    end
    
    print()
    for a,b in pairs(mb) do
        print(b[1],b[2],b[3],b[4])
    end
end

function createMenu(menu)
    bp = HEIGHT/2
    bh = 0
    bw = 0
    mb = {}
    for a, b in pairs(menu) do
        bw, bh = textSize(b)
        mb[a] = {menu[a], bp, bw, bh}
        bp = bp + 75
    end
end

Once again your code works like a charm dave :slight_smile:

Follow up question on this. The next step would be to use the values stored in mb in the touched function. What would be the best way to do that. Below is my previous implementation when the menu was hardcoded. How to i access the values without looping through mb somehow or should i store the values from mb in other variables first and then use them in thouched?

function touched(t)
    if t.state==BEGAN then
        if state == 0 then
            if t.x>menuWidth-exploreButtonWidth/2 and t.x<menuWidth+exploreButtonWidth/2 and t.y>mb1-exploreButtonHeight/2 and t.y<mb1+exploreButtonHeight/2 then
                explore()
            end

@fikabord Sorry, I don’t have a lot of time, so here is a simple example. Just tap between the lines for a different print from the table. If this doesn’t help, let me know and I can give a better example later.


function setup()
-- table to store menu items
    m = {"test1", "test2", "test3"}
    createMenu(m)
end

function draw()
    background(40,40,50)
    stroke(255)
    strokeWidth(3)
    line(0,800,WIDTH,800)
    line(0,600,WIDTH,600)
    line(0,400,WIDTH,400)
    line(0,200,WIDTH,200)
end

function createMenu(menu)
    bp = HEIGHT/2
    bh = 0
    bw = 0
    mb = {}
    for a, b in pairs(menu) do
        bw, bh = textSize(b)
        mb[a] = {menu[a], bp, bw, bh}
        bp = bp + 75
    end
end

function touched(t)
    if t.state==BEGAN then
        if t.y>600 and t.y<800 then
            print(mb[1][1])
        end
        if t.y>400 and t.y<600 then
            print(mb[2][1])
        end
        if t.y>200 and t.y<400 then
            print(mb[3][1])
        end
    end
end

Dave, got what i need. Mb[x][y] was what i needed. This should keep me busy for awhile :slight_smile:
Super thanks again.

Don’t forget “local”…

Sky, how much does that impact performance or is it more about good code standard?

Ok, so here is a follow up question on this.

Creating the menu and connecting the touch events to the menu works really well now. However, since the table is dynamic i need to calculate the starting height for the first item. The menu is supposed to be centered in the middle in terms of height and width.

This is what im trying to do. Get the height of all menu buttons and the space between them. Take the sum of this and substract it from the total height of the screen. Then i take this value and divide by 2 and use as my starting pos. However, the menu gets centered below the middle. Thoughts?

function createMenu(menu)
    setFontStyle("button")
    textWidth, textHeight = textSize(menu[1])
    local menuHeight = 0
    for a, b in pairs(menu) do
       -- menuItems = menuItems + 1
        menuHeight = menuHeight + textHeight + textHeight
    end
    menuHeight = menuHeight - textHeight
    local menuStartPosition = HEIGHT - menuHeight
    menuStartPosition = menuStartPosition/2

@fikabord I took your original code and modified it to this. I think this is what you’re after.


function setup()
    m = {"test1", "test2", "test3", "test4", "test5"}
    createMenu(m)
end

function draw()
    background(40,40,50)
    fill(255)
    for a,b in pairs(mb) do
        text(b[1],WIDTH/2,b[2])
    end
end

function createMenu(menu)
    mb = {}
    bp = HEIGHT/(#menu+1)
    for a, b in pairs(menu) do
        bw, bh = textSize(b)
        mb[a] = {menu[a], HEIGHT-bp*a, bw, bh}
    end
end

Yes Dave, it works perfectly and i learned about the # as well :slight_smile:
Thank you so much.

Dave, here is another question for you. Figured you be the best to ask since i got the code from you even though i guess its a general question.

So in draw i have a variable called screen. Then in the code i assign screen to be different functions depending on what want to show. It can be a function called displayMainMenu or displayEndOfDay. What i have noticed is that whatever drawn in these functions gets stacked. So if i first set screen to displayMainMenu and then press a button to end the day and set screen to displayEndOfDay the draw() will draw what is in both of those screens as if draw() just stacked whatever you wanted to draw. I thought draw would just clear the screen 60 times ever second and just draw what was in draw?

function draw()
    -- draw screen
    if playerStamina > 0 then
       screen()
    else
        if state == 0 then
            screen = displayOutOfStamina
            state = 3
            screen()
        else
            screen()
        end
    end
end

function explore()
    
    if playerExploredToday == true then
        --print("already explored today")
        
    else
        playerExploredToday = true
        a = {}
        for i=1, 3 do
            a[i] = math.random(5)
        end
    end
    m = {}
    for i=1, 3 do
        for j, k in pairs(card) do
            if a[i] == k[1] then
                m[i] = k["title"]
            end
        end
    end
    createMenu(m, true, false)
    screen = displayExplore
end

function displayExplore()
    setFontStyle("button")
   -- set button position  
    for a,b in pairs(mb) do
        --print(b[1],b[2],b[3],b[4])
        text(b[1], WIDTH/2, b[2])
    end
end

function displayNothing()
    print("nothing")
end

function touched(t)
    if t.state==BEGAN then
        if state == 0 then
            if t.x>menuWidth-mb[1][3]/2 and t.x<menuWidth+mb[1][3]/2 and t.y>mb[1][2]-mb[1][4]/2 and t.y<mb[1][2]+mb[1][4]/2 then
                explore()
                state = 6
                return
            end

Setting screen to displayNothing still displays what was on the previous screen

Oh i took something out of my code with the intention ofhighlighting the issue but figured it might be important to keep in there.

The first thing i do in all displayFunctions is setting a background image. This does solve the problem. Im more interested in understanding how draw() works.

@fikabord Draw does redraw the screen about 60 times a second, but in none of the code above do I see the command background(…) that clears the screen at the start of every draw. If the screen isn’t cleared, whatever was there before is still drawn. Normally the backgroung() command is the first thing in draw unless it gets put in other functions called by draw. Without seeing all of your code, that’s what I think is happening.

@fikabord Use @SkyTheCoder if you want a comment to notify me, just saying Sky doesn’t do anything.

And “local” makes a variable only used in one small area. If you had a function that needed its own variables, you would have to use local otherwise the variables would leak out of the function and to the rest of the project, and sometimes overwrite other variables.

Thx dave, noticed that part of the code had been removed by accident. And thx for clearing up how draw works.

@fikabord Here’s an example about the use of locals:

function setup()
    x = 1
    print(x) -- will print 1
    notUsingLocals()
    print(x) -- will print 2
    usingLocals()
    print(x) -- will print 2
end

function notUsingLocals()
    x = 2
end

function usingLocals()
    local x = 3
end

I have read that ‘local’ does increase performance. And I have also read that @dave1707 doesn’t have local in his coding vocabulary. My thoughts on that is it is because he is so diligent at providing code snippet examples that don’t require the use of locals. :slight_smile:

@matthew That’s why I’m always there to tell @dave1707 to use local. :wink:

@SkyTheCoder Yes I’ve seen that three times now, haha! :-B

@matthew You’re correct about the code snippets. My examples are meant to answer a question that was asked, not to be used word for word in another program. Even though locals may improve performance, unless that function/variable is going to be used in an intensive loop, the difference won’t be noticed. And as long as the variable in the function doesn’t conflict with a variable outside of that function, there’s no problem. Locals should be used in library code or a function the will be included in other programs, because you don’t know what variable names would be used in any of the other code. So in just snippets, local isn’t in my vocabulary, but I do know when and where it should be used.

@dave1707 damn right.