## 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.
Party member
Posts: 399
Joined: Mon Jan 10, 2011 8:25 am
Location: Oklahoma

### Re: How to avoid drawing map every single tick

ATL has spritebatch support built in. You just need to change map.useSpriteBatch to true and it should do the rest automatically. Canvas support is something I'm hoping to put into next version but I'm waiting for Tiled 0.9.0 to come out before I start breaking things since ATL needs another major overhaul.

But I don't think ATL is the problem in this situation. I get 33 FPS normally but it jumps up to about 170 FPS if I comment out your love.update. It jumps up to 320 FPS if I set the map to use sprite batches.

Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

### Re: How to avoid drawing map every single tick

Kadoba wrote:But I don't think ATL is the problem in this situation...
Definitely not

@munchor: I guess you have collision detection problems mostly because of how the way you perform it, actually.
When a rectangle shape is moving right, for instance, collision checks need to be performed on the right edge.
Generally, people just checks for collision on the upper-right AND down-right corners.
I made a picture, to explain. Yeah, it's a crap, but I hope you'll get my point.

Also, maybe you might want to reconsider the way you get solid tiles.
Actually, what you are doing is looping through all tiles, to build a list of those who are collidable before entering the game loop.
Then each time the player moves, you basically tests if the tiles where the player is trying to is listed inside these collidables tiles or not.

Code: Select all

function getSolidTiles(map)
local collidableTiles = {}
local layer = map.tl["map"]
for tileX, tileY, tile in layer.tileData:iterate() do
if tile and tile.properties.type == "block" then
local tile = {}
tile.x = tileX
tile.y = tileY
table.insert(collidableTiles, tile)
end
end
return collidableTiles
end

currentMap.isSolid = function(x, y)
for i = 1, #currentMap.solidTiles do
if x == currentMap.solidTiles[i].x and y == currentMap.solidTiles[i].y then
return true
end
end

currentMap.solidTiles = getSolidTiles(currentMap)

Well, it might work, but this is pretty costly. Fact is, it might be the other reason to the performance drop you are running to.
I suggest you check ATL's API. I am pretty sure there is a method to check if tile is walkable or not, and very simply.
Attachments
test.png (22.47 KiB) Viewed 1911 times

munchor
Prole
Posts: 39
Joined: Sun Jun 10, 2012 4:28 pm

### Re: How to avoid drawing map every single tick

Roland_Yonaba wrote:
Kadoba wrote:But I don't think ATL is the problem in this situation...
Also, maybe you might want to reconsider the way you get solid tiles.
Actually, what you are doing is looping through all tiles, to build a list of those who are collidable before entering the game loop.
Then each time the player moves, you basically tests if the tiles where the player is trying to is listed inside these collidables tiles or not.
And what is wrong with that? I think it's fine :S

Regarding the collision, I tried to do both edges, and the collision errors are exactlyy the same:

Code: Select all

  if player.vx > 0 then
for i = 0, player.vx - 1 do
if currentMap.isSolid(player.getTile(player.x + 16, player.y, 16, 16)) and currentMap.isSolid(player.getTile(player.x + 16, player.y + 16, 16, 16)) then
player.vx = 0
else
player.x = player.x + 1
player.translated = player.translated + 1
end
end
else
for i = 0, math.abs(player.vx) - 1 do
if currentMap.isSolid(player.getTile(player.x - 1, player.y, 16, 16)) and currentMap.isSolid(player.getTile(player.x - 1, player.y + 16, 16, 16)) then
player.vx = 0
else
player.x = player.x - 1
player.translated = player.translated - 1
end
end
end

if player.vy > 0 then
for i = 0, player.vy - 1 do
if currentMap.isSolid(player.getTile(player.x, player.y + 16, 16, 16)) and currentMap.isSolid(player.getTile(player.x + 16, player.y + 16, 16, 16)) then
player.vy = 0
else
player.y = player.y + 1
end
end
else
for i = 0, math.abs(player.vy) - 1 do
if currentMap.isSolid(player.getTile(player.x, player.y - 1, 16, 16)) and currentMap.isSolid(player.getTile(player.x + 16, player.y - 1, 16, 16)) then
player.vy = 0
else
player.y = player.y - 1
end
end
end
Edit
So, instead of checking first and last edge, I check all edge pixels, and it works just fine

Code: Select all

  if player.vx > 0 then
for i = 0, player.vx - 1 do
if player.collidingRight(player.currentMap) then
player.vx = 0
else
player.x = player.x + 1
player.translated = player.translated + 1
end
end
else
for i = 0, math.abs(player.vx) - 1 do
if player.collidingLeft(player.currentMap) then
player.vx = 0
else
player.x = player.x - 1
player.translated = player.translated - 1
end
end
end

if player.vy > 0 then
for i = 0, player.vy - 1 do
if player.collidingBelow(player.currentMap) then
player.vy = 0
else
player.y = player.y + 1
end
end
else
for i = 0, math.abs(player.vy) - 1 do
if player.collidingAbove(currentMap) then
player.vy = 0
else
player.y = player.y - 1
end
end
end
I still feel like it could be optimized, but I'm not sure.

Party member
Posts: 399
Joined: Mon Jan 10, 2011 8:25 am
Location: Oklahoma

### Re: How to avoid drawing map every single tick

It can be done much easier if you just crate a 2d array for blocked tiles. Iterating over and checking every blocked tile is much less efficient.

Code: Select all

local solidTiles

local function getSolidTiles(map)
solidTiles = setmetatable({},  {__call = function(self, x, y) return self[x] and self[x][y] end})
for x, y, tile in map.tl["map"]:iterate() do
if tile.properties.type == "block" then
if not solidTiles[x] then solidTiles[x] = {} end
solidTiles[x][y] = true
end
end
end

local function movePlayer(x,y)
if not solidTiles(x, y) then
player.x = x
player.y = y
end
end
Last edited by Kadoba on Fri Aug 24, 2012 6:11 pm, edited 1 time in total.

munchor
Prole
Posts: 39
Joined: Sun Jun 10, 2012 4:28 pm

### Re: How to avoid drawing map every single tick

Kadoba wrote:It can be done much easier if you just crate a 2d array for blocked tiles. Iterating over and checking every blocked tile is much less efficient.

Code: Select all

local solidTiles

local function getSolidTiles(map)
solidTiles = setmetatable({},  {__call = function(self, x, y) return self[x] and self[x][y] end})
for x, y, tile in map.tl["map"]:iterate() do
if tile.properties.type == "block" then
if not blockedTiles[x] then blockedTiles[x] = {} end
blockedTiles[x][y] = true
end
end
end

local function movePlayer(x,y)
if not solidTiles(x, y) then
player.x = x
player.y = y
end
end
Is blockedTiles the same thing as solidTiles? Thanks a lot, that's a MFS (memory for speed) optimization, I feel like it will improve game performance a lot

Party member
Posts: 399
Joined: Mon Jan 10, 2011 8:25 am
Location: Oklahoma

### Re: How to avoid drawing map every single tick

munchor wrote:Is blockedTiles the same thing as solidTiles?
Opps. Yes they're the same. I fixed my post.

Prole
Posts: 27
Joined: Sun May 16, 2010 10:47 pm

### Re: How to avoid drawing map every single tick

Hello there,

just stumbled across this thread... I think the initial question wasn't answered !
Isn't OpenGL handling the frame buffering (double/tripple buffer) ?!

So I don't really have to keep another copy of the screen in a canvas. Updating only
the changed part of the screen should do the job, or am I wrong ?!

Ragzouken
Citizen
Posts: 84
Joined: Fri Aug 10, 2012 7:59 am
Contact:

### Re: How to avoid drawing map every single tick

Adamantos wrote:So I don't really have to keep another copy of the screen in a canvas. Updating only
the changed part of the screen should do the job, or am I wrong ?!
My understanding is that at the beginning of each love.draw call, the screen is clear again and so you will have to manually redraw something each frame, even if it is only a static canvas you've been keeping.

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

Adamantos wrote:Isn't OpenGL handling the frame buffering (double/tripple buffer) ?!
Yes and no. This is part of the OS and driver implementation and is not specified in the standard. Being implementation defined, the behaviour is different for everyone.
Adamantos wrote:So I don't really have to keep another copy of the screen in a canvas. Updating only the changed part of the screen should do the job, or am I wrong ?!
Like Ragzouken said, the first thing you'll notice is that love.graphics.clear is called immediately before love.draw. This usually just clears the screen buffer (sets the entire buffer to the clear color set with love.graphics.setBackgroundColor), but can also clear the Canvas isntead if one is still set. This may be considered an issue or bug and could be changed in the future. Always remember to unset your Canvas.

The love.graphics.clear before love.draw is easy to remove, but now you'll see the effects of double buffering (if it's active). You would have to draw changes to both buffers to prevent it from flickering. Now imagine doing this with triple buffering where the swap behaviour may be unpredictable. It would not be possible to tell which buffer you're drawing to.

Speaking of swap behaviour, some implementations define the content of the swapped buffer as undefined. It may contain garbage and not the previous frame.

Wait, I have one more! OpenGL has a pixel ownership test. Implementations can choose to not render pixels of the OpenGL window that are obscured by other windows making it necessary to redraw everything just to be sure that all is drawn.

Does that answer it?
Shallow indentations.

Prole
Posts: 27
Joined: Sun May 16, 2010 10:47 pm

### Re: How to avoid drawing map every single tick

Okay.... thank you for your answer !

I will give it a try and remove the love.graphics.clear() from the love.run() function.
And to prevent flickering I have to do every draw operation atleast for two/three consecutive frames.

### Who is online

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