Page 1 of 1

Finding the translation to offset the zoom.

Posted: Sat Sep 20, 2014 8:38 pm
by Andynonomous
Hello out there,

I am hoping (more like desperately pleading) that somebody here will be able to help me. I have a problem regarding scaling that I have been stuck on for years! I know that it is a relatively simple problem, and I've tried my best to find a solution, but nothing I have tried has worked.

The Context
My project is top-down and implements a camera system which will follow the player and keep him close to the center of the screen.
The Problem
So naturally when I use love.graphics.scale() it zooms from the top left. I need to implement zooming over any particular point I choose. I know that there are plenty of tutorials and articles online explaining this but never any that I've been able to fully grasp or translate into my own working code.
What I Hope For
I'm going to post my code below consisting of my camera object and my main file. I'm effectively begging the love community to show me how to get this working within the context of the code I have. If my camera system is inadequate any examples of how to do this using the hump camera would be helpful as well. I've looked at all the info I could find regarding that camera system.
In a Nutshell
When it comes down to it, all I really need is the formula to arrive at the x and y values I need to translate the camera by to offset the zoom.
The Code
Most of the relevant code is in the mouse handling functions responding to 'mouse wheel up and down' input. The code in there now was adapted from another love tutorial implementing zooming but is not working in the context of my code. Please help if you can, at the risk of sounding dumb, I fully admit that I cannot figure this out on my own. Been trying a long time. Thanks in advance!

The Camera

Code: Select all

Camera = {}

--------------------------- Basic Functions -||
function Camera:new(o)
	o=o or {}
	setmetatable(o, self)
	self.__index = self
	return o
end

function Camera:init(x, y)
	self.width = love.window.getWidth()
	self.height = love.window.getHeight()
	self.halfWidth = self.width / 2
	self.halfHeight = self.height / 2
	self.x = x
	self.y = y	
	self.rotation = 0
	self.zoom = 1
	self.displayInfo = true
end

function Camera:set()
	love.graphics.push()
	love.graphics.rotate(-self.rotation)
	love.graphics.scale(self.zoom, self.zoom)
	love.graphics.translate(-self.x, -self.y)
	
end

function Camera:unset()
	love.graphics.pop()
end

function Camera:reset()
	self.x = 0
	self.y = 0
	self.rotation = 0
	self.zoom = 1
end

function Camera:move(dx, dy)
	self.x = self.x + (dx or 0)
	self.y = self.y + (dy or 0)
end

function Camera:rotate(dr)
	self.rotation = self.rotation + dr
end

function Camera:scale(amt)
	amt = amt or 1	
	oldZoom = self.zoom
	self.zoom = self.zoom * amt	
	return oldZoom
end

function Camera:setPosition(x, y)
	self.x =  x or self.x
	self.y =  y or self.y
end

function Camera:setScale(amt)	
	self.zoom = amt or self.zoom	
end

function Camera:incScale(amt)
	self.zoom = self.zoom + amt
end
-----------------------------Extra Functions -||
function Camera:inform()
	local info = tostring(self.x) .. ", " .. tostring(self.y)
	love.graphics.print(info, 0, 0)	
	love.graphics.print(self.zoom, 0,  12)
end

function Camera:toggleInfo() 
	self.displayInfo = not self.displayInfo
end

function Camera:draw()
	if self.displayInfo then self:inform() end
end
Main

Code: Select all

require 'camera'
----------------------------Love functions -||
function love.load()
	camera = Camera:new()
	camera:init(0, 0)	
	img = love.graphics.newImage('testShip.png')
	--I start the ship so that it is at the centre of the camera's view 
	shipWorldx = camera.halfWidth  
	shipWorldy = camera.halfHeight 
end

function love.update(dt)
	cameraInputHandling()	--This is here for testing purposes
end

function love.draw()
	camera:set()	
	love.graphics.draw(img, shipWorldx, shipWorldy)		
	camera:unset()
	--Draw a circle at the centre of the screen for reference
	love.graphics.setColor(0, 255, 0)
	love.graphics.circle('fill', camera.halfWidth, camera.halfHeight, 15, 360)
	love.graphics.setColor(255, 255, 255)		
	camera:draw()	 --For now, simply displays camera's world co-ordinates
end

function love.keyreleased(key)
	if key == 'escape' then
		love.event.push('quit')
	end
	if key == 'i' then
		camera:toggleInfo()
	end
	if key == 'r' then
		camera:reset()
	end		
end
--I must be doing something wrong in here...right?
function love.mousepressed(x, y, button) 	if button == 'wu' then	
		local mousex = x - camera.x
		local mousey = y - camera.y
		local lastZoom = camera.zoom
		camera:incScale(0.1)
		local newx = mousex * (camera.zoom / lastZoom)
		local newy = mousey * (camera.zoom / lastZoom)
		local tx = mousex - newx	
		local ty = mousey - newy
		camera:move(tx, ty) 		
	end
	if button == 'wd' then
		local mousex = x - camera.x
		local mousey = y - camera.y
		local lastZoom = camera.zoom
		camera:incScale(-0.1)
		local newx = mousex * (camera.zoom / lastZoom)
		local newy = mousey * (camera.zoom / lastZoom)
		local tx = mousex - newx	
		local ty = mousey - newy
		camera:move(tx, ty) 
	end
end
---------------------------------My functions -||
function cameraInputHandling()
	if love.keyboard.isDown('right') then camera:move(1) end
	if love.keyboard.isDown('left') then camera:move(-1) end
	if love.keyboard.isDown('up') then camera:move(0, -1) end
	if love.keyboard.isDown('down') then camera:move(0, 1) end
end

Re: Finding the translation to offset the zoom.

Posted: Sat Sep 20, 2014 10:46 pm
by Robin
Please upload a .love if you have a question.

I think something like this will work as you expect:

Code: Select all

function Camera:set()
   love.graphics.push()
   love.graphics.rotate(-self.rotation)
   local w = love.graphics.getWidth() / 2
   local h = love.graphics.getHeight() / 2
   love.graphics.translate(-w, -h)
   love.graphics.scale(self.zoom, self.zoom)
   love.graphics.translate(w - self.x, h - self.y)  
end

Re: Finding the translation to offset the zoom.

Posted: Sun Sep 21, 2014 3:47 pm
by Andynonomous
Thank you for your response, unfortunately it is still not working correctly. I'm attaching the .love file, if you could offer any more help I would really appreciate it. This problem is the bane of my existence. I can't express how frustrated I am. I even have a demo program in which the functionality I'm looking for is working correctly, but for some reason it doesn't behave the same way when I try and port it over to my system. I can post that code as well if it would help you guys help me. I know you guys aren't babysitters or anything, but I really need somebody to explain this like I'm five. Thanks again!

Re: Finding the translation to offset the zoom.

Posted: Sun Sep 21, 2014 5:04 pm
by Robin
I tried, but I couldn't make it work. Maybe it would be easier if you use Kikito's gamera library.

Re: Finding the translation to offset the zoom.

Posted: Sun Sep 21, 2014 6:31 pm
by Andynonomous
Thanks, I'll take a look at it.