반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

지난번 튜토리얼이 길어서 11번에 나눠서 다 올렸습니다.

그거 올리느라고 다른 글들이 많이 밀렸네요.

공부할 것이 많아서 좋습니다. :)

오늘 다룰 글은 1월 29일에 Coronasdk 홈페이지에 올라온 튜토리얼입니다.

모양 맞추기 게임을 아주 쉽게 잘 가르쳐 주고 있네요.


Posted on . Written by



오늘의 guest tutorial 은 Greg Pugh 의 무료 강좌 입니다. 그는 MC Strategies 에서 플래시 및 앱 디벨로퍼로 일하고 있고 펜실베니아 Nanticoke 에 있는 independent studio인 GP Animations의 owner 이기도 합니다.  Greg이 개발한 앱들은 그의 블로그에서보실 수 있습니다. 또한 그는 RayWenderlich.comKwiksher.com에 Corona tutorial을 연재하고 있습니다. 또한 그는 최근 Corona Ambassador 로서 Corona SDK 의 세계로 새로 진입하는 개발자들을 위한 iBook 을 집필하고 있습니다.


Preface


애들이 있다 보니까 저의 iPad는 아이들이 주로 독서하거나 게임할 때 그리고 앱들을 가지고 노는데 사용합니다. 바로 지금 제 딸이 두 책에 끌리는가 봅니다. 제가 쓴 책 (http://www.ColinTurtle.com)과  약간 괴상한 "Game For Cats" 라는 책에요. 조만간 제 딸은 자기 외모와 색깔들과 알파벳 뭐 이런것들을 배울 나이가 되겠죠. 그리고 다른 앱들을 가지고 놀게 될 겁니다. 오늘 저는 아이들이 모양을 드래그 and 드롭해서 같은 모양의 틀에 맞추는 아주 기초적인 아이들용 앱을 만드는 방법으로 보여드리려고 합니다.

우선 실제 이 앱이 동작하는 것을 이 비디오를 통해서 먼저 보셨으면 합니다.

보시다시피 두개의 모양을 동시에 drag 할 수 있게 만들 겁니다. 왜냐하면 아이들은 smart device들을 가지고 놀 때 두손을 모두 사용하려고 하는 경향이 있거든요. 이 기능을 구현하기 위해 David McCuskey 가 만든 dmc_multitouch 를 사용할 겁니다. (관련 모듈이 들어 있는 파일들은 프로젝트에 포함돼 있습니다. 그러니 따로 다운 받으실 필요는 없구요. 그냥 이 프로젝트만 다운 받으시면 됩니다.) 이 글을 쓰는 지금 시점에는 코로나 시뮬레이터에서 멀티터치를 지원하지 않고 있습니다. 테스트를 하시려면 publish 를 해서 디바이스에 인스톨 하신 다음에 멀티터치를 테스트 하셔야 할 겁니다.



프로젝트 파일은 여기에서 다운 받으실 수 있습니다. 일단 SnapShapes 폴더의 압축을 풀면 그 안에 두개의 폴더가 있을 겁니다. SnapShapes_FINAL 에는 완성된 main.lua file 가 있습니다. 그리고 SnapShapes_START 폴더에는 단순한 artwork 와 supporting files 들만 있습니다.


Project Code


시작하시려면 우선 여러분이 사용하시는 텍스트 에디터를 여시고 create a new file 을 선택하신 다음에 그 파일 이름을 main.lua 로 하고 SnapShapes_START 폴더 안에 저장하세요. 첫번째로 할 작업은 dmc_multitouch.lua 파일을 import 하는 겁니다. 아래 코드를 카피해서 main.lua 에 붙여넣기 하세요.


-- Require dmc_multitouch
MultiTouch = require("dmc_multitouch");


다음으로는 status bar 를 감출겁니다. 아이들은 상태바에 나오는 시간이나 여러분 phone 에 어떤 서비스들이 있는지 등은 관심이 없거든요.


-- Hide status bar
display.setStatusBar(display.HiddenStatusBar);


이제 제공된 이미지들을 여러분의 images 폴더에 넣으세요. 그리고 아래 코드를 복사해서 main.lua  파일에 붙여 넣고 저장하세요.


-- Background image
local background = display.newImageRect("images/background.png", 640, 960);
background.x = display.contentCenterX;
background.y = display.contentCenterY;
-- Square outline
local sqLine = display.newImageRect("images/sqLine.png", 228, 228);
sqLine.x = 473;
sqLine.y = 181;
-- Square
local square = display.newImageRect("images/square.png", 188, 188);
square.x = 144;
square.y = 778;
-- Circle outline
local circLine = display.newImageRect("images/circLine.png", 245, 245);
circLine.x = 181;
circLine.y = 180;
-- circle positioning
local circle = display.newImageRect("images/circle.png", 200, 200);
circle.x = 473;
circle.y = 778;
-- myText positioning
local myText = display.newImageRect("images/myText.png", 508, 78);
myText.x = 311;
myText.y = 475;


Corona SDK Simulator 를 여신 후 File > Open 을 선택하세요. 그리고 SnapShapes_START  폴더에 있는 main.lua 를 여세요. phone 종류는 iPhone으로 선택하시기 바랍니다. 이제 여러분 시뮬레이터는 아래 이미지처럼 보일 겁니다.




이제 여러분은 화면에 display 해야할 모든 것을 다 display 했습니다. 이제 기능들을 추가할 차례입니다.
우선 파란 원에 적용될 코드를 만들겁니다. 그 다음에는 단지 변수 이름 등만 수정해서 빨란 사각형에 적용하면 됩니다. 이 때 이 원에 대해 멀티터치가 가능하도록 하고 initial positioning variables 들을 0으로 세팅하세요. 아래 코드를 복사해서 여러분이 만든 main.lua 파일에 붙여 넣으세요.


-- Circle
MultiTouch.activate(circle, "move", "single");
-- Set initial variables to 0
local circlePosX = 0;
local circlePosY = 0;


원을 드래그 하면 이 원은 touch event의 target 이 될 겁니다. moved 와 ended 같은 phases 들을 이용해서 기능을 구현할 수 있게 되는 거죠. 이 원이 위에 있는 동그란 점선 중앙에 50픽셀 이내로 접근했다면 그 원은 그 동그란 점선 안으로 snap 될 겁니다. 그 외의 경우에는 원은 그냥 드래그한 장소에 있게 됩니다.
아래 코드를 추가해 주세요.


-- User drag interaction on blue circle
local function circleDrag (event)
local t = event.target
-- If user touches & drags circle, follow the user's touch
if event.phase == "moved" then
   circlePosX = circle.x - circLine.x; 
   circlePosY = circle.y - circLine.y;
   if (circlePosX < 0) then circlePosX = circlePosX * -1; end
   if (circlePosY < 0) then circlePosY = circlePosY * -1; end
   -- If user drags circle within 50 pixels of center of outline, snap into middle
   if (circlePosX <= 50) and (circlePosY <= 50) then
      circle.x = circLine.x;
      circle.y = circLine.y;
   end


이 원이 동그란 점선 안으로 snap 됐고 유저가 드래그 하는 것을 멈췄다면 그 원은 동그란 점선 안에 제대로 안착돼 있을 갑니다. 


아래 코드를 추가하세요.


-- When the stops dragging circle within 50 pixels of center of outline, snap into middle, and...
elseif event.phase == "ended" then
   if (circlePosX <= 50) and (circlePosY <= 50) then
      circle.x = circLine.x;
      circle.y = circLine.y;
     -- ...lock circle into place where it cannot be moved.
     MultiTouch.deactivate(circle);
   end
end
return true;
end


마지막으로 circleDrag 함수에 이벤트 리스너를 추가하세요. 그리고 저장하시구요.


circle:addEventListener(MultiTouch.MULTITOUCH_EVENT, circleDrag);


시뮬레이터를 refresh 하면 화면에서 파란 원을 드래그 하실 수 있으실 겁니다. 그리고 동그란 점선 중앙에서 50 픽셀 이내로 접근하면 동그란 점선 중앙에 원이 곧바로 snap 될 겁니다. 더이상 드래그를 하지 않으면 그 원은 동그란 점선 안에 제대로 위치해 있을 겁니다.

이제 같은 코드를 빨간 사각형에 적용해 보죠.
그냥 변수 이름들만 바꾸시면 됩니다.


-- Same actions for the square as the circle
MultiTouch.activate(square, "move", "single");
local squarePosX = 0;
local squarePosY = 0;
local function squareDrag (event)
local t = event.target
if event.phase == "moved" then
   squarePosX = square.x - sqLine.x;
   squarePosY = square.y - sqLine.y;
   if (squarePosX < 0) then squarePosX = squarePosX * -1; end
   if (squarePosY < 0) then squarePosY = squarePosY * -1; end
   if (squarePosX <= 50) and (squarePosY <= 50) then
      square.x = sqLine.x;
      square.y = sqLine.y;
   end
elseif event.phase == "ended" then
   if (squarePosX <= 50) and (squarePosY <= 50) then
      square.x = sqLine.x;
      square.y = sqLine.y;
      -- If you'd like to be able to move the square again, comment out the line below
      MultiTouch.deactivate(square);
   end
end
return true;
end
square:addEventListener(MultiTouch.MULTITOUCH_EVENT, squareDrag);


사각형이 점선안에 제대로 자리 잡은 후에도 계속 드래그할 수 있도록 하시려면 코드의 deactivate 라인을 주석처리해 주세요.
이제 유저가 두 모양을 모두 제자리에 놓았다면 유저에게 잘 했다고 축하 해 주시면 되겠네요.

여기까지 입니다. 아이들이 가지고 놀 수 있는 앱을 아주 쉽고 빠르고 만들었습니다.




The Next Step?


위에 구현된 기본적은 기능을 확장해서 좀 더 큰 아이나 어른들을 위한 앱으로 발전 시킬 수도 있겠죠.



    이 코드를 활용해서 아이들이 인형에게 옷을 입히는 앱을 만들 수도 있겠죠?
    여러 조각의 퍼즐을 맞추는 게임을 만들수도 있을 겁니다. 위에 있는 함수들을 여러 조각들에 적용해서 구현하면 될 겁니다.
    adventure game 에 puzzle challenge 를 만들 수도 있을 겁니다.



모바일 혁명이 계속된다면 교육용 앱도 지금 보다 많이 대중성을 가질 겁니다. multitouch 모양 맞추기 기능의 기본을 이해하고 있으면 집에서만이 아니라 학교에서도 사용할 수 있는 아주 좋은 앱을 확장해서 개발할 수도 있겠죠?

반응형

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

2013. 2. 14. 23:41 | Posted by 솔웅


반응형
Posted on . Written by



And Finally…


지금까지의 코드는 single display object 에 대한 내용이었습니다. 실제로는 여러 object 에 이것이 적용 될 수도 있을 겁니다. object 들의 그룹에 pinch-zoome 이 일어날 수도 있겠죠. 더 중요한 것은 이 기능을 re-use 할 수 있도록 하려면 어떻게 해야 할까요?

:touch() 함수를 re-use 하려면 이 기능이 어떤 display object(이미지이든 그룹이든)에도 쉽게 적용 될 수 있도록 해야겠죠. 사용하고 있는 reference 들을 간단하게 change 할 수도 있어야 되겠구요. 이 기느응ㄹ 구현하기 위해 여러 object 들을 포함한 display group 을 하나 만듭시다. 그리고 touch listener 를 붙이고 그 그룹에 function 도 적용해 보죠.


sample11.lua
local group = display.newGroup() -- create display group to listen for new touches
-- populate display group with objects
local rect1 = display.newRect( group, 200, 200, 200, 100 )
rect1:setFillColor( 0, 0, 255 )
 
local rect2 = display.newRect( group, 300, 300, 200, 100 )
rect2:setFillColor( 0, 255 ,0 )
 
local rect3 = display.newRect( group, 100, 400, 200, 100 )
rect3:setFillColor( 255, 0, 0 )
 
group.dots = {} -- keep a list of the tracking dots
 
-- advanced multi-touch event listener
function touch(self, e)
local target = e.target -- get the object which received the touch event
local rect = self -- get reference to self object
if (e.phase == "began") then -- handle began phase of the touch event life cycle...
-- ...
 
end
 
group.touch = touch -- attach pinch zoom touch listener
group:addEventListener("touch") -- listen for touches starting on the touch object
 



In Summary


이제 모두 완료 됐습니다. 이제 touch listener module 은 어떤 display object 나 그룹에도 적용될 수 있습니다. 즉 쉽게 multitouch pinch-zoom-rotation 을 구현할 수 있게 된거죠.


아직 전체 project 를 다운받지 못하신 분들은 여기에서 다운받아서 실행해 보세요.


질문이나 의견이 있으시면 언제든지 댓글에 달아 주세요.

반응형

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

2013. 2. 14. 23:23 | Posted by 솔웅


반응형
Posted on . Written by



Pinch Centre Translation


이전 글에서 만들었던 sample9.lua 코드를 실행해 보세요. tracking dot 들이 rotate,scale, move 할 때 display object 가 약간씩 이동하는 걸 보실 수 있을 겁니다. 이렇게 하면 정확하게 그 midpoint 를 얻을 수가 없는 상황이거든요.


이 문제를 해결하려면 translation, scaling, rotation 을 적용하는데 단순히 basic 만 사용하면 안됩니다. 여기에 display object 의 center point location 도 같이 적용해야 합니다.

    Scaling 은 midpoint 와 “rect” centre 사이의 거리도 참고해서 적용되어야 합니다.
    Rotation 은 “rect” centre 에 적용 되야 합니다. tracking dot midpoint 주위를 회전해야 합니다.
    translation 은 이미 적용됐기 때문에 따로 고려를 하지 않아도 됩니다.


이제 어떤 standard library 수학 함수를 우리가 사용해야 할까요? point 를 회전시켜야 하는데 그 회전은 다른 포인트 주변을 돌아야 합니다. 그러니까 우리는 math helper 들을 사용할 필요가 있습니다. 또한 moved phase 에도 작업을 해 줘야 합니다.



sample10.lua


-- rotates a point around the (0,0) point by degrees
-- returns new point object
function rotatePoint( point, degrees )
local x, y = point.x, point.y
local theta = math.rad( degrees )
local pt = {
x = x * math.cos(theta) - y * math.sin(theta),
y = x * math.sin(theta) + y * math.cos(theta)
}
return pt
end
 
-- rotates point around the centre by degrees
-- rounds the returned coordinates using math.round() if round == true
-- returns new coordinates object
function rotateAboutPoint( point, centre, degrees, round )
 
local pt = { x=point.x - centre.x, y=point.y - centre.y }
pt = rotatePoint( pt, degrees )
pt.x, pt.y = pt.x + centre.x, pt.y + centre.y
if (round) then
pt.x = math.round(pt.x)
pt.y = math.round(pt.y)
end
return pt
end
 
 
-- changes to 'moved' phase
 
-- ...
-- apply rotation and scaling to rect
rect.rotation = rect.rotation + rotate
rect.xScale, rect.yScale = rect.xScale * scale, rect.yScale * scale
end
local pt = {} -- declare working point for the rect location
-- translation relative to centre point move
pt.x = rect.x + (centre.x - rect.prevCentre.x)
pt.y = rect.y + (centre.y - rect.prevCentre.y)
-- scale around the average centre of the pinch (centre of tracking dots, not rect centre)
pt.x = centre.x + ((pt.x - centre.x) * scale)
pt.y = centre.y + ((pt.y - centre.y) * scale)
-- rotate the rect centre around the pinch centre (same rotation as the rect is rotated!)
pt = rotateAboutPoint( pt, centre, rotate, false )
-- apply pinch translation, scaling and rotation to the rect centre
rect.x, rect.y = pt.x, pt.y
-- store the centre of all touch points
rect.prevCentre = centre
 
else -- "ended" and "cancelled" phases

main.lua

sample10.lua


moved phase 에 여러 기능들이 추가 됐습니다.


    pt 는 display 객체의 포지션 에 대한 working space 를 사용하기 위해 정의됩니다.
    midpoint translation은 working object 에 적용됩니다.
    midpoint 와 display object 중심사이의 거리가 scale 됩니다.
    display object 의 중심은 midpoint 주위를 회전합니다.


이제 코드를 실행해 보세요. 여러분 손가락이 어디에 있던 touch (tracking dot) 은 display object 에서 시작되고 touch point 에 따라 pinch-zoom 이 일어날 겁니다.


이 효과는 손가락 두개를 사용할 때 제대로 나타날 겁니다. 이전에는 tracking point들이 display object 에서의 그들의 시작지점의 영향을 받았었는데 이제는 약간 달라졌거든요. 결과는 거의 같긴 하지만 터치 포인트들간의 평균이 조금 더 정확해 졌습니다.



반응형

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

2013. 2. 14. 21:35 | Posted by 솔웅


반응형
Posted on . Written by


Rotation


이제 display object를 회전시키는 기능을 적용하겠습니다. 기본적인 로직은 midpoint 주위로 각각의 tracking dot 이 얼마나 ratate 되었느냐를 판단하는것부터 시작해야 할 겁니다. 그 평균을 구해서 object 의 이전 .rotation 값에 그 차이를 더해 주어야겠죠. 이것을 하려면 이것을 계산하는 함수들을 몇개 더 추가 해야 겠네요.

왜냐하면 angle 을 계산하려면 특정 수학 공식을 대입해야 하거든요. 그리고 원 둘레의 두 포인트 사이의 가장 작은 angle 을 구하는 작업도 필요합니다. 이것은 tracking dot 이 회전한 것에 대한 angle 을 사용할 때 아주 중요하게 사용됩니다. 잘못하면 작은 각도 말고 큰 각도를 사용할 수 있거든요. 90도와 260도가 있다면 우리가 필요한 것은 90도 입니다.


sample9.lua

-- returns the degrees between (0,0) and pt (note: 0 degrees is 'east')
function angleOfPoint( pt )
local x, y = pt.x, pt.y
local radian = math.atan2(y,x)
local angle = radian*180/math.pi
if angle < 0 then angle = 360 + angle end
return angle
end
 
-- returns the degrees between two points (note: 0 degrees is 'east')
function angleBetweenPoints( a, b )
local x, y = b.x - a.x, b.y - a.y
return angleOfPoint( { x=x, y=y } )
end
 
-- returns the smallest angle between the two angles
-- ie: the difference between the two angles via the shortest distance
function smallestAngleDiff( target, source )
local a = target - source
if (a > 180) then
a = a - 360
elseif (a < -180) then
a = a + 360
end
return a
end

calcAvgScaling 함수에서 했던 것처럼 모든 tracking dot들이 midpoint 주위를 회전한 것에 대한 평균 값을 구하기 위해 calcAvgRotation 함수를 사용하고 그 안에서 위의 함수들을 사용할 겁니다. 그리고 tracking dot 각도들 사이의 차이들도 update 해야 합니다. 그리고 직전 각도들도 마찬가지구요. 다행히 midpoint 로부터의 거리와 관련해서는 이미 구현해 놨었습니다. 약간의 코드만 추가하면 될 것 같습니다.

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

이제 이 약간의 코드를 추가함으로서 rect:touch() 함수는 이미 began 과 ended  phases 에 해당 값들을 업데이트 하게 되었습니다. 이제 우리가 해야 할 일은 moved phase 안의 “rect” display object에 rotation 을 적용하는 것 뿐입니다. 이 기능은 tracking dot 이 하나 이상일 때에 적용되는 기능입니다. 이제 tracking dot들의 midpoint 주위의 회전값 평균을 계산하고 이 object 에 적용하기 위해 위의 함수들을 call 하기만 하면 됩니다.

-- if there is more than one tracking dot, calculate the rotation and scaling
if (#rect.dots > 1) then
-- calculate the average rotation of the tracking dots
rotate = calcAverageRotation( rect.dots )
-- calculate the average scaling of the tracking dots
scale = calcAverageScaling( rect.dots )
-- apply rotation to rect
rect.rotation = rect.rotation + rotate
-- apply scaling to rect
rect.xScale, rect.yScale = rect.xScale * scale, rect.yScale * scale
end

main.lua

sample9.lua


반응형

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

2013. 2. 14. 08:14 | Posted by 솔웅


반응형
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) 를 하게 됐습니다.

반응형


반응형

두어달 가량 China Team 에 원격으로 진행된 Knowledge Transfer 가 끝났습니다. 

저도 한 네 다섯개의 Session 을 맡았던 것 같은데요.


두 나라의 시간 차이로 이곳 미국 동부 시간으로 밤 10시, 중국 시간으로는 아침 11시에 진행이 됐었습니다.


이 KT 가 끝나고 나서 China Team 에서 고맙다고 메일이 왔는데요.


이에 대해 우리 매니저가 보낸 답장을 가지고 오늘 영어 공부를 할 겁니다.


XXX


Thank you and the team very much for all your hard work these past few months! You have all done great work and are very quick at learning new technology as well as how our team works. We are very excited to continue the great work we have all started!

 

I hope you and the whole team in China have a great vacation and enjoy the New Year’s festivities!

 

Thank you!



당신과 당신 팀이 지난 몇달간 열심히 일해줘서 대단히 감사드립니다. 모두들 훌륭하게 일을 마쳤습니다. 그리고 아주 빠른 시간에 새로운 기술들과 우리팀 업무들을 잘 습득해 주셨습니다. 지금까지 그래왔듯이 훌륭하게 일을 진행할 여러분들과 같이 계속 근무하게 되서 무척 기대 됩니다.


중국에 있는 모든 팀들이 좋은 명절을 보내고 즐거운 설날 연휴를 보내시길 바랍니다.


감사합니다.



위 글은 프로젝트 매니저인 마이크가 보낸 메일이구요. 또 다른 프로젝트 매니저인 팻이 보낸 메일도 있어요.



Well said!

 

Thank you all for making the KT successful.  It really is a two way partnership and I appreciate all the hard work, early mornings, and late nights everyone has put in onshore and offshore.

 

R, L, K, and F – We wish you all a very happy, healthy, and enjoyable holiday.  I look forward to seeing you all soon.

 

Happy New Year,


얘기 잘 하셨어요!


KT 를 성공적으로 마칠 수 있게 되서 모두에게 감사드립니다. 말그대로 양쪽 방향으로 잘 진행된 파트너쉽이었습니다. 이른 아침 그리고 늦은 밤에 사무실 안에서 그리고 사무실 밖에서 열심히 일해 준 것에 감사의 마음을 표합니다.

R,L,K 그리고 F (사람 이름은 이니셜로 처리했습니다) -  모두들 행복하고 건강하고 즐거운 명절 보내길 바라며 조만간 만나기를 바랍니다.


새해 복 많이 받으세요.

아시다시피 그냥 영어로 들을 때는 존대말을 염두에 두지 않는데 이렇게 번역하면서 존대말로 하니까 말들이 너무 거리감 있게 느껴지네요.


어쨌든 팻이 보낸 메일 중에 onshore 와 offshore  해석할 때 조금 생각을 해야 됐는데요.

글자 그대로는 육상, 해상 이렇게 번역할 수 있겠지만 이 편지 내용에서는 무엇으로 해석할 까 고민이 됐으요.

또 다른 뜻인 국내, 국외로 해석하면 적당할 것 같기도 하구요.

KT Session 진행할 때 중국은 아침 11시니까 사무실에서 했는데 저희쪽에서는 밤 10시라서 집에서 진행했거든요.

그래서 저한테는 사무실 안과 밖이라는 느낌이 제일 먼저 와서 그냥 그걸로 번역해 버렸어요.

국내외가 맞을 수도 있겠네요.


어느 의미이든 이 메일을 이해하는데 크게 지장을 주지는 않는 것 같군요.

정확히 아시는 분 계시면 알려 주세요.


반응형

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

2013. 2. 12. 10:32 | Posted by 솔웅


반응형
Posted on . Written by



이전 글 까지만 해도 이 코드는 유용합니다. 하지만 좀 더 다듬어야 하죠. 작은 파란 사각형을 하나 이상의 손가락으로 움직일 수 있습니다. multitouch input device의 장점은 virtual 상황에서 real world 의 느낌을 주는데 있습니다. 이 코드에 rotation 과 scaling 효과를 주면 훨씬 더 실감나게 움직이곘죠.



Relative Motion


이 작업을 하기 전에 이전 코드(6번)를 실행 시킨 후 한 손가락을 이용했을 때 사각형이 어떻게 움직이는지 한번 보세요. touch point 로 사각형의 중심이 이동한 다음에 움직이죠. 이렇게 사각형의 중심이 이동하지 않고 그냥 touch point 와 그냥 relative 하게 움직이도록 할 겁니다. 이 작업을 하기 위해 moved와 ended phases 에 코드를 추가 할 겁니다.



sample7.lua

function rect:touch(e)
local target = e.target -- get the object which received the touch event
-- handle began phase of the touch event life cycle...
if (e.phase == "began") then
print( e.phase, e.x, e.y )
local dot = newTrackDot(e) -- create a tracking dot
rect.dots[ #rect.dots+1 ] = dot -- add the new dot to the list
-- pre-store the centre position of all touch points
rect.prevCentre = calcAvgCentre( rect.dots )
return true -- we handled the began phase
elseif (e.parent == rect) then
if (e.phase == "moved") then
print( e.phase, e.x, e.y )
-- calculate the centre position of all touch points
local centre = calcAvgCentre( rect.dots )
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
print( e.phase, e.x, e.y )
if (isDevice or e.numTaps == 2) then -- remove the tracking dot from the list
local index = table.indexOf( rect.dots, e.target ) -- get index of dot to be removed
table.remove( rect.dots, index ) -- remove dot from list
e.target:removeSelf() -- remove tracking dot from the screen
-- store the new centre of all touch points
rect.prevCentre = calcAvgCentre( rect.dots )
end
end
return true
end
return false -- if the target is not responsible for this touch event return false
end

main.lua

sample7.lua


여기서 수정한 부분은 아래와 같습니다.

    모든 touch 들의 center 를 계산하고 began phase 안에서 참고하기 위해 그 값을 저장한다.
    moved phase 에서 사각형의 x,y 값에 이전 touch 와 현재의 touch center 사이의 차이점을 추가적용한다.
    ended phase 에 터치들의 저장된 터치들의 중심값을 업데이트한다. 그래서 손가락을 떼더라도 다음 moved phase 에서 사각형이 필요없이 이동하지 않도록 한다.

이제 사용자는 사각형 위에 여러 손가락을 얹어도 이상하게 움직이지 않을 겁니다. 그 손가락들을 바꾸고 움직이고 해도 어색하지 않게 움직입니다. 이제 사각형이 손가락 움직임에 따라 회전하면 더 자연스럽겠네요.




반응형

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

2013. 2. 12. 09:50 | Posted by 솔웅


반응형
Posted on . Written by


multitouch display object 들을 위한 시뮬레이터 디버거를 사용하실 수 있습니다. tracking dot 중의 하나에서 touch 를 release 했을 때 이 dot 이 사라지지 않는걸 보셨을 겁니다. 이게 디버깅하기 아주 좋은 조건이거든요. 왜냐하면 touch 를 뗐어도 여러 touch point 가 있는 것처럼 데이터가 저장돼 있을 거거든요. 디버깅에는 좋지만 실제 앱을 이렇게 만드는 건 별로 유용하지는 않을 거에요. 계속 하얀 원이 쌓일 테니까요.


이 문제를 해결하시려면 rect:touch() function 의 ended phase 에서 해당 tracking dot들을 없애주면 됩니다. 일단 device 에서 running 하는지 여부를 코드의 시작 부분에서 변수에 저장해 두는 것에서부터 시작해야 되겠네요.


-- which environment are we running on?
local isDevice = (system.getInfo("environment") == "device")


The isDevice variable will be true if the code is running on a real, physical device and it can be used to automatically remove the tracking dot when the user lifts their finger.
isDevice 변수는 이 앱이 실제 디바이스에서 구동될 경우 true 가 될 겁니다. 그러면 이 값이 true 일 경우에만 손가락이 떼어질 때 해당 tracking dot 을 없애버리면 되겠죠.





sample6.lua


if (e.phase == "moved") then
print( e.phase, e.x, e.y )
 
else -- ‘ended’ and ‘cancelled’ phases
 
print( e.phase, e.x, e.y )
if ( isDevice or e.numTaps == 2 ) then -- remove the tracking dot from the list
local index = table.indexOf( rect.dots, e.target ) -- get index of dot to be removed
table.remove( rect.dots, index ) -- remove dot from list
e.target:removeSelf() -- remove tracking dot from the screen
end
end
return true
 

isDevice or e.numTaps == 2 가 있죠? 이렇게 함으로서 이미 rect:touch() function를 call 한 tap lisener 를 가지는 tracking dot을 가능하게 합니다. 그러면 시뮬레이터에서는 double tap 으로 tracking dot 을 remove 할 수 있도록 구현할 수 있습니다.

그 tap listener 는 이 코드가 시뮬레이터에서 돌아갈 때에만 동작하도록 해야합니다. 그래서 이 때 isDevice 변수를 다시 사용할 겁니다. 이 tap listener 는 tracking dot들을 생성하는 newTrackDot() 함수 안에 추가 됐습니다.


-- listen for a tap when running in the Simulator
function circle:tap(e)
if (e.numTaps == 2) then
e.parent = rect -- set the parent
rect:touch(e) -- call touch to remove the tracking dot
end
return true
end
-- only attach tap listener in the simulator
if (not isDevice) then
circle:addEventListener("tap")
end

main.lua

sample6.lua


Note that we also:
    우리는 두개의 tap 을 체크해서 double tap 일 경우에만 tracking dot을 remove 할 겁니다.
    그리고 touch 함수안에 했던 대로 .parent property를 세팅합니다.
    이 코드가 시뮬레이터에서 동작할 경우에만 해당 tap listener를 attach 합니다.



반응형


반응형

그동안 개발한 모바일 웹을 블랙베리용 WebWorks 어플리케이션으로 개발을 해야 합니다. 그래서 블랙베리 웹웍스에 대한 공부를 시작했습니다.



What's a WebWorks application?


BlackBerry WebWorks application은 블랙베리 스마트폰이나 태블릿에 설치할 수 있는 standalone web application 입니다.



What's the big deal?


첫번째로 BlackBerry WebWorks application이 standalone application 이라는 것은 원격에 있는 웹페이지나 어플리케이션을 로드하기 위해 그 주소를 일일이 타이핑할 필요가 없다는 겁니다. 이렇게 하려면 그 어플리케이션은 블랙베리 디바이스 내에 있어야 하겠죠. 그 어플리케이션은 따로 handle 할 필요가 없는 브라우저(WebKit engine container)로 볼 수 있는 앱이 되어야 합니다. 즉 컨테이너에 패키지로 들어있는 웹 asset들의 bundle 이라는 얘기죠. 


두번째로 어플리케이션을 빌드하기 위해  CSS와 HTML5 그리고 자바스크립트 같은 표준 웹 기술의 장점을 사용할 수 있다는 겁니다. 그리고 센차(Sencha), 폰갭(PhoneGap), jQuery 나 Dojo 같은 많이 사용되는 모바일 웹 프레임워크들을 사용할 수 있다는 겁니다. 표준 웹 기술을 사용함으로서 여러분이 가지고 있는 웹 개발 경험이나 웹 assets들을 활용할수 있기 때문에 어플리케이션을 빠르게 개발할 수 있는 장점을 갖게 됩니다.


세번째로는 가중 중요한 건데요. BlackBerry WebWorks platform을 사용함으로서 HTML5 어플리케이션에 native 기능을 사용하도록 만들 수 있다는 겁니다. 여러분은 자바스크립트 wrapper를 사용한 platform APIs 들을 사용하실 수 있습니다. 이를 이용해 블랙베리의 여러 기능들을 사용하실 수 있습니다. (BBM, PIM, media, hardware). 이렇게 함으로서 여러분 앱을 사용하는 유저들에게 integrated experience 를 전달할 수 있습니다. 이 모든 것들은 오픈 소스입니다. BlackBerry WebWorks 는 GitHub 에 있는 open source project 중 하나 입니다.



What tools do I need?


개발을 위한 에디터로는 여러분들이 사용하고 계시는 에디터를 그냥 사용하시면 됩니다.


BlackBerry WebWorks application을 테스트 하는 것은 여러분이 예상하시는 것 보다 훨씬 간단합니다. Ripple emulator 를 사용하세요. 그리고 여러분의 BlackBerry WebWorks application 이 작동하는 웹사이트 (로컬이든지 remote server 든지)를 point 해 주시면 됩니다. 그러면 완전히  BlackBerry WebWorks SDK 환경에서 emulating 하실 수 있습니다. 코드를 컴파일 하거나 시뮬레이터를 실행시키실 필요가 없습니다. Ripple emulator 를 사용하시면 일반 데스크탑 브라우저 개발하는 것과 비슷하게 개발하실 수 있습니다. 그러니까 소스를 고치고 싶으실 때도 그냥 에디터에서 곧바로 소스를 고치시면 됩니다. 그런 다음에 Ripple emulator 를 refresh 하시면 바뀐 소스의 결과를 보실 수 있습니다.


Ripple emulator 를 가지고 소스를 패키지화 하고 여러분 앱을 sign 하실 수도 있습니다. 여러분 앱을 패키지화하고 sign 을 하시려면 우선 BlackBerry WebWorks SDK를 인스톨 하셔야 합니다. 그리고 나서 Ripple emulator에 있는 packaging settings 를 configure 하시면 됩니다.


여러분의 어플리케이션을 블랙베리 스마트폰이나 태블릿에 deploy 하시려면 BlackBerry WebWorks SDK 을 사용하시면 됩니다.




아래 내용은 좀 더 high-level process 와 관련한 detail 들 입니다.


  1. Create your application web files (for example, HTML, CSS, and JavaScript).
  2. Test and debug your application with the Ripple emulator. For more information, see Getting started with the Ripple emulator.
  3. Create a BlackBerry WebWorks configuration document (config.xml) that contains details about your application. For more information, see Creating a configuration document.
  4. Package your application using the Ripple emulator (make sure that you install the BlackBerry WebWorks SDK first). For more information, see Packaging your app in Ripple.
  5. Deploy your application to a BlackBerry device or simulator. For BlackBerry 10 OS or BlackBerry PlayBook OS applications, you deploy a .bar file. For BlackBerry 7 (or earlier versions of the BlackBerry Device Software), you deploy a .cod file. For more information on deploying apps, see the testing section.



How do I distribute my application?


BlackBerry WebWorks application은 native BlackBerry smartphone 이나  tablet applications 과 마찬가지로 패키지화 하시면 됩니다. 블랙베리 7 용 이나 그 이전 버전 으로 개발된 스마트폰 앱들은 BlackBerry Desktop Manager 나 the BlackBerry App World storefront 같은 웹사이트를 통해서 distribute 될 수 있습니다. BlackBerry PlayBook OS 용 어플리케이션들은BlackBerry App World를 통해서면 distribute 될 수 있습니다.


앱을 distribute 하는것과 관련한 좀 더 자세한 정보를 원하시면 Distributing your application를 보세요.



What's next?

To get started, visit the following resources for developing web applications for the BlackBerry Application Platform:






반응형


반응형

2월 9일 금요일 오후부터 눈이 엄청 왔어요.

앞이 안 보일 정도로 눈보라가 몰아치더라구요.


밤새 그랬나봐요. 아침에 일어났더니 모든게 다 눈에 잠겼더라구요.

거기다 전기까지 나가고..


뉴스를 보니까 여긴 50~60센티미처 정도 온거 같더라구요.


가장 많이 온 곳은 코네티컷으로 90센티미터까지 내렸다고 하던데...


밤새 분 바람은 거의 허리케인 수준의 강도라고 하구요.


다행히 토요일 저녁에 전기가 들어와서 설날 아침에 한국에 안부 전화는 드릴 수 있었어요.




집 앞에 주차해 놓은 차들인데.. 완전히 눈에 덮였죠?



완전 차를 알아 볼 수 없을 정도예요.


집에서 바라본 아파트 전경인데...

눈이 그치자 모두들 자동차 눈 치우러 나오더라구요.

전 마나님이 눈 덮이 차가 귀엽다고 치우지 말라그래서... 그냥 놔 뒀어요.. ^^






반응형