Most efficient way to draw a tilegrid(spritebatch vs canvas)
Posted: Tue Sep 11, 2012 2:49 am
Hello,
After hearing about love2d a while ago I decided to give it a go, and I am absolutely in love!
Anyway, I'm writing a basic tilebased platform engine, and have been experimenting what could be the best method to draw a tilegrid.
I have 3 options all with 30x15 tiles on screen. I haven' t tried any profilers yet, so I'm simply running my laptop on power saver mode and checking out the FPS haha.
non canvas, non spritebatch
no optimizations whatsoever 48-50 fps
spritebatch
I was expecting a very big improvement on fps using a spritebatch, but I'm still not achieving a steady 60 fps. It's usually between 58-60 fps.
Canvas
The tilegrid doesn' t changed all that often, so it seems like a waste to draw every frame. I'm clearing and drawing to the canvas each time the tilegrid changes. The canvas is drawn to the screen every frame.
It seems like drawing the canvas is a pretty expensive operation, I usually have around 50-55 fps, with spikes when changing the tilegrid.
Now this isn't even a very big map, and I'm using only a single layer.
Is there something I'm doing wrong or could improve upon? I can imagine I'm not clearing the spritebatch/canvas properly or something.
Not having to redraw the canvas every frame would also be a great improvement.
The source code from the relevant section can be found below
Spritebatch
Canvas
After hearing about love2d a while ago I decided to give it a go, and I am absolutely in love!
Anyway, I'm writing a basic tilebased platform engine, and have been experimenting what could be the best method to draw a tilegrid.
I have 3 options all with 30x15 tiles on screen. I haven' t tried any profilers yet, so I'm simply running my laptop on power saver mode and checking out the FPS haha.
non canvas, non spritebatch
no optimizations whatsoever 48-50 fps
spritebatch
I was expecting a very big improvement on fps using a spritebatch, but I'm still not achieving a steady 60 fps. It's usually between 58-60 fps.
Canvas
The tilegrid doesn' t changed all that often, so it seems like a waste to draw every frame. I'm clearing and drawing to the canvas each time the tilegrid changes. The canvas is drawn to the screen every frame.
It seems like drawing the canvas is a pretty expensive operation, I usually have around 50-55 fps, with spikes when changing the tilegrid.
Now this isn't even a very big map, and I'm using only a single layer.
Is there something I'm doing wrong or could improve upon? I can imagine I'm not clearing the spritebatch/canvas properly or something.
Not having to redraw the canvas every frame would also be a great improvement.
The source code from the relevant section can be found below
Spritebatch
Code: Select all
function Tilegrid:draw(camera)
local xEnd = math.floor(camera:width() / self.tileWidth);
local yEnd = math.floor(camera:height() / self.tileHeight);
if self.changed then
self.spritebatch:clear();
end
for x = 0, xEnd, 1 do
for y = 0, yEnd, 1 do
if self:getTile(x, y) ~= nil then
if self.changed then
self.spritebatch:addq(self:getTile(x, y).sprite:getQuad(), x * self.tileWidth, y * self.tileHeight);
end
self:getTile(x, y):draw(self.spritebatch);
end
end
end
love.graphics.draw(self.spritebatch);
if self.changed == true then self.changed = false end
end
function Tilegrid:getTile(x, y)
if self.tiles[x + 1] == nil then
return nil;
end
return self.tiles[x + 1][y + 1];
end
function Tilegrid:setTile(x, y, tile, solid)
if tile == -1 then
self.tiles[x + 1][y + 1] = nil;
return;
end
if self:getTile(x, y) == nil then
self.tiles[x + 1][y + 1] = Tile:new(x, y, self.tileWidth, self.tileHeight, self.spritesheet);
end
self.changed = true;
self.tiles[x + 1][y + 1].index = tile;
self.tiles[x + 1][y + 1].solid = solid;
end
Code: Select all
function Tilegrid:draw(camera)
local xEnd = math.floor(camera:width() / self.tileWidth);
local yEnd = math.floor(camera:height() / self.tileHeight);
if self.changed then
self.spritebatch:clear(); --print("clear");
self.canvas:clear();
end
for x = 0, xEnd, 1 do
for y = 0, yEnd, 1 do
if self:getTile(x, y) ~= nil then
if self.changed then
self.spritebatch:addq(self:getTile(x, y).sprite:getQuad(), x * self.tileWidth, y * self.tileHeight);
end
self:getTile(x, y):draw(self.spritebatch);
end
end
end
if self.changed then
self.canvas:renderTo(function()
love.graphics.draw(self.spritebatch);
end);
end
love.graphics.scale(camera.scaleX,camera.scaleY);
love.graphics.draw(self.canvas);
if self.changed == true then self.changed = false end
end
function Tilegrid:getTile(x, y)
if self.tiles[x + 1] == nil then
return nil;
end
return self.tiles[x + 1][y + 1];
end
function Tilegrid:setTile(x, y, tile, solid)
if tile == -1 then
self.tiles[x + 1][y + 1] = nil;
return;
end
if self:getTile(x, y) == nil then
self.tiles[x + 1][y + 1] = Tile:new(x, y, self.tileWidth, self.tileHeight, self.spritesheet);
end
self.changed = true;
self.tiles[x + 1][y + 1].index = tile;
self.tiles[x + 1][y + 1].solid = solid;
end