Hi all,
I am building a game where I keep a reference to my sprites in a table.
Then I loop over this table to draw all the sprites.
This goes fine, until I reach about 15 sprites, then performance starts to seriously drop.
My question: is there a better way to draw large numbers of sprites? These sprites are transparent PNG’s with retina versions. I am testing on iPad 3. My Code:
function draw()
for i=#self.allSprites,1,-1 do
self.allSprites[i]:draw()
end
end
Try to use mesh instead of sprite. Lots of sprites will kill performace. Here is an example i found on mesh vs sprites.
-- Use this function to perform your initial setup
function setup()
--gameState is the current state of play
-- 1 is sprites
-- 2 is meshes
iparameter("gameState",1,2,1)
iparameter("size",25,100,40)
g=mesh()
g.texture="Planet Cute:Brown Block"
xpos=0 --used for the movement of the background
ground={}
roof={}
for i=1,200 do
ground[i]=math.random(20)
roof[i]=math.random(20)
end
FPS = 0
watch("FPS")
timeInterval = 0
frameCount = 0
end
-- This function gets called once every frame
function draw()
--FPS print out from Minesweeper by @Reefwing
frameCount = frameCount + 1
timeInterval = timeInterval + DeltaTime
if timeInterval > 1 then
FPS = math.floor((frameCount / timeInterval)+0.5)
timeInterval = 0
frameCount = 0
end
elementcount=0
background(0)
if gameState==1 then
for i = 1,(1.5*WIDTH/size) do
for h=1,ground[i] do
sprite("Planet Cute:Ramp South",xpos+size*i-size,-50+(size/2)*h,size,size)
elementcount = elementcount + 1
end
for h=1,roof[i] do
sprite("Planet Cute:Ramp South",xpos+size*i-size,HEIGHT+50-(size/2)*h,size,size)
elementcount = elementcount + 1
end
end
elseif gameState==2 then
g:clear()
for i = 1,(1.5*WIDTH/size) do
for h=1,ground[i] do
local idx = g:addRect(xpos+size*i-size,-50+(size/2)*h,size,size)
g:setRectTex(idx, 0, 0, 1, 1)
elementcount = elementcount + 1
end
for h=1,roof[i] do
local idx = g:addRect(xpos+size*i-size,HEIGHT+50-(size/2)*h,size,size)
g:setRectTex(idx, 0, 0, 1, 1)
elementcount = elementcount + 1
end
end
g:draw()
end
xpos=xpos-1
if xpos<-1*size then
xpos=0
end
temp=ground[1]
tempr=roof[1]
for c=1,#ground-1 do
ground[c]=ground[c+1]
roof[c]=roof[c+1]
end
ground[#ground]=temp
roof[#roof]=tempr
text("Elements drawn: "..elementcount,WIDTH/2,HEIGHT/2)
end
--# Main
-- SpriteMesh
-- Use this function to perform your initial setup
function setup()
meshes = {}
extras = {}
width = 101
height = 171
noSmooth()
for i=1, 50 do
meshes[i] = mesh()
meshes[i].texture = readImage("Planet Cute:Character Pink Girl")
extras[i] = {}
extras[i].pos = vec2(math.random()*WIDTH, math.random()*HEIGHT)
extras[i].vel = vec2(math.random()*2-1, math.random()*2-1)
end
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
for i=1, #meshes do
pushMatrix()
extras[i].pos.x = extras[i].pos.x + extras[i].vel.x
extras[i].pos.y = extras[i].pos.y + extras[i].vel.y
if extras[i].pos.x < 0 or extras[i].pos.x > WIDTH then
extras[i].vel.x = -extras[i].vel.x end
if extras[i].pos.y < 0 or extras[i].pos.y > HEIGHT then
extras[i].vel.y = -extras[i].vel.y end
translate(extras[i].pos.x, extras[i].pos.y)
meshes[i]:clear()
meshes[i]:addRect(0,0,width,height)
meshes[i]:draw()
popMatrix()
end
end
--MeshBilder
--# Main
-- SpriteMesh
-- Use this function to perform your initial setup
function setup()
meshes = {}
extras = {}
width = 120
height = 140
--noSmooth()
for i=75, 95 do
meshes[i] = mesh()
meshes[i].texture = readImage("Dropbox:B"..i)
extras[i] = {}
extras[i].pos = vec2(math.random()*WIDTH, math.random()*HEIGHT)
extras[i].vel = vec2(math.random()*2-1, math.random()*2-1)
end
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
smooth()
for i=75,95 do --#meshes do
pushMatrix()
extras[i].pos.x = extras[i].pos.x + extras[i].vel.x
extras[i].pos.y = extras[i].pos.y + extras[i].vel.y
if extras[i].pos.x < 0 or extras[i].pos.x > WIDTH then
extras[i].vel.x = -extras[i].vel.x end
if extras[i].pos.y < 0 or extras[i].pos.y > HEIGHT then
extras[i].vel.y = -extras[i].vel.y end
translate(extras[i].pos.x, extras[i].pos.y)
meshes[i]:clear()
meshes[i]:addRect(0,0,width,height)
meshes[i]:draw()
popMatrix()
end
end
These are some great examples, thanks!
What I still fail to grasp is the basic principle of a mesh. In this code I’m trying to display a 200x200 part of a larger image, but it’s not working. Any idea why not?
function setup()
mymesh = mesh()
mymesh.texture = readImage("Dropbox:texture")
end
function draw()
local idx=mymesh.addRect(0,0,200,200)
mymesh.setRectTex(idx,0,0,200,200)
mymesh.draw()
end
SpriteBatch doesn’t only work on sprite sheets…you can render (lots) of regular sprites as well and still benefit from the speed increase. Here’s a small example:
function setup()
batch = SpriteBatch("Small World:Church")
end
function draw()
background(0)
-- draw sprites like normal, only use the batch object
-- instead:
batch:sprite("Church", WIDTH/2, HEIGHT/2)
-- you can even use Codea's style and transform functions:
pushMatrix()
translate(200, 200)
rotate(45)
tint(255, 255, 255, 128)
batch:sprite("Church")
popMatrix()
-- now draw the batch
batch:draw()
end