How to limit panning

I am playing with a pan and zoom template. I figured out how to limit zooming, but how do i limit the panning of of an image. I kind of made a sloppy work around but it is bad, basically +5 to the if it goes to far left or up, or -5 it goes to far right or down. Here is the sample code.

-- -- Project: PinchZoom with Pan -- -- Date: August 19, 2010 -- -- Version: 1.1 -- -- File name: main.lua -- -- Author: Corona Labs (mikofh) -- -- Abstract: Pinch/Zoom Gesture sample app with Pan added -- -- Demonstrates: locations events, buttons, touch, Pan -- -- File dependencies: none -- -- Target devices: Devices only -- -- Limitations: Mutitouch not supported on Simulator -- -- Update History: -- v1.1 Added Simulator warning message -- -- Comments: Pinch and Zoom to scale the image on the screen. -- -- Sample code is MIT licensed, see http://www.coronalabs.com/links/code/license -- Copyright (C) 2010 Corona Labs Inc. All Rights Reserved. --------------------------------------------------------------------------------------- -- activate multitouch system.activate( "multitouch" ) local maxpos, maypos, maxminuspos, mayminuspos = 2000, 2000, -2000, -2000 -- add bkgd image to screen local background = display.newImage( "aquariumbackgroundIPhone.jpg", 0, 0 ) local function calculateDelta( previousTouches, event ) local id,touch = next( previousTouches ) if event.id == id then id,touch = next( previousTouches, id ) assert( id ~= event.id ) end local dx = touch.x - event.x local dy = touch.y - event.y return dx, dy end -- create a table listener object for the bkgd image function background:touch( event ) local result = true local phase = event.phase local previousTouches = self.previousTouches local numTotalTouches = 1 if ( previousTouches ) then -- add in total from previousTouches, subtract one if event is already in the array numTotalTouches = numTotalTouches + self.numPreviousTouches if previousTouches[event.id] then numTotalTouches = numTotalTouches - 1 end end if "began" == phase then -- Very first "began" event if ( not self.isFocus ) then -- Subsequent touch events will target button even if they are outside the contentBounds of button display.getCurrentStage():setFocus( self ) self.isFocus = true --miko collect values for panning self.myX = event.x-self.x self.myY = event.y-self.y -- Store initial position --self.isDragging = true --miko end collection previousTouches = {} self.previousTouches = previousTouches self.numPreviousTouches = 0 elseif ( not self.distance ) then local dx,dy if previousTouches and ( numTotalTouches ) \>= 2 then dx,dy = calculateDelta( previousTouches, event ) end -- initialize to distance between two touches if ( dx and dy ) then local d = math.sqrt( dx\*dx + dy\*dy ) if ( d \> 0 ) then self.distance = d self.xScaleOriginal = self.xScale self.yScaleOriginal = self.yScale print( "distance = " .. self.distance ) end end end if not previousTouches[event.id] then self.numPreviousTouches = self.numPreviousTouches + 1 end previousTouches[event.id] = event elseif self.isFocus then if "moved" == phase then if ( self.distance ) then local dx,dy if previousTouches and ( numTotalTouches ) \>= 2 then dx,dy = calculateDelta( previousTouches, event ) end if ( dx and dy ) then local newDistance = math.sqrt( dx\*dx + dy\*dy ) local scale = newDistance / self.distance print( "newDistance(" ..newDistance .. ") / distance(" .. self.distance .. ") = scale(".. scale ..")" ) if ( scale \> 0 ) then self.xScale = self.xScaleOriginal \* scale self.yScale = self.yScaleOriginal \* scale end --miko test ind her om xScale \< 1 og så juster ved at gange op. end else self.x = event.x - self.myX self.y = event.y - self.myY if (self.x \> maxpos) then self.x = maxpos elseif (self.x \< maxminuspos) then self.x = maxminuspos end if (self.y \> maypos) then self.y = maypos elseif (self.y \< mayminuspos) then self.y = mayminuspos end end if not previousTouches[event.id] then self.numPreviousTouches = self.numPreviousTouches + 1 end previousTouches[event.id] = event elseif "ended" == phase or "cancelled" == phase then --[[if numTotalTouches == 1 then --miko move panning with one finger only local myXnew = event.x local myYnew = event.y --calculate panning left/right/up/down local mydx = math.abs(myXnew - self.myX) local mydy = math.abs(myYnew - self.myY) if (mydx \> 50) then --right/left panning mydx = myXnew - self.myX if (mydx \> 50) then transition.to(self, { time=200, x=(self.x+50) } ) --self.x = self.x+50 elseif (mydx \< -50) then transition.to(self, { time=200, x=(self.x-50) } ) end elseif (mydy \> 50) then --up/down panning mydy = myYnew - self.myY if (mydy \> 50) then transition.to(self, { time=200, y=(self.y+50) } ) elseif (mydy \< -50) then transition.to(self, { time=200, y=(self.y-50) } ) end end --move --now set variables to new x,y self.myX = event.x self.myY = event.y end]]-- if previousTouches[event.id] then self.numPreviousTouches = self.numPreviousTouches - 1 previousTouches[event.id] = nil end if ( #previousTouches \> 0 ) then -- must be at least 2 touches remaining to pinch/zoom self.distance = nil else -- previousTouches is empty so no more fingers are touching the screen -- Allow touch events to be sent normally to the objects they "hit" display.getCurrentStage():setFocus( nil ) self.isFocus = false self.distance = nil self.xScaleOriginal = nil self.yScaleOriginal = nil -- reset array self.previousTouches = nil self.numPreviousTouches = nil end end end return result end -- Determine if running on Corona Simulator -- local isSimulator = "simulator" == system.getInfo("environment") -- Multitouch Events not supported on Simulator -- if isSimulator then msg = display.newText( "Multitouch not supported on Simulator!", 0, 20, "Verdana-Bold", 14 ) msg.x = display.contentWidth/2 -- center title msg.y = display.contentHeight/2 -- center title msg:setTextColor( 255,255,0 ) end -- register table listener background:addEventListener( "touch", background ) &nbsp;

Thanks,

Scott

  

Bump? (Sorry but I have waited 5 days)

First this code is very old.  Corona SDK has changed a lot since 2010.  It would also help to know what you are trying to do and how it’s not working. A more descriptive statement of the problem, the goal, what’s really happening, etc. would be really helpful to the community.

Rob

Sorry rob,
The code works fine, I would like the camera group to stop moving after a certain x and/or y cord. The way I have now is just not smooth. Here is my current unsmooth code
 

\</lua\> local perspective = require("perspective") local camera = perspective.createView() local screenSizeXR = -600 local screenSizeXL = 600 local screenSizeYU = 600 local screenSizeYD = -600 local background = display.newRect( display.contentCenterX, display.contentCenterY, 1600, 1200 ) camera:add(background, 3) background.alpha = 0 function looper() --loop 2 if ((background.x+camera.x)\<= (screenSizeXR+200)\*camera.xScale ) and (backgroundTouch ~= 1) then backgroundTouch =1 camera.x = (screenSizeXR\*camera.yScale) Runtime:removeEventListener( "tap", zooming ) Runtime:removeEventListener( "touch", zooming ) Runtime:addEventListener( "touch", addBack ) end if ((background.x+camera.x) \>= (screenSizeXL+200) \*camera.xScale ) and (backgroundTouch ~= 1) then backgroundTouch = 1 camera.x = (screenSizeXL\*camera.xScale)-200 Runtime:removeEventListener( "tap", zooming ) Runtime:removeEventListener( "touch", zooming ) Runtime:addEventListener( "touch", addBack ) end if ((background.y+camera.y) \>= (screenSizeYU+200)\*camera.yScale ) and (backgroundTouch ~= 1) then backgroundTouch = 1 print( "running" ) camera.y = (screenSizeYU\*camera.yScale)-100 Runtime:removeEventListener( "tap", zooming ) Runtime:removeEventListener( "touch", zooming ) Runtime:addEventListener( "touch", addBack ) end if ((background.y + camera.y)\<= (screenSizeYD+250)\*camera.yScale) and (backgroundTouch ~= 1) then backgroundTouch = 1 camera.y = (screenSizeYD+200)\*camera.yScale backgroundTouch = 1 Runtime:removeEventListener( "tap", zooming ) Runtime:removeEventListener( "touch", zooming ) Runtime:addEventListener( "touch", addBack ) end end timeLooper = timer.performWithDelay(1,looper, 0) -- create a table listener object for the bkgd image function zooming( event ) local result = true local phase = event.phase local previousTouches = camera.previousTouches local numTotalTouches = 1 if ( previousTouches ) then -- add in total from previousTouches, subtract one if event is already in the array numTotalTouches = numTotalTouches + camera.numPreviousTouches if previousTouches[event.id] then numTotalTouches = numTotalTouches - 1 end end if "began" == phase then -- Very first "began" event if ( not camera.isFocus ) then -- Subsequent touch events will target button even if they are outside the contentBounds of button display.getCurrentStage():setFocus( camera ) camera.isFocus = true --miko collect values for panning camera.myX = event.x-camera.x camera.myY = event.y-camera.y -- Store initial position --camera.isDragging = true --miko end collection previousTouches = {} camera.previousTouches = previousTouches camera.numPreviousTouches = 0 elseif ( not camera.distance ) then local dx,dy if previousTouches and ( numTotalTouches ) \>= 2 then dx,dy = calculateDelta( previousTouches, event ) end -- initialize to distance between two touches if ( dx and dy ) then local d = math.sqrt( dx\*dx + dy\*dy ) if ( d \> 0 ) then camera.distance = d camera.xScaleOriginal = camera.xScale camera.yScaleOriginal = camera.yScale end end end if not previousTouches[event.id] then camera.numPreviousTouches = camera.numPreviousTouches + 1 end previousTouches[event.id] = event elseif camera.isFocus then if "moved" == phase then powersSwitch = 0 powerSelect.alpha = 0 undoPower.alpha =0 stickPower.alpha =0 if ( camera.distance ) then local dx,dy if previousTouches and ( numTotalTouches ) \>= 2 then dx,dy = calculateDelta( previousTouches, event ) end if ( dx and dy ) then local newDistance = math.sqrt( dx\*dx + dy\*dy ) local scale = newDistance / camera.distance if ( scale \> 0 ) then if (scale \> 1 and camera.xScale \< .8) then camera.xScale = camera.xScaleOriginal \* scale camera.yScale = camera.yScaleOriginal \* scale end if (scale \< 1 and camera.xScale \> .4) then camera.xScale = camera.xScaleOriginal \* scale camera.yScale = camera.yScaleOriginal \* scale end end --miko test ind her om xScale \< 1 og så juster ved at gange op. end else system.deactivate( "multitouch" ) camera.x = event.x - camera.myX camera.y = event.y - camera.myY --print( "go right" ) if (camera.x \> maxpos) then camera.x = maxpos elseif (camera.x \< maxminuspos) then camera.x = maxminuspos end if (camera.y \> maypos) then camera.y = maypos elseif (camera.y \< mayminuspos) then camera.y = mayminuspos end end if not previousTouches[event.id] then camera.numPreviousTouches = camera.numPreviousTouches + 1 end previousTouches[event.id] = event elseif "ended" == phase or "cancelled" == phase then system.activate( "multitouch" ) --[[if numTotalTouches == 1 then --miko move panning with one finger only local myXnew = event.x local myYnew = event.y --calculate panning left/right/up/down local mydx = math.abs(myXnew - camera.myX) local mydy = math.abs(myYnew - camera.myY) if (mydx \> 60) then --right/left panning mydx = myXnew - camera.myX if (mydx \> 60) then transition.to(camera, { time=200, x=(camera.x+60) } ) --camera.x = camera.x+60 elseif (mydx \< -60) then transition.to(camera, { time=200, x=(camera.x-60) } ) end elseif (mydy \> 60) then --up/down panning mydy = myYnew - camera.myY if (mydy \> 60) then transition.to(camera, { time=200, y=(camera.y+60) } ) elseif (mydy \< -60) then transition.to(camera, { time=200, y=(camera.y-60) } ) end end --move --now set variables to new x,y camera.myX = event.x camera.myY = event.y end]]-- if previousTouches[event.id] then camera.numPreviousTouches = camera.numPreviousTouches - 1 previousTouches[event.id] = nil end if ( #previousTouches \> 0 ) then -- must be at least 2 touches remaining to pinch/zoom camera.distance = nil else -- previousTouches is empty so no more fingers are touching the screen -- Allow touch events to be sent normally to the objects they "hit" display.getCurrentStage():setFocus( nil ) camera.isFocus = false camera.distance = nil camera.xScaleOriginal = nil camera.yScaleOriginal = nil -- reset array camera.previousTouches = nil camera.numPreviousTouches = nil end end end return result end Runtime:addEventListener( "tap", zooming ) Runtime:addEventListener( "touch", zooming ) \</lua\>

Thanks,
Scott

I’m using this library and it can clamp the camera to certain x/y bonds simply by calling a setBounds() function. Check it out.

http://code.coronalabs.com/code/perspective-virtual-camera-system

It doesn’t do zoom so you’ll probably have to combine with your code.

Bump? (Sorry but I have waited 5 days)

First this code is very old.  Corona SDK has changed a lot since 2010.  It would also help to know what you are trying to do and how it’s not working. A more descriptive statement of the problem, the goal, what’s really happening, etc. would be really helpful to the community.

Rob

Sorry rob,
The code works fine, I would like the camera group to stop moving after a certain x and/or y cord. The way I have now is just not smooth. Here is my current unsmooth code
 

\</lua\> local perspective = require("perspective") local camera = perspective.createView() local screenSizeXR = -600 local screenSizeXL = 600 local screenSizeYU = 600 local screenSizeYD = -600 local background = display.newRect( display.contentCenterX, display.contentCenterY, 1600, 1200 ) camera:add(background, 3) background.alpha = 0 function looper() --loop 2 if ((background.x+camera.x)\<= (screenSizeXR+200)\*camera.xScale ) and (backgroundTouch ~= 1) then backgroundTouch =1 camera.x = (screenSizeXR\*camera.yScale) Runtime:removeEventListener( "tap", zooming ) Runtime:removeEventListener( "touch", zooming ) Runtime:addEventListener( "touch", addBack ) end if ((background.x+camera.x) \>= (screenSizeXL+200) \*camera.xScale ) and (backgroundTouch ~= 1) then backgroundTouch = 1 camera.x = (screenSizeXL\*camera.xScale)-200 Runtime:removeEventListener( "tap", zooming ) Runtime:removeEventListener( "touch", zooming ) Runtime:addEventListener( "touch", addBack ) end if ((background.y+camera.y) \>= (screenSizeYU+200)\*camera.yScale ) and (backgroundTouch ~= 1) then backgroundTouch = 1 print( "running" ) camera.y = (screenSizeYU\*camera.yScale)-100 Runtime:removeEventListener( "tap", zooming ) Runtime:removeEventListener( "touch", zooming ) Runtime:addEventListener( "touch", addBack ) end if ((background.y + camera.y)\<= (screenSizeYD+250)\*camera.yScale) and (backgroundTouch ~= 1) then backgroundTouch = 1 camera.y = (screenSizeYD+200)\*camera.yScale backgroundTouch = 1 Runtime:removeEventListener( "tap", zooming ) Runtime:removeEventListener( "touch", zooming ) Runtime:addEventListener( "touch", addBack ) end end timeLooper = timer.performWithDelay(1,looper, 0) -- create a table listener object for the bkgd image function zooming( event ) local result = true local phase = event.phase local previousTouches = camera.previousTouches local numTotalTouches = 1 if ( previousTouches ) then -- add in total from previousTouches, subtract one if event is already in the array numTotalTouches = numTotalTouches + camera.numPreviousTouches if previousTouches[event.id] then numTotalTouches = numTotalTouches - 1 end end if "began" == phase then -- Very first "began" event if ( not camera.isFocus ) then -- Subsequent touch events will target button even if they are outside the contentBounds of button display.getCurrentStage():setFocus( camera ) camera.isFocus = true --miko collect values for panning camera.myX = event.x-camera.x camera.myY = event.y-camera.y -- Store initial position --camera.isDragging = true --miko end collection previousTouches = {} camera.previousTouches = previousTouches camera.numPreviousTouches = 0 elseif ( not camera.distance ) then local dx,dy if previousTouches and ( numTotalTouches ) \>= 2 then dx,dy = calculateDelta( previousTouches, event ) end -- initialize to distance between two touches if ( dx and dy ) then local d = math.sqrt( dx\*dx + dy\*dy ) if ( d \> 0 ) then camera.distance = d camera.xScaleOriginal = camera.xScale camera.yScaleOriginal = camera.yScale end end end if not previousTouches[event.id] then camera.numPreviousTouches = camera.numPreviousTouches + 1 end previousTouches[event.id] = event elseif camera.isFocus then if "moved" == phase then powersSwitch = 0 powerSelect.alpha = 0 undoPower.alpha =0 stickPower.alpha =0 if ( camera.distance ) then local dx,dy if previousTouches and ( numTotalTouches ) \>= 2 then dx,dy = calculateDelta( previousTouches, event ) end if ( dx and dy ) then local newDistance = math.sqrt( dx\*dx + dy\*dy ) local scale = newDistance / camera.distance if ( scale \> 0 ) then if (scale \> 1 and camera.xScale \< .8) then camera.xScale = camera.xScaleOriginal \* scale camera.yScale = camera.yScaleOriginal \* scale end if (scale \< 1 and camera.xScale \> .4) then camera.xScale = camera.xScaleOriginal \* scale camera.yScale = camera.yScaleOriginal \* scale end end --miko test ind her om xScale \< 1 og så juster ved at gange op. end else system.deactivate( "multitouch" ) camera.x = event.x - camera.myX camera.y = event.y - camera.myY --print( "go right" ) if (camera.x \> maxpos) then camera.x = maxpos elseif (camera.x \< maxminuspos) then camera.x = maxminuspos end if (camera.y \> maypos) then camera.y = maypos elseif (camera.y \< mayminuspos) then camera.y = mayminuspos end end if not previousTouches[event.id] then camera.numPreviousTouches = camera.numPreviousTouches + 1 end previousTouches[event.id] = event elseif "ended" == phase or "cancelled" == phase then system.activate( "multitouch" ) --[[if numTotalTouches == 1 then --miko move panning with one finger only local myXnew = event.x local myYnew = event.y --calculate panning left/right/up/down local mydx = math.abs(myXnew - camera.myX) local mydy = math.abs(myYnew - camera.myY) if (mydx \> 60) then --right/left panning mydx = myXnew - camera.myX if (mydx \> 60) then transition.to(camera, { time=200, x=(camera.x+60) } ) --camera.x = camera.x+60 elseif (mydx \< -60) then transition.to(camera, { time=200, x=(camera.x-60) } ) end elseif (mydy \> 60) then --up/down panning mydy = myYnew - camera.myY if (mydy \> 60) then transition.to(camera, { time=200, y=(camera.y+60) } ) elseif (mydy \< -60) then transition.to(camera, { time=200, y=(camera.y-60) } ) end end --move --now set variables to new x,y camera.myX = event.x camera.myY = event.y end]]-- if previousTouches[event.id] then camera.numPreviousTouches = camera.numPreviousTouches - 1 previousTouches[event.id] = nil end if ( #previousTouches \> 0 ) then -- must be at least 2 touches remaining to pinch/zoom camera.distance = nil else -- previousTouches is empty so no more fingers are touching the screen -- Allow touch events to be sent normally to the objects they "hit" display.getCurrentStage():setFocus( nil ) camera.isFocus = false camera.distance = nil camera.xScaleOriginal = nil camera.yScaleOriginal = nil -- reset array camera.previousTouches = nil camera.numPreviousTouches = nil end end end return result end Runtime:addEventListener( "tap", zooming ) Runtime:addEventListener( "touch", zooming ) \</lua\>

Thanks,
Scott

I’m using this library and it can clamp the camera to certain x/y bonds simply by calling a setBounds() function. Check it out.

http://code.coronalabs.com/code/perspective-virtual-camera-system

It doesn’t do zoom so you’ll probably have to combine with your code.