Hey Everyone.
I have added in rotation support into Corona’s default pinch-zoom sample code (and got it working!).
Since I can’t test multitouch in the corona simulator, I’m exporting to the iOS simulator. Everything seems to work as it should in the basic iPhone simulator, but breaks on the Retina iPhone simulator. In the retina simulator and when exporting to an actual phone, I am getting a strange flip issue that seems to be related to inconsistent touch values in my calculateRotation function.
I used the same “touch” and “event” values that the sample code uses to calculate distance etc. When I print out the x,y values to see whats happening, I find that in one frame, touch 1 (touch.x, touch.y) might be something like: 100, 300 while touch 2 (event.x, event.y) could be 200, 250. The next frame they switch! So now touch 1 (touch.x,touch.y) is 200,250 and touch 2 (event.x,event.y) is 100,300. This seems like the obvious culprit, but if it is then I am confused as to why this works at all in the iOS (non retina) simulator. Any ideas what might be going on here?
I’ve also created a project file for anyone to download and test with here:
http://dl.dropbox.com/u/46392597/pinch_zoom_roate_example.zip
If we can get this working correctly I was going to throw it up on code share for everyone to use, I’ve just got this weird bug.
Here’s the code as well if you just want to look at it.
[lua]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
local function calculateCenter( previousTouches, event )
local id,touch = next( previousTouches )
if event.id == id then
id,touch = next( previousTouches, id )
assert( id ~= event.id )
end
local cx = math.floor( ( touch.x + event.x ) * 0.5 )
local cy = math.floor( ( touch.y + event.y ) * 0.5 )
return cx, cy
end
local function calculateRotation( previousTouches, event )
local id,touch = next( previousTouches )
if event.id == id then
id,touch = next( previousTouches, id )
assert( id ~= event.id )
end
local radianValue = (math.atan2((touch.x - event.x),(touch.y - event.y)))
local degreeValue = math.deg(radianValue)
return degreeValue
end
local function initialTouchRotation( previousTouches, event )
local id,touch = next( previousTouches )
if event.id == id then
id,touch = next( previousTouches, id )
assert( id ~= event.id )
end
local radianValue2 = (math.atan2((touch.x - event.x),(touch.y - event.y)))
local degreeValue2 = math.deg(radianValue2)
return degreeValue2
end
function background:touch( event )
if (alignImageMode == true) then
local phase = event.phase
local eventTime = event.time
local previousTouches = self.previousTouches
if not self.xScaleStart then
self.xScaleStart, self.yScaleStart = self.xScale, self.yScale
end
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
– Store initial position
self.x0 = event.x - self.x
self.y0 = event.y - self.y
previousTouches = {}
self.previousTouches = previousTouches
self.numPreviousTouches = 0
self.firstTouch = event
elseif not self.distance then
local dx,dy
local cx,cy
if previousTouches and numTotalTouches >= 2 then
dx,dy = calculateDelta( previousTouches, event )
cx,cy = calculateCenter( previousTouches, event )
initialTouchRotationValue = initialTouchRotation( previousTouches, event )
initialImageRotationValue = self.rotation
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
self.x0 = cx - self.x
self.y0 = cy - self.y
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
print (“moving”)
if self.distance then
local dx,dy
local cx,cy
if previousTouches and numTotalTouches == 2 then
dx,dy = calculateDelta( previousTouches, event )
cx,cy = calculateCenter( previousTouches, event )
rotationValue = calculateRotation( previousTouches, event )
end
if dx and dy then
local newDistance = math.sqrt( dx*dx + dy*dy )
local scale = newDistance / self.distance
if scale > 0 then
self.xScale = self.xScaleOriginal * scale
self.yScale = self.yScaleOriginal * scale
– Make object move while scaling
self.x = cx - ( self.x0 * scale )
self.y = cy - ( self.y0 * scale )
–Make object rotate while moving and scaling
self.rotation = initialImageRotationValue -(rotationValue - initialTouchRotationValue)
end
end
else
if event.id == self.firstTouch.id then
– don’t move unless this is the first touch id.
– Make object move (we subtract self.x0, self.y0 so that moves are
– relative to initial grab point, rather than object “snapping”).
self.x = event.x - self.x0
self.y = event.y - self.y0
end
end
if event.id == self.firstTouch.id then
self.firstTouch = event
end
if not previousTouches[event.id] then
self.numPreviousTouches = self.numPreviousTouches + 1
end
previousTouches[event.id] = event
elseif “ended” == phase or “cancelled” == phase then
– check for taps
local dx = math.abs( event.xStart - event.x )
local dy = math.abs( event.yStart - event.y )
if eventTime - previousTouches[event.id].time < 150 and dx < 10 and dy < 10 then
if not self.tapTime then
– single tap
self.tapTime = eventTime
self.tapDelay = timer.performWithDelay( 300, function() self.tapTime = nil end )
elseif eventTime - self.tapTime < 300 then
– double tap
timer.cancel( self.tapDelay )
self.tapTime = nil
if self.xScale == self.xScaleStart and self.yScale == self.yScaleStart then
transition.to( self, { time=300, transition=easing.inOutQuad, xScale=self.xScale*2, yScale=self.yScale*2, x=event.x - self.x0*2, y=event.y - self.y0*2 } )
else
local factor = self.xScaleStart / self.xScale
transition.to( self, { time=300, transition=easing.inOutQuad, xScale=self.xScaleStart, yScale=self.yScaleStart, x=event.x - self.x0*factor, y=event.y - self.y0*factor } )
end
end
end
–
if previousTouches[event.id] then
self.numPreviousTouches = self.numPreviousTouches - 1
previousTouches[event.id] = nil
print (“here”)
end
if self.numPreviousTouches == 1 then
– must be at least 2 touches remaining to pinch/zoom
print (“here2”)
self.distance = nil
– reset initial position
local id,touch = next( previousTouches )
self.x0 = touch.x - self.x
self.y0 = touch.y - self.y
self.firstTouch = touch
elseif self.numPreviousTouches == 0 then
– 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 true
end
end[/lua] [import]uid: 3116 topic_id: 16749 reply_id: 316749[/import]