How to avoid drawing map every single tick

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.
munchor
Prole
Posts: 39
Joined: Sun Jun 10, 2012 4:28 pm

How to avoid drawing map every single tick

Post by munchor »

Code: Select all

function love.draw()
  currentMap:setDrawRange(player.translated, 0, 800, 640)
  love.graphics.translate(-player.translated, 0)

  --love.graphics.push()
  currentMap:draw()
  --love.graphics.pop()

  --love.graphics.push()
  love.graphics.draw(player.image, player.x, player.y)
  --love.graphics.pop()
end
That is my love.draw() function. It works just fine, but when there are lots of tiles in a 800*600 screen, the game renders really really slowly. I think it's because I'm drawing the map every single tick. How can I avoid drawing it every single tick?

Thank you.
User avatar
OmarShehata
Party member
Posts: 259
Joined: Tue May 29, 2012 6:46 pm
Location: Egypt
Contact:

Re: How to avoid drawing map every single tick

Post by OmarShehata »

You need to draw everything every single frame. It sounds counter intuitive but I've been told that trying to only redraw parts of the screen is actually slower than clearing the screen and drawing everything again, (at least that was for the set up I had in a project with SDL/OpenGL)

With that said, you should be able to render a lot of tiles without a slow down.

It's likely in your currentMap:draw() function. Can you post its contents?
User avatar
T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

Re: How to avoid drawing map every single tick

Post by T-Bone »

You should check out Canvas (https://love2d.org/wiki/Canvas) and Spritebatch (https://love2d.org/wiki/SpriteBatch). They work differently but both can be useful in this case.

Basically, the idea is that if some parts don't change, you can draw them once to some sort of buffer and then just draw that every frame. This can, in many cases, dramatically improve performance.

Spritebatches can only work with a single image source file, and you can add parts of it to the batch using Quads. The Spritebatch also doesn't need to know how large it's going to be, which is useful in some situations. It is also compatible with love-native-android which can be good to know.

Canvases (previously called Framebuffers) are fixed-size images basically, that you can draw to by passing a function similar to love.draw to using the Canvas:renderTo method. They allow you to draw basically anything.

Once you have created a Canvas or a Spritebatch, you can draw them by using love.graphics.draw inside love.draw like you'd normally do with an image or something.
User avatar
Boolsheet
Inner party member
Posts: 780
Joined: Wed Dec 29, 2010 4:57 am
Location: Switzerland

Re: How to avoid drawing map every single tick

Post by Boolsheet »

munchor wrote: That is my love.draw() function. It works just fine, but when there are lots of tiles in a 800*600 screen, the game renders really really slowly. I think it's because I'm drawing the map every single tick. How can I avoid drawing it every single tick?
Like OmarShehata and T-Bone said, you need to draw it everytime or store the intermediate result in a Canvas and draw that. If this is new to you, then you've only been exposed to applications that do the redrawing for you. LÖVE is a bit closer to the OpenGL API.

There can be many reasons for the slowdown. Hardware has its limits and maybe you already hit it. LÖVE has a few gotchas and maybe you did something in your code to get a perfomance hit. For that we need to see the full code. It doesn't have to be your game, it can also be a small example (like a scene out of the game) where you see the same effect.
T-Bone wrote:The Spritebatch also doesn't need to know how large it's going to be, which is useful in some situations.
SpriteBatches do not dynamically allocate the memory, if you mean that. The size argument of love.graphics.newSpriteBatch defaults to 1000 if you leave it out.
Shallow indentations.
User avatar
T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

Re: How to avoid drawing map every single tick

Post by T-Bone »

Boolsheet wrote:
munchor wrote: That is my love.draw() function. It works just fine, but when there are lots of tiles in a 800*600 screen, the game renders really really slowly. I think it's because I'm drawing the map every single tick. How can I avoid drawing it every single tick?
Like OmarShehata and T-Bone said, you need to draw it everytime or store the intermediate result in a Canvas and draw that. If this is new to you, then you've only been exposed to applications that do the redrawing for you. LÖVE is a bit closer to the OpenGL API.

There can be many reasons for the slowdown. Hardware has its limits and maybe you already hit it. LÖVE has a few gotchas and maybe you did something in your code to get a perfomance hit. For that we need to see the full code. It doesn't have to be your game, it can also be a small example (like a scene out of the game) where you see the same effect.
T-Bone wrote:The Spritebatch also doesn't need to know how large it's going to be, which is useful in some situations.

SpriteBatches do not dynamically allocate the memory, if you mean that. The size argument of love.graphics.newSpriteBatch defaults to 1000 if you leave it out.
Ah, but that's the number of stuff that can be drawn to the SpriteBatch, not the size of the SpriteBatch (as in numbers of pixels in width and height). The only reason I mention it is that it is a clear difference between SpriteBatches and Canvases.
User avatar
Boolsheet
Inner party member
Posts: 780
Joined: Wed Dec 29, 2010 4:57 am
Location: Switzerland

Re: How to avoid drawing map every single tick

Post by Boolsheet »

T-Bone wrote:Ah, but that's the number of stuff that can be drawn to the SpriteBatch, not the size of the SpriteBatch (as in numbers of pixels in width and height). The only reason I mention it is that it is a clear difference between SpriteBatches and Canvases.
Oh, ok, but you do not "draw to the SpriteBatch". You give it the information where you want the images drawn. When you then draw the SpriteBatch, it will go through the list and draw everything in one call.
Shallow indentations.
User avatar
Lafolie
Inner party member
Posts: 809
Joined: Tue Apr 05, 2011 2:59 pm
Location: SR388
Contact:

Re: How to avoid drawing map every single tick

Post by Lafolie »

The term "the size of the spriteBatch is 10" says to me that the spriteBatch in question can hold 10 quads. In fact, spriteBatches don't have any attributes such as width or height, as a spriteBatch is a collective object and has nothing by itself that is drawn. Indeed, it is possible to retrieve the width/height of the source image, but that has little to do with the spriteBatch itself.

That's a pretty poor example of how a spriteBatch differs from a Canvas. A batch is used for speedily drawing images that use a texture atlas (a quad), and is particularly useful for repetitions of said images. It is essentially a collection of quads and a reference to the image that the quads should refer to.

A canvas is used for dynamic drawing operations; drawing things to something that isn't the screen. This can be used to make composite images and all manner of effects. I once used them to "flatten" blood particles onto a background, making them permanent but cost-effective.
Do you recognise when the world won't stop for you? Or when the days don't care what you've got to do? When the weight's too tough to lift up, what do you? Don't let them choose for you, that's on you.
munchor
Prole
Posts: 39
Joined: Sun Jun 10, 2012 4:28 pm

Re: How to avoid drawing map every single tick

Post by munchor »

I'm using AdvTiledLoader, so the map:draw() function can be found here.

I'll give the Canvas a try, it looks good.

Edit
I tried the canvas, it didn't work very well. On love.load() I have "myCanvas = love.graphics.newCanvas(800, 640)"

Code: Select all

  myCanvas:renderTo(function()
                      currentMap:draw()
                   end)
  love.graphics.draw(myCanvas)
But the map isn't drawn correctly, it's all messed up :S If I replace all those lines with "currentMap:draw()" it works just fine.
User avatar
Jasoco
Inner party member
Posts: 3726
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: How to avoid drawing map every single tick

Post by Jasoco »

Not sure what renderTo is. What you probably want is setTarget.

Code: Select all

love.graphics.setTarget(myCanvas)
--Draw your map and everything you want on your canvas
love.graphics.setTarget() --To return the drawing to the main screen
You'd call that whenever you need to redraw the map. And then simply love.graphics.draw(myCanvas, x, y) every frame. Only call the map drawing stuff when it's needed like when something changes and you'll only need to draw a single image every frame. Well, plus whatever you want to draw that's not the map.

Just remember that not everyone can support canvases.
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: How to avoid drawing map every single tick

Post by Nixola »

Jasoco wrote:Not sure what renderTo is. What you probably want is setTarget.
1) Isn't it setCanvas?
2) canvas:renderTo(functionThatDrawsSomething() --[

Code: Select all

] end) and
love.graphics.setCanvas(canvas)
functionThatDrawsSomething()
love.graphics.setCanvas()
are the same thing
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 7 guests