marți, 5 iulie 2011

A corona lua multi-touch pinch-zoom example





I found that the pinch zoom example in here was a little harder to understand, so I decided to make my own class to handle pinch-zoom events:

It's simple to use, just do something like:
--hide the statusbar
display.setStatusBar( display.HiddenStatusBar )

--include the mtouch library
local mtouch = require( "mtouch" )

--create the zoom object - an image
local image     = nil

local function OnZoomIn( event )
 --grow our image
 image.xScale = image.xScale * 1.01
 image.yScale = image.yScale * 1.01
 print("new width="..image.contentWidth)
end

local function OnZoomOut( event )
 --shrink our image
 image.xScale = image.xScale / 1.01
 image.yScale = image.yScale / 1.01
 print("new width="..image.contentWidth)
end

local function main()
 --add the image
 image = display.newImage("image.jpg" )
 --set the imaage to the center of the device
 image.x = display.contentWidth  * 0.5
 image.y = display.contentHeight * 0.5
 --create the pinch zoom over our image
 mtouch.setZoomObject( image )
 mtouch.setOnZoomIn  ( OnZoomIn  ) 
 mtouch.setOnZoomOut ( OnZoomOut  )
 --add the fictive touch for the simulator - comment this if you are deploying to device!
 mtouch.setFictiveSimulatorTouch( 100, 100 )
end

main()

Screenshot:


And the mtouch class:
module(..., package.seeall)
-- activate multitouch
system.activate( "multitouch" )

-- math helpers
local sqrt         = math.sqrt
local abs     = math.abs
-- current touches
local touches      = {}
-- last zoom distance - I use this to compare with current distance
-- if its smaller then zoom out, else  zoom in
local lastDistance = 0
local zoomObject   = nil      --the zoom object
local OnZoomIn     = nil      --the zoom in event
local OnZoomOut    = nil      --the zoom out event
--fictive touch
local fictiveTouch = {}
fictiveTouch.id = "QHHJGL10"

-----------------------------------------------
-- counts a dictionary
-----------------------------------------------
local function CountDictionary(dict)
 local ret = 0
 for k, v in pairs(dict) do
  ret = ret + 1
 end
 return ret
end

-----------------------------------------------
-- returns an element at some index in a dictionary
-----------------------------------------------
local function GetDictElAtIndex( dict, index )
 local temp = 0
 local ret  = nil
 for k, v in pairs(dict) do
  if( temp == index ) then
   ret   = v
   break
  end
  temp   = temp + 1
 end
 return ret
end

-----------------------------------------------
-- update x and y for a specific touch-event
-----------------------------------------------
local function UpdateTouch( event )
 local id  = event.id
 local obj = event.target
 local  x  = event.x
 local  y  = event.y
 if touches[id] then
  touches[id].x = x
  touches[id].y = y
 end
end

-----------------------------------------------
-- calculate the distance between two touches 
-----------------------------------------------
local function DistanceBetween2T( t1, t2 )
 local ret = 0
 local deltax = t2.x - t1.x
 local deltay = t2.y - t1.y
 ret          = sqrt( deltax * deltax + deltay * deltay )
 return ret
end
-----------------------------------------------
-- touch listener
-----------------------------------------------
function on_touch( event )
 local ret = false
 if     event.phase == "began" then
  --register this touch
  touches[ event.id ] = event
 elseif event.phase == "moved" then
  UpdateTouch(event)
  --verify if i have at least 2 touches
  if( CountDictionary(touches) >= 2 ) then
   zoomObject.touching = true
   --gets the first 2 touches and calculate the distance between them
   local touch1 = GetDictElAtIndex( touches, 0 )
   local touch2 = GetDictElAtIndex( touches, 1 )
   local dist   = DistanceBetween2T( touch1, touch2 )
   --
   local args        = {}
   args.distance     = dist
   args.lastdistance = lastDistance
   args.difference   = abs( lastDistance - dist )
   args.touch1       = touch1
   args.touch2       = touch2
   if lastDistance ~= -1 then
    if dist < lastDistance then 
     --zoom out
     if OnZoomOut ~= nil then OnZoomOut( args ) end
    else
     --zoom in
     if OnZoomIn  ~= nil then  OnZoomIn( args ) end
    end
    ret = true
   end
   --save the lastdistance
   lastDistance = dist
  end
 elseif event.phase == "ended" then
  --remove this touch from list
  touches[ event.id ]  = nil
  lastDistance    = -1
  zoomObject.touching = false
 end
 return ret
end

-----------------------------------------------
-- properties
-----------------------------------------------
function setZoomObject( obj )
 zoomObject          = obj
 zoomObject.touching = false
 -- register table listener
 zoomObject:addEventListener( "touch", on_touch )
end


-----------------------------------------------
-- returns current zoom object
-----------------------------------------------
function getZoomObject() 
 return zoomObject
end

-----------------------------------------------
-- returns the number of current touches
-----------------------------------------------
function getNrTouches() 
 return CountDictionary(touches)
end

-----------------------------------------------
-- sets the zoomin event function
-----------------------------------------------
function setOnZoomIn( event )
 OnZoomIn = event
end

-----------------------------------------------
-- sets the zoomout event function
-----------------------------------------------
function setOnZoomOut( event )
 OnZoomOut = event
end

-----------------------------------------------
-- for the simulator: create a fictive touch
-----------------------------------------------
function setFictiveSimulatorTouch( x, y)
 fictiveTouch.x = x; fictiveTouch.y = y
 touches[ fictiveTouch.id ] = fictiveTouch
 fictiveTouch.rect = display.newRect( fictiveTouch.x, fictiveTouch.y, 20, 20 )
end

-----------------------------------------------
-- for the simulator: removes a fictive touch
-----------------------------------------------
function removeFictiveSimulatorTouch()
 touches[ fictiveTouch.id ] = nil
 fictiveTouch.rect:removeSelf()
end

-----------------------------------------------
-- clean me
-----------------------------------------------
function clean()
 zoomObject:removeEventListener( "touch", on_touch )
end