A Question of Draw performance

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
Pash
Prole
Posts: 43
Joined: Sun Dec 30, 2012 8:04 am

A Question of Draw performance

Post by Pash »

Hi guys and gals,

Attached is an image to show my point. I am trying to create a draw only the visible blocks system for a game I am working on. Using code like this:-

Code: Select all

function world:update()
	for i=1, #worldBlocks do
		if worldBlocks[i].x * self.blockSize >= PlayerCam.x and worldBlocks[i].x * self.blockSize < love.graphics.getWidth() 
			and worldBlocks[i].y * self.blockSize >= PlayerCam.y and worldBlocks[i].y * self.blockSize < love.graphics.getHeight() then   
			worldBlocks[i].vis = true
		else 
			worldBlocks[i].vis = false
		end 
	end 
end 

function world:draw()
	for i=1, #worldBlocks do
		if worldBlocks[i].vis then 
			love.graphics.draw(worldBlocks[i].id.img, worldBlocks[i].x * self.blockSize, worldBlocks[i].y * self.blockSize )
		end 
	end
end
These callbacks are in love.update and love.draw respectively.

Now, while this appears to definitely improve the fps drop that I was experiencing without including this, it still isn't as good as I was expecting. Is this fps drop of around 50% in this case, or even 60-70% in other cases (more blocks drawn on screen) to be expected simply because of the volume of items being drawn? I have the base level start randomized to start at different points as well, if the blocks are all not visible on the screen the fps still seems to drop. Is this to do with table lookups or something then because of the lightweight logic in draw?

These blocks will be destroyable and will all have collision properties at some point as well.

Does anyone have better methods for engineering this? At the moment the block count is quiet small as well. I have attached my love file as well. Would really appreciate any pointers :)

Thanks,

Pash
Attachments
block drawing 1.jpg
block drawing 1.jpg (73.5 KiB) Viewed 6424 times
tbads.love
(5.02 KiB) Downloaded 174 times
Sagan Interactive - Looking forward to a creative 2013.
User avatar
MarekkPie
Inner party member
Posts: 587
Joined: Wed Dec 28, 2011 4:48 pm
Contact:

Re: A Question of Draw performance

Post by MarekkPie »

This looks like the case for SpriteBatches.
User avatar
Pash
Prole
Posts: 43
Joined: Sun Dec 30, 2012 8:04 am

Re: A Question of Draw performance

Post by Pash »

Thanks. This seems to be the general consensus. Ill give that a go.
Sagan Interactive - Looking forward to a creative 2013.
User avatar
Pash
Prole
Posts: 43
Joined: Sun Dec 30, 2012 8:04 am

Re: A Question of Draw performance

Post by Pash »

I really don't think this is going to scale well at all.

Using spritebatch now. I also added a timer in to check out the speed of the world draw code.

Code: Select all

function world:update()
	timeBefore = love.timer.getTime()
	blockSetBatch:clear()
	for i=1, #worldBlocks do
		if worldBlocks[i].x * self.blockSize >= PlayerCam.x and worldBlocks[i].x * self.blockSize < love.graphics.getWidth() 
			and worldBlocks[i].y * self.blockSize >= PlayerCam.y and worldBlocks[i].y * self.blockSize < love.graphics.getHeight() then   
			blockSetBatch:addq( worldBlocks[i].id.img, worldBlocks[i].x * self.blockSize, worldBlocks[i].y * self.blockSize )
		end 
	end
	howLongItTookToExecute = love.timer.getTime() - timeBefore 
end 

function world:draw()
	love.graphics.draw(blockSetBatch)
end
Attached Love file and Screenshot
Attachments
tbads.love
(5.93 KiB) Downloaded 169 times
block drawing 2.jpg
block drawing 2.jpg (318.97 KiB) Viewed 6336 times
Sagan Interactive - Looking forward to a creative 2013.
User avatar
Pash
Prole
Posts: 43
Joined: Sun Dec 30, 2012 8:04 am

Re: A Question of Draw performance

Post by Pash »

As usual, the peeps on irc are very awesome, gave me some good suggestions which I will give a go.
Sagan Interactive - Looking forward to a creative 2013.
User avatar
slime
Solid Snayke
Posts: 3161
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: A Question of Draw performance

Post by slime »

In case anyone else has similar issues and wanders into this topic: a suggestion from IRC was to only clear/re-add all the sprites when a sprite needs to be removed from the spritebatch, instead of doing it every frame regardless of whether anything's changed.

Additionally, if only a few sprites within the spritebatch change position/rotation/color/whatever and the rest stay the same, you can use SpriteBatch:setq to directly set only the few that changed, instead of redoing everything.

It's also a good idea to use SpriteBatch:bind / SpriteBatch:unbind when clearing and re-adding everything at once.
User avatar
Pash
Prole
Posts: 43
Joined: Sun Dec 30, 2012 8:04 am

Re: A Question of Draw performance

Post by Pash »

Thanks Slime. I won't get a chance to get to try this until next week but ill post back when I've tried.
Sagan Interactive - Looking forward to a creative 2013.
User avatar
Pash
Prole
Posts: 43
Joined: Sun Dec 30, 2012 8:04 am

Re: A Question of Draw performance

Post by Pash »

Into a much more smooth performance now with the methods slime posted above. Only updating when you need to is key for using spritebatchs for tile/block based games.

Thanks all!!
Attachments
block drawing 4.jpg
block drawing 4.jpg (89.68 KiB) Viewed 6155 times
Sagan Interactive - Looking forward to a creative 2013.
User avatar
Pash
Prole
Posts: 43
Joined: Sun Dec 30, 2012 8:04 am

Re: A Question of Draw performance

Post by Pash »

I am reaching this hard limit of ~16k sprites in a spritebatch for version 0.8.0 of love. Up to this limit, the performance is fine. I would say its fine to work it this way. But with this limit, I cant add all my tiles to the batch.

So naturally, my next idea is to improve my logic of choosing which tiles should be added to batch. I think larger table iterations are killing my performance. We are talking 100,000's of table items to look through. So I was thinking to add a second table, which is updated every frame, and would only contain drawable tiles. Then I would update the spritebatches based on the table contents. Even at higher resolutions there shouldnt be more than 10k tiles to iterate through in that table. Which is considerably less than the 100,000's of blocks in the world map.

I am gonna try this tonight. I can't think of better ways to do this, unless anyone has any suggestions?

Cheers,

Pash
Sagan Interactive - Looking forward to a creative 2013.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: A Question of Draw performance

Post by micha »

Pash wrote:I think larger table iterations are killing my performance. We are talking 100,000's of table items to look through.
I suppose you have a table with to indeces, with all the tiles in it. If this is the case, you can shorten the iteration by using the two-index structure. So lets say you have a table with two indices, containing information on what tiles have to be drawn: tile[x][y]. For a whole loop you would do two nested for loops for x and y each from 1 to the respective maximum. You can shorten these loopes, if you know the camera position. From the camera position, first determine the (tile)-coordinates of the first tile in the upper left corner and of the last tile in the lower right corner. These tile coordinates can now be used as the start and the end of the for loops. That way, the number of table entries to consider will never be larger than the number of tiles visible on screen.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], GetAsync and 3 guests