Improving code

Hello guys,

can someone take a look at the below code please?
I’m currently trying to display as about as 500 objects on screen, but FPS does not look so very stable.
I know I can do much more than this with mesh, so what’s wrong with my code?

Ipad 3 IOS 8.

Thank you in advance



parameter.integer("interval",0,10,1)
function setup()
    fps = FPS()
    frame = 0
    timer = 0
    dnl = false
    getImage()
end

function draw()
    background(183, 183, 183, 255)
    
    if dnl == true then
        timer =  timer + 1
        if timer == 1 then
            objSprite = readImage("Documents:Foe-Class-B")
            ar = aRect()
        end
        ar:draw()

            frame = (frame+1)%60
            if frame%interval == 0 then
                ar:Addrect(math.random(WIDTH),HEIGHT+50,40,60)
            end

    else
        text("Downloading Image",WIDTH/2,HEIGHT/2)
    end
    
    
    fps:draw()
end

function getImage()

    http.request("https://dl.dropboxusercontent.com/u/3106041/Foe-Class-B.png", gotImage)
end

function gotImage(img)

    saveImage("Documents:Foe-Class-B",img)
    sound(SOUND_PICKUP, 16598)
    dnl = true
end

aRect = class()

function aRect:init()
    self.m=mesh()
    self.m.texture = objSprite
    self.ships = {}
    self.index = 0
    local index
end


function aRect:Addrect(x,y,w,h)
    self.index = self.m:addRect(x,y,w,h)    
    self.m:setRectTex(self.index,0.93,0.45,0.06,0.20)
    table.insert(self.ships,FoeBolt(self.index,x,y,math.random(-10,10),3,0,0) )
end

function aRect:removeRect(index,key)
        self.m:setRect(index, 1, 1, 0, 0, 0)    
        table.remove(self.ships,key)
end

function aRect:draw()
    text("Items : "..table.maxn(self.ships),100,60)
    self.m:clear()
    for i,v in ipairs(self.ships) do
    v.x = v.x + v.xa * v.speed 
    v.y = v.y - v.ya * v.speed
    if v.y > HEIGHT + 200 or v.y < - 200 then
        self:removeRect(v.index,i)
    end
    
        index = self.m:addRect(v.x,v.y,40,60)
        self.m:setRectTex(index,0.93,0.45,0.06,0.20)
        self.m:setRect(index, v.x, v.y,40, 60, 0)
    end
    self.m:draw()
end

FoeBolt = class()

function FoeBolt:init(i,x,y,a,speed,btype,rotation)
    self.index = i
    self.x = x
    self.y = y
    self.angle = a
    self.rotation = rotation
    self.xa = math.sin(math.rad(self.angle))
    self.ya = math.cos(math.rad(self.angle)) 
    self.timer = 0
    self.pow = 3
    self.width = width or 9
    self.speed =  speed or 0.25
    self.btype = btype or 0
end

--# FPS
FPS = class()

function FPS:init(frac)
    self.val = 60
    self.frac = frac or 0.01
--    self.t0 = os.clock()
    self.t0 = ElapsedTime
end

function FPS:draw()

    pushStyle()
    local vShift = 0
  -- if jobs:active() then vShift = 30 end
--    if jobs.active then vShift = 30 end
    -- update FPS value with some smoothing
    local old = self.val
    local frac = self.frac
--    local t1 = os.clock()
    local t1 = ElapsedTime
    local delta = t1 - self.t0
    self.t0 = t1
    local new = 1/delta or old
    if new>65 then new=65 end
    local ratio = new/old
    if 0.5<ratio and ratio<2 then new = old*(1-frac)+ new*frac end
    self.val = new
    -- write the FPS on the screen
    if math.floor(new) >= 60 then
    fill(48, 255, 0, 255)
        else
    fill(255, 0, 0, 255)        
    end


   -- fontSize(25)
    --font("BITDUST TWO")
    rectMode(CENTER)
    text(math.floor(new).." FPS",WIDTH/2,20-vShift)
popStyle()
end


  1. For a simpler FPS estimate, try FPS=FPS*.9+0.1*DeltaTime
    (set FPS to 60 initially)

  2. Why create so many separate and identical rectangles, when you could just create one, and draw it as many times as you want?

Hi @Ignatz, thanks for the FPS calculation.
If i don’t create a rect each frame, how can I clear mesh rectangles? When i add 100 or so it starts stuttering.
Can you please show me how you’d do it?

@Ignatz, this is what I think you mean :



function aRect:draw()
    text("Items : "..table.maxn(self.ships),100,60)

    for i,v in ipairs(self.ships) do
    v.x = v.x + v.xa * v.speed 
    v.y = v.y - v.ya * v.speed
    if v.y > HEIGHT + 200 or v.y < - 200 then
        self:removeRect(v.index,i)
    end
    self.m:setRect(v.index, v.x, v.y,40, 60, 0)
    end
    self.m:draw()
end


This code starts stuttering after a certain amount of added rects with no mesh:clear()

any idea?

@deactive Here’s some code that creates 500 mesh rects and moves them down the screen. I’m just using a simple texture from Codea instead of reading yours. Also, I’m not removing any of them when they reach the bottom. My iPad Air runs this at 60 FPS. I can run about 1300 before it starts to drop the FPS.


displayMode(FULLSCREEN)

function setup()
    m=mesh()
    m.texture="Planet Cute:Character Cat Girl"
    tab={}
    for z=1,500 do
        m:addRect(0,0,50,100)
        table.insert(tab,vec2(math.random(20,WIDTH-20),
                math.random(HEIGHT-400,HEIGHT)))
    end
    fill(255)
end

function draw()
    background(40, 40, 50)
    for a,b in pairs(tab) do
        b.y=b.y-1
        m:setRect(a,b.x,b.y,50,100) 
    end
    m:draw()
    text(#tab.." objects   fps="..math.floor(1/DeltaTime),WIDTH/2,HEIGHT-50)
end

@deactive, @dave1707 - nice. I can get even more by adding the rects at random points in a big rectangular area, then using translate to move them down the screen.

It works faster because you aren’t having to reset individual rect coords each draw.

displayMode(FULLSCREEN)

function setup()
    m=mesh()
    m.texture="Planet Cute:Character Cat Girl"
    n=2000
    for z=1,n do
        m:addRect(math.random(20,WIDTH-20),math.random(-300,300),50,100)
    end
    fill(255)
    startY=HEIGHT 
    FPS=60
end

function draw()
    background(40, 40, 50)
    FPS=FPS*0.8+0.2/DeltaTime
    pushMatrix()
    translate(0,startY)
    startY=startY-1
    m:draw()
    popMatrix()
    text(n.." objects   fps="..math.floor(FPS),WIDTH/2,HEIGHT-50)
end

Hi @Ignatz, compared with @dave1707’s, your code doen’t make use of table. May be that the reason it runs quite faster?

If i use translate within mine, it does’t speed up this much …

mine is faster because it doesn’t need to use the setRect command 500 times per draw, not because of the table

@Ignatz The problem with not using a table is you don’t know the position of each individual rect. You won’t be able to calculate a collision distance.

@dave1707 - you can add a table in setup to store positions if you want, for collision testing purposes. But it won’t affect drawing speed at all because it isn’t needed for that.

Collision testing is a separate function altogether, and for that purpose, the original table of positions adjusted by the translation will work fine, ie there is no need to continually adjust the individual object positions.

@Ignate Looking at your code, your creating X amount of rects in a static mesh and then just moving the whole mesh down the screen with translate. In order to control an individual rect, you need to use setRect to change it. Here’s my code from above where I added a rotation on each rect.


displayMode(FULLSCREEN)

function setup()
    m=mesh()
    m.texture="Planet Cute:Character Cat Girl"
    tab={}
    for z=1,1000 do
        m:addRect(0,0,50,100)
        table.insert(tab,vec2(math.random(20,WIDTH-20),
                math.random(HEIGHT-400,HEIGHT)))
    end
    fill(255)
end

function draw()
    background(40, 40, 50)
    for a,b in pairs(tab) do
        b.y=b.y-1
        m:setRect(a,b.x,b.y,50,100,b.y/40) 
    end
    m:draw()
    text(#tab.." objects   fps="..math.floor(1/DeltaTime),WIDTH/2,HEIGHT-50)
end

Sure, but I dont think he needed to rotate, in which case, setRect is not required. No need to make it more complicated than necessary.

If the objects weren’t interactive, ie they just moved down the screen en masse without being shot at, it would be even quicker to create a background image with a lot of objects, and just scroll it down the screen.

@Ignatz That’s the problem with a lot of the discussions, not enough information on what they really want or how it’s going to be used. But the fun is just writing code and seeing how others do it. Also, it gives the new coders something to look over and learn from.

and it gives us something to gnaw on :wink:

@dave1707 @ignatz do you think the rect change could be included in a shader, controlled by an external variable? Do you think this could increase the fps (i mean increase the number of rectangles with 60 fps)?

Hi @Ignatz, @dave1707, sorry it was not my intention to throw the question without letting you have the proper amount of information. I found useful @Ignatz’s sample, I might need that either way and it’s very intersting how much you can learn every time. And @dave1707, really I did not want others to write code instead of me. If I looked so, let me apologize, please. Of course my code aims to check collision and keep track of other individual information, so I have to use tables.

@Jmv38 - nope, it’s not really something shaders are designed for

I think getting a few thousand objects to scroll down the screen at full speed is pretty good already!

@deactive There’s no need to apologize. I just meant that if someone doesn’t give detailed information in their question, then there’s going to be different responses. And a lot of times that’s a good thing because new coders get to see a lot of different coding approaches.

@Ignatz, any chance instead to make rects spawning continuosly rather than having a big bunch appearing all at a time?
Also, is there any a way to see each of them running at its own ( random ) speed?
Maybe I can’t use this approach for object that will be shot at, but perhaps for more static or less interactive kind of items, such as background “tiled” representations or weather effects.

@dave1707, thank you :slight_smile:

@deactive I modified my code above to spawn a new object at a random speed every second until there is a max of 25 objects. When an object goes off the bottom, they reappear at the top.


displayMode(FULLSCREEN)

function setup()
    count=0
    maxSprites=25
    m=mesh()
    m.texture="Planet Cute:Character Cat Girl"
    tab={}
    spawn()
    fill(255)
end

function spawn()
    count=count+1
    if count>60 and #tab<maxSprites then
        count=0
        m:addRect(0,0,50,100)
        table.insert(tab,vec3(math.random(20,WIDTH-20),
                math.random(HEIGHT,HEIGHT+50),math.random(4)))
    end
end

function draw()
    background(40, 40, 50)
    for a,b in pairs(tab) do
        b.y=b.y-b.z
        m:setRect(a,b.x,b.y,50,100) 
        if b.y<0 then
            b.y=math.random(HEIGHT,HEIGHT+400)
        end
    end
    m:draw()
    text(#tab.." objects   fps="..math.floor(1/DeltaTime),WIDTH/2,HEIGHT-50)
    spawn()
end