Page 1 of 1

Problem with drawing only the cubes on screen.

Posted: Thu Aug 09, 2018 1:06 pm
by Bogdan705
So I decided to optimize my game by only drawing cubes that are visible ( already been doing that, and by that I will explain in a bit ) and those that are on screen. Problem is, there are only so many cubes on the screen at a time, yet it tells me it draws around 900+ of them.
love 2018-08-08 21-34-01-166.jpg
love 2018-08-08 21-34-01-166.jpg (543.14 KiB) Viewed 5622 times
When I'm zoomed in at 100% ( default zoom and above ) it's around 900+. At 200% or when I'm at the edge, around 700+. At some point, the number of drawn cubes caps at 1200+ when I zoom out enough.
Now by visible I mean cubes that should theoretically be visible from the isometric point of view. Cubes that have a neighbor to the top, left and right are "not visible". If any of those three conditions is not met, then it "is visible".
After that I use two functions I made, normalToIsoX and normalToIsoY to find out the x,y coordinates of the cube, based on its x,y,z coordinate on the grid. After that I use cam:cameraCoords() on isoX and isoY to find the cubes x,y on the screen ( I use hump.camera )
Now here is the code :

Code: Select all

t.cubeIsVisible = function(x,y,z)
  local xE = false
  local yE = false
  local zE = false
  if (x + 1) > #grid then xE = true end
  if (y + 1) > #grid[x] then yE = true end
  if (z + 1) > #grid[x][y] then zE = true end
  if xE or yE or zE then return true end
  local n = 0
  if grid[x + 1][y][z] ~= 0 then n = n + 1 end
  if grid[x][(y + 1)][z] ~= 0 then n = n + 1 end
  if grid[x][y][(z + 1)] ~= 0 then n = n + 1 end
  local screenX, screenY = cam:cameraCoords(gridFuncs.normalToIsoX(x,y),gridFuncs.normalToIsoY(x,y,z,3))
  if n == 3 then
    return false
  elseif not (((screenX < -100*zoom) or (screenX > wW + 100*zoom)) and ((screenY < -100*zoom) or (screenY > wH + 100*zoom))) then
    return true
  end
end
I have no idea what is causing this problem. Could anyone help me please? Thank you. :rofl:

Re: Problem with drawing only the cubes on screen.

Posted: Thu Aug 09, 2018 1:13 pm
by Bogdan705
I realized that the edge xE,yE and zE might be making the game draw cubes on the border of the map so I decided to scrap and change the function. Now it still draws around 800+ at 100%, but only 400+ at 200%. One significant change though ( for the worse ), is that the game runs way slower now. Here is the new code :

Code: Select all

t.cubeIsVisible = function(x,y,z) -- checks if a cube is visible ( in this case covered up by other cubes )
  local screenX, screenY = cam:cameraCoords(gridFuncs.normalToIsoX(x,y),gridFuncs.normalToIsoY(x,y,z,3))
  if not (((screenX < -150) or (screenX > wW + 150)) and ((screenY < -150) or (screenY > wH + 150))) then
    local n = 0
    if gridFuncs.gridCheck(x+1,y,z,0,false) then n = n + 1 end
    if gridFuncs.gridCheck(x,y+1,z,0,false) then n = n + 1 end
    if gridFuncs.gridCheck(x,y,z+1,0,false) then n = n + 1 end
    if n == 3 then return false else return true end
  else return false end
end
And here is gridCheck()

Code: Select all

t.gridCheck = function(x,y,z,v,t) -- checks the grid for something, if search is outside the grid then it produces an error
  return pcall(function()
            if t then
              if grid[x][y][z] == v then else print(haha + ahah) end
            elseif not t then
              if grid[x][y][z] ~= v then else print(haha + ahah) end
            end end)
end
These two functions get called in another function that loops through the grid called gridDraw(), and gridDraw() in term gets called in love.draw. Also, in love.update I have this :

Code: Select all

  if camCycle >= 0.1 then
    -- zoom
    clientFuncs.camZoom()
    cam:zoomTo(zoom)
    -- get cam pos
    local x,y = cam:position()
    -- get the diff between the target pos and current pos
    local xDiff,yDiff = math.abs(isoX - x), math.abs(isoY - y)
    -- slow down if jumping or falling
    local m = 1
    if player.data.jumping or 
       gridFuncs.gridCheck(player.entity.pos.x,
                           player.entity.pos.y,
                           player.entity.pos.z - 1,0,true) then m = 0.3 end
    if xDiff < 5 then xDiff = 0 else xDiff = xDiff / (20 / (settings.camSpeed/10*player.entity.stats.speed*m)) end
    if yDiff < 5 then yDiff = 0 else yDiff = yDiff / (20 / (settings.camSpeed/10*player.entity.stats.speed*m)) end
    camCycle = 0
    -- move cam x pos
    if isoX > x then
      cam:lookAt(x + xDiff,y)
    else
      cam:lookAt(x - xDiff,y)
    end
    -- update cam pos
    local x,y = cam:position()
    -- move cam y pos
    if isoY > y then
      cam:lookAt(x,y + yDiff)
    else
      cam:lookAt(x,y - yDiff)
    end
  end
And this :

Code: Select all

camCycle = camCycle + 1*dt*settings.camSpeed
And I think I created some sort of feedback loop, and that in turn slows down the game.

Re: Problem with drawing only the cubes on screen.

Posted: Thu Aug 09, 2018 1:18 pm
by Bogdan705
Nevermind I managed to make the camera run smooth again, but it still says it renders 800+ cubes. Here is a .love file
ooga.love
(505.07 KiB) Downloaded 246 times

Re: Problem with drawing only the cubes on screen.

Posted: Thu Aug 09, 2018 1:40 pm
by Bogdan705
I looked at my memory usage and it says love uses 60mb. Is that a lot or not much in terms of Love2D standards ?

Re: Problem with drawing only the cubes on screen.

Posted: Thu Aug 09, 2018 2:13 pm
by 0x72

Code: Select all

 not (((screenX < -150) or (screenX > wW + 150)) and ((screenY < -150) or (screenY > wH + 150)))  
renders 1,3,5,7,9:

Code: Select all

region #5 is your viewport and everything else is not visible:

1|2|3
-+-+-
4|5|6
-+-+-
7|8|9
You want to render only 5 (viewport) so try changing and keyword to an or.

Code: Select all

 not ((screenX < -150) or (screenX > wW + 150)) or ((screenY < -150) or (screenY > wH + 150))  
or express differently:

Code: Select all

  ((-150 < screenX) and (screenX < wW + 150)) and ((-150 < screenY) and (screenY < wH + 150)) -- "inside" instead "not outside"  
Also: this solution you have iterates over all the cubes each frame. If it ever become a performance issue read about spatial hashing.
It depends on the size of your world, but I'm already not getting steady 60 with the map you have there - 20181 cubes. cubeIsVisible is responsible for more then 91% time in the gridDraw (after fixing the condition and actually rendering around 60 cubes).

Also: it looks like your coords are anchored to corners so 150 might not be perfect value: this one worked for me better:

Code: Select all

  ((-250 < screenX) and (screenX < wW)) and ((-250 < screenY) and (screenY < wH))

Re: Problem with drawing only the cubes on screen.

Posted: Thu Aug 09, 2018 5:29 pm
by Bogdan705
:awesome: :awesome: :awesome: Thank you a lot

Re: Problem with drawing only the cubes on screen.

Posted: Thu Aug 09, 2018 5:44 pm
by Bogdan705
I will try your solution + spatial hashing + capping the framerate and see what the result is.

Re: Problem with drawing only the cubes on screen.

Posted: Sat Aug 11, 2018 7:27 am
by pedrosgali
I'd also suggest drawing your cubes to a canvas and checking each frame if you need to redraw it. So if the camera moves redraw but otherwise just draw the previous render to the screen. I posted an isometric map generation example on another thread on here, I'd leave a link here but I'm on my phone so you'll have to do a search if you want to download it for the code. But using the above method I got a consistent 60 fps regardless of how many tiles I needed on screen (Until I moved the camera at which point it could get a bit laggy if there were too many objects to render.) Since you have players moving you can just draw them after the canvas render.