Using Tables and "For" Commands to Draw Multiple Objects Efficiently

Hey all, I have a pretty stupid question (lol). I was working on a new project and wanted to draw lots of rectangles but I didn’t want to fill up my code, and I wanted to try to find the most efficient way possible to create multiple rectangles in fixed locations. I thought a table and “For” command(s) would work in this situation but I haven’t been successful yet. Could anyone help? Thanks in advance!

--create an image in setup
img=image(w,h) --where w,h are width and height of drawing area
setContext(img)
--draw all your rectangles, eg in a row, using for loop
fill(0) --black
for i=100,WIDTH,100 do --steps of 100
    rect(i,100,50,50)
end
setContext()

--then in draw
sprite(img)

If you don’t know how to do a for loop, google for “lua for loop”

Here’s an example using a table and for loop. Any number of rectangles can be added. If the rectangles will be the same size, then the vec4’s can be changed to vec2’s to hold the x,y positions and the for loop will just use b.x and b.y.


function setup()
    -- rectangle x,y,w,h
    rct={vec4(100,100,30,50),vec4(300,300,20,80),vec4(200,300,30,30),
         vec4(100,500,50,20),vec4(50,250,60,10),vec4(75,350,100,5)}
end

function draw()
    background(40, 40, 50)
    fill(255)
    for a,b in pairs(rct) do
        rect(b.x,b.y,b.z,b.w)
    end
end

You can extend this concept even further by using an array of data structures not just fixed values.

For instance you could create something like this.

drawList = {
   { type="rect", size=vec4(100,100,30,50), color=color(255,0,0) },
   { type="rect", size=vec4(200,200,30,50), color=color(255,0,0) },
   { type="sprite", pos=vec2(400,50), image="spritename", tint=color(255,0,0) },
   { type="line", start=vec2(0,0), end=vec2(300,199), color=color(0,255,0) },
   -- etc etc etc
}

Then you can loop through as above, but the magic bit is that you can use the type field to decide which draw function to use very neatly by again using a table in Lua
eg

drawFunctions = {
     rect = function(d) 
          fill(d.color)
          rect(d.size.x,d.size.y,d.size.z,d.size.w)
     end,

    sprite = function(d)
    end,

    line = function(d)
    end,
 
    -- etc etc
}

function draw()

     local dli
     for i=1,#drawList do
         dli = drawList[i]
         drawFunctions[dli.type](dli)
     end

end

This is what’s known as a data-driven approach. ie the emphasis is placed on the data to tell the program what to do, rather than just writing big blocks of code and it’s definitely a better approach to take - especially with the flexibility that tables in Lua give you. Gotta love tables in Lua :slight_smile:

Could this be used to create multiple instances of classes while running the program? My example being to that of calling up a lot of windows on a PC. So basically, making an unlimited number of automatically-generated instances of a class. Is this possible on Codea?

yes, that’s what classes are good for

I mean, there is a difference between what I think you mean, and what I mean. I’m not a complete beginner to Codea, it’s just there are quite a few features I haven’t delved into yet.

What I actually meant was not as such:

function setup()

b = ball(WIDTH/2,HEIGHT/2)

end

ball = class()

ball:init(x,y)
self.x = x
self.y = y
end

and so forth.

I wanted to be able to create an INFINITE amount of instances of a class, while IN the program, like my window example.

My screen manager code takes a table of screens to create for managing transitions / state etc and one of the fields is a reference to the controller class for the given screen (I use an OO approach so each of my app screens is a sub class of a base screen class).

eg.

local screens = {   -- First screen is the default one - id must be unique!
    { id = "TITLE",   object = TitleScreen,      init = {data=69} },
    { id = "CREATE",  object = CreateGameScreen, retain = true },
    { id = "BANK",    object = BankScreen,       retain = true },
    { id = "SUMMARY", object = SummaryScreen,    retain = true }, 
}

Then in the code that actually generates a screen I create an instance of the screen like this

local function createScreen(s)
    print("CREATE SCREEN : "..s.id)
    local obj = s.object((s.init or {}));
    return obj
end

Works a treat :slight_smile:

I can also have multiple instances of the same screen, basically it’s the proper OO approach your mother always warned you about :slight_smile:

So yes this would work for your balls example as well.

Is ‘local screens’ a local table? So having a local table will do it instead of a lot of ifs and elses with lots of ‘x = sCales()’?

Thanks for the tip. would it be ok to get back to you on that another day regarding my specific project?

Yes it is local - but it’s local to the tab (file) instead of the function.

Scope in Lua is a lot like C/C++, in that anything declared local within a function will disappear as soon as the function ends (unless you’ve got a reference to it or it’s caught up in a closure).

Likewise anything declared local OUTSIDE of a function is local to the tab / file and not accessible outside of that tab / file - it’s basically like making a variable private to the tab - note this is NOT the same as a private member variable in a class, this would be the equivalent of a private static member, in that there would only be one instance shared amongst ALL instances of the class.

Yeah, by all means you can get back to me, or alternatively just post questions on the forum, I’m hanging around here more and more at the moment :slight_smile:

Thanks for all the different approaches and responses! Also, ( I don’t want to make another thread) is there a way to use a table and it’s strings in a loop that will make multiple texts and use the strings from the table? Like this:

btext={"Hi", "Hi Again", "Bye"}
bxcords={"10", "20", "30"}

For btextCount=1, 3 do
     For bxcordsCount=1, 3 do
     text(btext[btextCount], bxcords[bxcordsCount], 100)
     end
end

Btw I didn’t copy and paste this. What I want is just a bunch of texts and different locations and with different texts that use a table and loops.

Just lump the whole lot in a table inside a table, you can do it “raw” (which I don’t recommend) that is - just ensure the entries are all in the correct order. ie

data = {
    {"Hi",10},
    {"Hi Again",20}
}

and access the elements using standard integer array notation (counting from one), or use associative keys (which I do recommend) to make the code / data more readable ie.

data = {
    { string="Hi", xcoord=10}
}

Then just parse the list in a single loop

for i=1,#data do

   text(data[i][1], data[i][2], 100)       -- without keys - not readable
 
   -- or 

   text(data[i].string,data[i].xcoord,100)   -- with keys - better IMHO

end

Would this work if I wanted multiple, seperate texts?

If you wanted to draw all your texts at once then yes (just add a ycoord to the data), if you want to draw texts at different times, just have different tables, or a table of tables :slight_smile:

Ideally you just have a drawTextsFromTable() function and then pass in the table of texts (or whatever) you want to draw as a parameter.

Experiment with the code / idea, try things out and see what happens - it’s the best way to learn. :slight_smile:

It so happens that I am not as familiar with tables and their uses as I would like to be. Where is the best place to find out about them?

@CayDay47 - I’ve written an ebook on Lua with a lot on tables and classes, and also several posts about tables (and classes). I wrote them because I found it very hard to get good information about them.

You can find links to all of them on this page, ebooks at the top

http://coolcodea.wordpress.com/2013/06/19/index-of-posts/

@Ignatz - Thanks for the help. I’m sure I’ll glean a lot of information from your link here.

BTW - is thast your website, or another coder’s?

it’s mine