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.
How to avoid drawing map every single tick
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
- 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
Definitely notKadoba wrote:But I don't think ATL is the problem in this situation...
@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)
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.
Re: How to avoid drawing map every single tick
And what is wrong with that? I think it's fine :SRoland_Yonaba wrote:Also, maybe you might want to reconsider the way you get solid tiles.Kadoba wrote:But I don't think ATL is the problem in this situation...
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.
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
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
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.
Re: How to avoid drawing map every single tick
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 lotKadoba 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
Re: How to avoid drawing map every single tick
Opps. Yes they're the same. I fixed my post.munchor wrote:Is blockedTiles the same thing as solidTiles?
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 ?!
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 ?!
Re: How to avoid drawing map every single tick
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.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 ?!
Re: How to avoid drawing map every single tick
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:Isn't OpenGL handling the frame buffering (double/tripple buffer) ?!
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.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 ?!
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.
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.
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: Bing [Bot], Google [Bot] and 6 guests