Camera to view all objects

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.
Post Reply
User avatar
leiradel
Party member
Posts: 184
Joined: Thu Mar 11, 2010 3:40 am
Location: Lisbon, Portugal

Camera to view all objects

Post by leiradel »

Hi All,

I'm developing a game where all objects have a getExtents() method which returns the minimum and maximum coordinates occupied by the object. I'm trying to develop a camera that will get the extents of all visible objects and scale and translate things appropriately to have them all appear on the screen. I've tried many things but can't seem to make it work:

Code: Select all

function love.draw()
  -- the background is not scaled nor translated 
  love.graphics.draw( back, 0, 0 )

  -- scale and translate the coordinate system
  local minx, miny, maxx, maxy = self.visible[ 1 ]:getExtents()
  local len = #self.tracked
  
  for i = 2, len do
    local ominx, ominy, omaxx, omaxy = self.visible[ i ]:getExtents()
    
    if ominx < minx then
      minx = ominx
    end
    
    if ominy < miny then
      miny = ominy
    end
    
    if omaxx > maxx then
      maxx = omaxx
    end
    
    if omaxy > maxy then
      maxy = omaxy
    end
  end
  
  local dx = maxx - minx
  local dy = maxy - miny
  local scale
  
  if dx > dy then
    scale = love.graphics.getWidth() / dx
  else
    scale = love.graphics.getHeight() / dy
  end
  
  love.graphics.translate( -minx, -miny )
  love.graphics.scale( scale )

  -- draw the objects
  for i = 1, len do
    self.visible[ i ]:draw()
  end
end
Any tips on what I'm doing wrong?

Thanks,

Andre

EDIT: I've found that if I swap the translate and scale calls it works, I have no idea how I missed it. The problem that I'm having now is to centralize the objects on the screen, i.e. if the objects are spread along the horizontal ax I want to make them appear with the same space left on the top and on the bottom.
User avatar
BlackBulletIV
Inner party member
Posts: 1261
Joined: Wed Dec 29, 2010 8:19 pm
Location: Queensland, Australia
Contact:

Re: Camera to view all objects

Post by BlackBulletIV »

I can't see where you're calling push() and pop(). Try this:

Code: Select all

  love.graphics.push()
  love.graphics.scale( scale )
  love.graphics.translate( -minx, -miny )
  
  -- draw the objects
  for i = 1, len do
    self.visible[ i ]:draw()
  end
  
  love.graphics.pop()
User avatar
leiradel
Party member
Posts: 184
Joined: Thu Mar 11, 2010 3:40 am
Location: Lisbon, Portugal

Re: Camera to view all objects

Post by leiradel »

BlackBulletIV wrote:I can't see where you're calling push() and pop()
Translation, scaling and rotation only last until love.draw exits. Anyway, I've already added push and pop to print some debug info on the screen.

Thanks,

Andre
User avatar
BlackBulletIV
Inner party member
Posts: 1261
Joined: Wed Dec 29, 2010 8:19 pm
Location: Queensland, Australia
Contact:

Re: Camera to view all objects

Post by BlackBulletIV »

Oh so you don't actually need push() and pop()? I thought you did. Well I learned something new. :)
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Camera to view all objects

Post by vrld »

leiradel wrote:The problem that I'm having now is to centralize the objects on the screen, i.e. if the objects are spread along the horizontal ax I want to make them appear with the same space left on the top and on the bottom.
You are nearly there. Consider this image:
Camera center
Camera center
camera_center.png (12.04 KiB) Viewed 1672 times
You already calculated the upper left (ul) and lower right (lr) corners:

Code: Select all

ul = (minx, miny)
lr = (maxx, maxy)
You then translate to (-minx, -miny), which is equivalent of moving the upper left corner to the origin (0); but to center the scene, you need to move the point c to the origin.
How do you get c? Simple: It's halfway from ul to lr, i.e.

Code: Select all

c = (ul + lr) / 2 = ( (minx + maxx)/2, (miny + maxy)/2 )
If you do this you'll notice that only a quarter of your objects will be drawn. That's because LÖVE's coordinate system has it's origin in the upper left edge of the screen rather than the screen center. You can compensate for that by moving the upper left edge of the screen to the center, i.e. translate by (-screen_width/2, -screen_height/2).
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
leiradel
Party member
Posts: 184
Joined: Thu Mar 11, 2010 3:40 am
Location: Lisbon, Portugal

Re: Camera to view all objects

Post by leiradel »

Thanks vrld, for a nice explanation (with graphics!)

I've managed to make it work:

Code: Select all

  local dx = self.maxx - self.minx
  local dy = self.maxy - self.miny
  local scale, x0, y0
  
  if dx > dy then
    scale = love.graphics.getWidth() / dx
    x0 = -self.minx
    y0 = -self.miny - ( dy - love.graphics.getHeight() / scale ) / 2
  else
    scale = love.graphics.getHeight() / dy
    x0 = -self.minx - ( dx - love.graphics.getWidth() / scale ) / 2
    y0 = -self.miny
  end
  
  love.graphics.scale( scale )
  love.graphics.translate( x0, y0 )
I'm pretty sure I can get away with love.graphics.get[Width|Height] / scale if I add an additional translate call before the scale call.

Thanks again,

Andre
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 4 guests