I’m trying to write a simple 2D camera that can pan around a 2D scene and zoom in on specific points. I’ve been working on trying to get the camera to pan and zoom at the same point.
Panning is straightforward, but writing a generic zoom seems to be pretty tricky. I can get both to work if the scene group is positioned at 0,0. If the group is offset, the zoom breaks, and I’ve not been able to figure out how to handle that case.
I’ve tried both setting anchorChildren=true (which breaks the zoom) and trying to derive the offset from within the camera.fixReference function.
Does anyone have any ideas of how to handle this case?
Here’s my test code:
main.lua
[lua]
require “camera”
local group=display.newGroup()
camera.view(group)
– changing these numbers will not influence the original scene, but will through the camera’s fixReference function completely off!
– group.anchorChildren=true uncomment to break
group.x,group.y=1000,0 – set to 0,0 to make everything work
local function createScene()
local bg=display.newRect(group,display.contentCenterX,display.contentCenterY,display.contentWidth,display.contentHeight)
bg.fill={0.5,0.2,0.2}
bg:setStrokeColor(255, 0, 0)
bg.strokeWidth=5
local c=display.newCircle(group,display.contentCenterX,display.contentCenterY,20)
c.fill={1,0,0}
local ct=display.newCircle(display.contentCenterX,display.contentCenterY,5)
ct:setFillColor(255,127)
local cx,cy=group:contentToLocal( display.contentCenterX, display.contentCenterY)
display.newLine(group,cx,cy,display.contentCenterX,display.contentCenterY).width=4
end
createScene()
function touch(event)
if event.phase==“began” then
touchId=event.id
end
if event.id~=touchId then
return false
end
if event.phase==“ended” then
local x,y=group:contentToLocal(event.x,event.y)
local dx,dy=10,10
display.newLine(group,x,y,x+dx,y+dy).strokeWidth=4
display.newLine(group,x,y,x-dx,y-dy).strokeWidth=4
display.newLine(group,x,y,x-dx,y+dy).strokeWidth=4
display.newLine(group,x,y,x+dx,y-dy).strokeWidth=4
local t=camera.panTo(event.x,event.y)
timer.performWithDelay(t,function()
local t=camera.zoom(2,display.contentCenterX,display.contentCenterY)
timer.performWithDelay( t, function()
camera.zoom(1,display.contentCenterX,display.contentCenterY)
end)
end)
end
return true
end
Runtime:addEventListener(“touch”,touch)
[/lua]
camera.lua
[lua]
local M={}
camera=M
local display=display
local transition=transition
local easing=easing
local print=print
local timer=timer
local debug=debug
local error=error
setfenv(1,M)
local group
local cameraTime=4000
function create()
group=display.newGroup()
group.anchorChildren=true
group.anchorX,group.anchorY=0.5,0.5
group.x,group.y=display.contentCenterX,display.contentCenterY
end
function view(obj)
group:insert(obj)
end
function panTo(x,y)
local dx,dy=display.contentCenterX-x,display.contentCenterY-y
transition.cancel(“pan”)
transition.cancel(“panzoom”)
if dx*dx+dy*dy==0 then
return 0
end
transition.to(group,{time=cameraTime,tag=“pan”,transition=easing.inOutCubic,x=group.x+dx,y=group.y+dy,onComplete=function()
end})
return cameraTime
end
local anchor
local function fixReference(x,y)
if anchor then
anchor:removeSelf()
end
– old anchor coordinates
local ox=(group.width*(group.anchorX-0.5))
local oy=(group.height*(group.anchorY-0.5))
local lx,ly=group:contentToLocal(x, y)
– compute the new anchor
group.anchorX=lx/group.width
group.anchorY=ly/group.height
anchor=display.newCircle(group,group.anchorX*group.width,group.anchorY*group.height,20)
anchor.fill={0,1,0}
– offset the group’s position to stop it jumping
group.x=group.x-ox+(group.width*(group.anchorX-0.5))
group.y=group.y-oy+(group.height*(group.anchorY-0.5))
end
function zoom(zoom,x,y)
if group.xScale==zoom then
return 0
end
if x and y and zoom>group.xScale then
fixReference(x,y)
end
transition.to(group,{time=cameraTime,tag=“zoom”,transition=easing.inOutCubic,xScale=zoom,yScale=zoom})
return cameraTime
end
create()
return M
[/lua]