Corona SDK/Corona Doc

Pinch Zoom Rotate 구현하기 - 8/11 -

솔웅 2013. 2. 14. 08:14
반응형
Posted on . Written by


Scaling

display object를 멀티 터치로 컨트롤 하면서 우리가 원하는 transformation을 적용하려면 모든 tracking dot들의 평균 값들이 필요합니다. 그리고 그 값을 display object의 midpoint (그 평균 위치) 에 이미지를 위치시켜야 합니다.


scaling 과 관련해서는 수학적인 계산이 필요합니다.

    midpoint 와 tracking dot들 간의 거리의 합 구하기
    거리의 합계를 dot 들의 갯수로 나눈 평균 거리 구하기
    tracking dot 들의 이전 위치에 대한 같은 평균 거리 구하기
    이전과 현재의 평균 거리 사이의 차이 구하기
    display object 의 .xScale 과 .yScale에  multiplication 으로 그 차이를 적용하기


이건 여러 tracking dot들이 움직일 때 display object 의 평균 transition 을 어떻게 적용할 지를 정해 주는 겁니다. 이 scaling 값을 얻도록 하는 기본 라이브러리 함수들을 만들 겁니다. 아래 함수는 스크린의 두개의 지점사이의 거리를 계산하는 함수입니다. 아주 전형적인 삼각함수죠.

sample8.lua

-- returns the distance between points a and b
function lengthOf( a, b )
local width, height = b.x-a.x, b.y-a.y
return (width*width + height*height)^0.5
end


tracking dot들의 midpoint 를 얻기 위해 sample 5 에서 다뤘던  calcAvgCentre() 함수를 사용할 겁니다.  midpoint 와 tracking dot 들 사이의 평균 거리를 구해서 저장하기 위해 다음과 같은 함수들을 사용할 겁니다. 첫번째는 각 dot 들의 현재 distance 를 get 해서 그 값을 tracking dot 에 저장할 겁니다. 그리고 이전 distance 도 물론 저장하구요. 두번째 함수에서는 이전과 현재 거리 set 들 사이의 차이를 계산하는 함수를 사용할 겁니다.


-- calculate each tracking dot's distance from the midpoint
local function updateTracking( centre, points )
for i=1, #points do
local point = points[i]
point.prevDistance = point.distance
point.distance = lengthOf( centre, point )
end
end
 
-- calculates scaling amount based on the average change in tracking point distances
local function calcAverageScaling( points )
local total = 0
for i=1, #points do
local point = points[i]
total = total + point.distance / point.prevDistance
end
return total / #points
end

이 함수를 사용하는 방법은 간단합니다. rect:touch()의 began 과 ended phase 에서 call 하시면 됩니다. 그러면 이 함수들이 적당한 값으로 해당 tracking dot 들의 값을 update 할 겁니다. 아래는 began 과 ended phase 에서 call 하는 부분입니다.


-- "began"
-- pre-store the tracking dot scale and rotation values
updateTracking( rect.prevCentre, rect.dots )
return true -- we handled the began phase
 
-- "ended"
-- store the new centre of all touch points
rect.prevCentre = calcAvgCentre( rect.dots )
-- refresh tracking dot scale and rotation values
updateTracking( rect.prevCentre, rect.dots )

moved phase 는 조금 더 복잡합니다. 왜냐하면 실제 이 부분에서 대부분의 일이 진행 될 거거든요. 다행히 여기서 우리가 해야 될 일은 tracking dot 을 update 하는 똑 같은 일에다가 tracking dot 이 한개 이상일 경우 scaling 을 적용하는 일 뿐입니다.


if (e.phase == "moved") then
print( e.phase, e.x, e.y )
local centre, scale, rotate = {}, 1, 0 -- declare working variables
centre = calcAvgCentre( rect.dots ) -- calculate the average centre position of all touch points
updateTracking( rect.prevCentre, rect.dots ) -- refresh tracking dot scale and rotation values
-- if there is more than one tracking dot, calculate the rotation and scaling
if (#rect.dots > 1) then
scale = calcAverageScaling( rect.dots ) -- calculate the average scaling of the tracking dots
rect.xScale, rect.yScale = rect.xScale * scale, rect.yScale * scale -- apply scaling to rect
end
rect.x = rect.x + (centre.x - rect.prevCentre.x) -- update the X position of rect
rect.y = rect.y + (centre.y - rect.prevCentre.y) -- update the Y position of rect
rect.prevCentre = centre -- store the centre of all touch points
else -- "ended" and "cancelled" phases

main.lua

sample8.lua


위에서 moved phase 에서 우리가 바꾼 부분은 아래와 같습니다.

    앞으로 일어날 transformation 값들과 같이 사용될 변수들 정의
    tracking dot 들의 저장된 distance 값을 refresh 하기 위해 updateTracking 을 call 하기
    tracking scaling 에서 변한 값의 평균을 구하기 위해 distance 값들 사용하기
    display object "rect" 에 해당 scaling 적용하기

The display object now translates (moves) and scales (zooms) along with our tracking dots (touch points).
이제 이 display object 는 tracking dot 들 (touch point 들) 의 움직임에 따라 translates (moves) 과  scales (zooms) 를 하게 됐습니다.

반응형